diff --git a/DEPS b/DEPS
index 86b95ea..11c0a22c 100644
--- a/DEPS
+++ b/DEPS
@@ -44,7 +44,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '580ee66c07dfb79d9b1f83cc3e5907eb4b563dd8',
+  'v8_revision': 'a011eb0a6c8d22602afe15a104dd76363371b8cb',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
diff --git a/base/numerics/safe_conversions.h b/base/numerics/safe_conversions.h
index 66b278f..4d62167 100644
--- a/base/numerics/safe_conversions.h
+++ b/base/numerics/safe_conversions.h
@@ -110,35 +110,35 @@
 // that the specified numeric conversion will saturate by default rather than
 // overflow or underflow, and NaN assignment to an integral will return 0.
 // All boundary condition behaviors can be overriden with a custom handler.
+template <template <typename>
+          class SaturationHandler = SaturatedCastDefaultHandler,
+          typename Dst,
+          typename Src>
+constexpr Dst saturated_cast_impl(const Src value,
+                                  const RangeCheck constraint) {
+  return constraint.IsValid()
+             ? static_cast<Dst>(value)
+             : (constraint.IsOverflow()
+                    ? SaturationHandler<Dst>::HandleOverflow()
+                    // Skip this check for integral Src, which cannot be NaN.
+                    : (std::is_integral<Src>::value || constraint.IsUnderflow()
+                           ? SaturationHandler<Dst>::HandleUnderflow()
+                           : SaturationHandler<Dst>::HandleNaN()));
+}
+
+// saturated_cast<> is analogous to static_cast<> for numeric types, except
+// that the specified numeric conversion will saturate by default rather than
+// overflow or underflow, and NaN assignment to an integral will return 0.
+// All boundary condition behaviors can be overriden with a custom handler.
 template <typename Dst,
           template <typename>
           class SaturationHandler = SaturatedCastDefaultHandler,
           typename Src>
 constexpr Dst saturated_cast(Src value) {
-  static_assert(
-      SaturationHandler<Dst>::lowest() < SaturationHandler<Dst>::max(), "");
-  // While this looks like a lot of code, it's all constexpr and all but
-  // one variable are compile-time constants (enforced by a static_assert).
-  // So, it should evaluate to the minimum number of comparisons required
-  // for the range check, which is 0-3, depending on the exact source and
-  // destination types, and whatever custom range is specified.
   using SrcType = typename UnderlyingType<Src>::type;
-  return IsGreaterOrEqual<SrcType, Dst>::Test(
-             value, NarrowingRange<Dst, SrcType, SaturationHandler>::lowest())
-             ? (IsLessOrEqual<SrcType, Dst>::Test(
-                    value,
-                    NarrowingRange<Dst, SrcType, SaturationHandler>::max())
-                    ? static_cast<Dst>(value)
-                    : SaturationHandler<Dst>::HandleOverflow())
-             // This last branch is a little confusing. It's specifically to
-             // catch NaN when converting from float to integral.
-             : (std::is_integral<SrcType>::value ||
-                        std::is_floating_point<Dst>::value ||
-                        IsLessOrEqual<SrcType, Dst>::Test(
-                            value, NarrowingRange<Dst, SrcType,
-                                                  SaturationHandler>::max())
-                    ? SaturationHandler<Dst>::HandleUnderflow()
-                    : SaturationHandler<Dst>::HandleNaN());
+  return saturated_cast_impl<SaturationHandler, Dst>(
+      static_cast<SrcType>(value),
+      DstRangeRelationToSrcRange<Dst, SaturationHandler, SrcType>(value));
 }
 
 // strict_cast<> is analogous to static_cast<> for numeric types, except that
diff --git a/base/numerics/safe_conversions_impl.h b/base/numerics/safe_conversions_impl.h
index 5ef3321..270d5916 100644
--- a/base/numerics/safe_conversions_impl.h
+++ b/base/numerics/safe_conversions_impl.h
@@ -167,28 +167,37 @@
 };
 
 enum RangeConstraint {
-  RANGE_VALID = 0x0,  // Value can be represented by the destination type.
-  RANGE_UNDERFLOW = 0x1,  // Value would overflow.
-  RANGE_OVERFLOW = 0x2,  // Value would underflow.
+  RANGE_VALID = 0x0,      // Value can be represented by the destination type.
+  RANGE_UNDERFLOW = 0x1,  // Value would underflow.
+  RANGE_OVERFLOW = 0x2,   // Value would overflow.
   RANGE_INVALID = RANGE_UNDERFLOW | RANGE_OVERFLOW  // Invalid (i.e. NaN).
 };
 
-// Helper function for coercing an int back to a RangeContraint.
-constexpr RangeConstraint GetRangeConstraint(int integer_range_constraint) {
-  // TODO(jschuh): Once we get full C++14 support we want this
-  // assert(integer_range_constraint >= RANGE_VALID &&
-  //        integer_range_constraint <= RANGE_INVALID)
-  return static_cast<RangeConstraint>(integer_range_constraint);
-}
+// This class wraps the range constraints as separate booleans so the compiler
+// can identify constants and eliminate unused code paths.
+class RangeCheck {
+ public:
+  constexpr RangeCheck(bool is_in_upper_bound, bool is_in_lower_bound)
+      : is_overflow_(!is_in_upper_bound), is_underflow_(!is_in_lower_bound) {}
+  constexpr RangeCheck() : is_overflow_(0), is_underflow_(0) {}
+  constexpr bool IsValid() const { return !is_overflow_ && !is_underflow_; }
+  constexpr bool IsInvalid() const { return is_overflow_ && is_underflow_; }
+  constexpr bool IsOverflow() const { return is_overflow_ && !is_underflow_; }
+  constexpr bool IsUnderflow() const { return !is_overflow_ && is_underflow_; }
 
-// This function creates a RangeConstraint from an upper and lower bound
-// check by taking advantage of the fact that only NaN can be out of range in
-// both directions at once.
-constexpr inline RangeConstraint GetRangeConstraint(bool is_in_upper_bound,
-                                                    bool is_in_lower_bound) {
-  return GetRangeConstraint((is_in_upper_bound ? 0 : RANGE_OVERFLOW) |
-                            (is_in_lower_bound ? 0 : RANGE_UNDERFLOW));
-}
+  // These are some wrappers to make the tests a bit cleaner.
+  constexpr operator RangeConstraint() const {
+    return static_cast<RangeConstraint>(static_cast<int>(is_overflow_) << 1 |
+                                        static_cast<int>(is_underflow_));
+  }
+  constexpr bool operator==(const RangeConstraint rhs) const {
+    return rhs == static_cast<RangeConstraint>(*this);
+  }
+
+ private:
+  const bool is_overflow_;
+  const bool is_underflow_;
+};
 
 // The following helper template addresses a corner case in range checks for
 // conversion from a floating-point type to an integral type of smaller range
@@ -211,11 +220,9 @@
 // To fix this bug we manually truncate the maximum value when the destination
 // type is an integral of larger precision than the source floating-point type,
 // such that the resulting maximum is represented exactly as a floating point.
-template <typename Dst,
-          typename Src,
-          template <typename> class Bounds = std::numeric_limits>
+template <typename Dst, typename Src, template <typename> class Bounds>
 struct NarrowingRange {
-  using SrcLimits = typename std::numeric_limits<Src>;
+  using SrcLimits = std::numeric_limits<Src>;
   using DstLimits = typename std::numeric_limits<Dst>;
 
   // Computes the mask required to make an accurate comparison between types.
@@ -253,6 +260,7 @@
 
 template <typename Dst,
           typename Src,
+          template <typename> class Bounds,
           IntegerRepresentation DstSign = std::is_signed<Dst>::value
                                               ? INTEGER_REPRESENTATION_SIGNED
                                               : INTEGER_REPRESENTATION_UNSIGNED,
@@ -267,83 +275,111 @@
 // split it into checks based on signedness to avoid confusing casts and
 // compiler warnings on signed an unsigned comparisons.
 
-// Dst range is statically determined to contain Src: Nothing to check.
+// Same sign narrowing: The range is contained for normal limits.
 template <typename Dst,
           typename Src,
+          template <typename> class Bounds,
           IntegerRepresentation DstSign,
           IntegerRepresentation SrcSign>
 struct DstRangeRelationToSrcRangeImpl<Dst,
                                       Src,
+                                      Bounds,
                                       DstSign,
                                       SrcSign,
                                       NUMERIC_RANGE_CONTAINED> {
-  static constexpr RangeConstraint Check(Src value) { return RANGE_VALID; }
+  static constexpr RangeCheck Check(Src value) {
+    using SrcLimits = std::numeric_limits<Src>;
+    using DstLimits = NarrowingRange<Dst, Src, Bounds>;
+    return RangeCheck(
+        static_cast<Dst>(SrcLimits::max()) <= DstLimits::max() ||
+            static_cast<Dst>(value) <= DstLimits::max(),
+        static_cast<Dst>(SrcLimits::lowest()) >= DstLimits::lowest() ||
+            static_cast<Dst>(value) >= DstLimits::lowest());
+  }
 };
 
 // Signed to signed narrowing: Both the upper and lower boundaries may be
-// exceeded.
-template <typename Dst, typename Src>
+// exceeded for standard limits.
+template <typename Dst, typename Src, template <typename> class Bounds>
 struct DstRangeRelationToSrcRangeImpl<Dst,
                                       Src,
+                                      Bounds,
                                       INTEGER_REPRESENTATION_SIGNED,
                                       INTEGER_REPRESENTATION_SIGNED,
                                       NUMERIC_RANGE_NOT_CONTAINED> {
-  static constexpr RangeConstraint Check(Src value) {
-    return GetRangeConstraint((value <= NarrowingRange<Dst, Src>::max()),
-                              (value >= NarrowingRange<Dst, Src>::lowest()));
+  static constexpr RangeCheck Check(Src value) {
+    using DstLimits = NarrowingRange<Dst, Src, Bounds>;
+    return RangeCheck(value <= DstLimits::max(), value >= DstLimits::lowest());
   }
 };
 
-// Unsigned to unsigned narrowing: Only the upper boundary can be exceeded.
-template <typename Dst, typename Src>
+// Unsigned to unsigned narrowing: Only the upper bound can be exceeded for
+// standard limits.
+template <typename Dst, typename Src, template <typename> class Bounds>
 struct DstRangeRelationToSrcRangeImpl<Dst,
                                       Src,
+                                      Bounds,
                                       INTEGER_REPRESENTATION_UNSIGNED,
                                       INTEGER_REPRESENTATION_UNSIGNED,
                                       NUMERIC_RANGE_NOT_CONTAINED> {
-  static constexpr RangeConstraint Check(Src value) {
-    return GetRangeConstraint(value <= NarrowingRange<Dst, Src>::max(), true);
+  static constexpr RangeCheck Check(Src value) {
+    using DstLimits = NarrowingRange<Dst, Src, Bounds>;
+    return RangeCheck(
+        value <= DstLimits::max(),
+        DstLimits::lowest() == Dst(0) || value >= DstLimits::lowest());
   }
 };
 
-// Unsigned to signed: The upper boundary may be exceeded.
-template <typename Dst, typename Src>
+// Unsigned to signed: Only the upper bound can be exceeded for standard limits.
+template <typename Dst, typename Src, template <typename> class Bounds>
 struct DstRangeRelationToSrcRangeImpl<Dst,
                                       Src,
+                                      Bounds,
                                       INTEGER_REPRESENTATION_SIGNED,
                                       INTEGER_REPRESENTATION_UNSIGNED,
                                       NUMERIC_RANGE_NOT_CONTAINED> {
-  static constexpr RangeConstraint Check(Src value) {
-    return IntegerBitsPlusSign<Dst>::value > IntegerBitsPlusSign<Src>::value
-               ? RANGE_VALID
-               : GetRangeConstraint(
-                     value <= static_cast<Src>(NarrowingRange<Dst, Src>::max()),
-                     true);
+  static constexpr RangeCheck Check(Src value) {
+    using DstLimits = NarrowingRange<Dst, Src, Bounds>;
+    using Promotion = decltype(Src() + Dst());
+    return RangeCheck(static_cast<Promotion>(value) <=
+                          static_cast<Promotion>(DstLimits::max()),
+                      DstLimits::lowest() <= Dst(0) ||
+                          static_cast<Promotion>(value) >=
+                              static_cast<Promotion>(DstLimits::lowest()));
   }
 };
 
 // Signed to unsigned: The upper boundary may be exceeded for a narrower Dst,
-// and any negative value exceeds the lower boundary.
-template <typename Dst, typename Src>
+// and any negative value exceeds the lower boundary for standard limits.
+template <typename Dst, typename Src, template <typename> class Bounds>
 struct DstRangeRelationToSrcRangeImpl<Dst,
                                       Src,
+                                      Bounds,
                                       INTEGER_REPRESENTATION_UNSIGNED,
                                       INTEGER_REPRESENTATION_SIGNED,
                                       NUMERIC_RANGE_NOT_CONTAINED> {
-  static constexpr RangeConstraint Check(Src value) {
-    return (MaxExponent<Dst>::value >= MaxExponent<Src>::value)
-               ? GetRangeConstraint(true, value >= static_cast<Src>(0))
-               : GetRangeConstraint(
-                     value <= static_cast<Src>(NarrowingRange<Dst, Src>::max()),
-                     value >= static_cast<Src>(0));
+  static constexpr RangeCheck Check(Src value) {
+    using SrcLimits = std::numeric_limits<Src>;
+    using DstLimits = NarrowingRange<Dst, Src, Bounds>;
+    using Promotion = decltype(Src() + Dst());
+    return RangeCheck(
+        static_cast<Promotion>(SrcLimits::max()) <=
+                static_cast<Promotion>(DstLimits::max()) ||
+            static_cast<Promotion>(value) <=
+                static_cast<Promotion>(DstLimits::max()),
+        value >= Src(0) && (DstLimits::lowest() == 0 ||
+                            static_cast<Dst>(value) >= DstLimits::lowest()));
   }
 };
 
-template <typename Dst, typename Src>
-constexpr RangeConstraint DstRangeRelationToSrcRange(Src value) {
+template <typename Dst,
+          template <typename> class Bounds = std::numeric_limits,
+          typename Src>
+constexpr RangeCheck DstRangeRelationToSrcRange(Src value) {
   static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric.");
   static_assert(std::is_arithmetic<Dst>::value, "Result must be numeric.");
-  return DstRangeRelationToSrcRangeImpl<Dst, Src>::Check(value);
+  static_assert(Bounds<Dst>::lowest() < Bounds<Dst>::max(), "");
+  return DstRangeRelationToSrcRangeImpl<Dst, Src, Bounds>::Check(value);
 }
 
 // Integer promotion templates used by the portable checked integer arithmetic.
@@ -575,8 +611,8 @@
 template <typename L, typename R>
 constexpr bool IsLessImpl(const L lhs,
                           const R rhs,
-                          const RangeConstraint l_range,
-                          const RangeConstraint r_range) {
+                          const RangeCheck l_range,
+                          const RangeCheck r_range) {
   return l_range == RANGE_UNDERFLOW || r_range == RANGE_OVERFLOW ||
          (l_range == r_range &&
           static_cast<decltype(lhs + rhs)>(lhs) <
@@ -596,8 +632,8 @@
 template <typename L, typename R>
 constexpr bool IsLessOrEqualImpl(const L lhs,
                                  const R rhs,
-                                 const RangeConstraint l_range,
-                                 const RangeConstraint r_range) {
+                                 const RangeCheck l_range,
+                                 const RangeCheck r_range) {
   return l_range == RANGE_UNDERFLOW || r_range == RANGE_OVERFLOW ||
          (l_range == r_range &&
           static_cast<decltype(lhs + rhs)>(lhs) <=
@@ -617,8 +653,8 @@
 template <typename L, typename R>
 constexpr bool IsGreaterImpl(const L lhs,
                              const R rhs,
-                             const RangeConstraint l_range,
-                             const RangeConstraint r_range) {
+                             const RangeCheck l_range,
+                             const RangeCheck r_range) {
   return l_range == RANGE_OVERFLOW || r_range == RANGE_UNDERFLOW ||
          (l_range == r_range &&
           static_cast<decltype(lhs + rhs)>(lhs) >
@@ -638,8 +674,8 @@
 template <typename L, typename R>
 constexpr bool IsGreaterOrEqualImpl(const L lhs,
                                     const R rhs,
-                                    const RangeConstraint l_range,
-                                    const RangeConstraint r_range) {
+                                    const RangeCheck l_range,
+                                    const RangeCheck r_range) {
   return l_range == RANGE_OVERFLOW || r_range == RANGE_UNDERFLOW ||
          (l_range == r_range &&
           static_cast<decltype(lhs + rhs)>(lhs) >=
diff --git a/base/numerics/safe_numerics_unittest.cc b/base/numerics/safe_numerics_unittest.cc
index 0e3d999b..5304593 100644
--- a/base/numerics/safe_numerics_unittest.cc
+++ b/base/numerics/safe_numerics_unittest.cc
@@ -671,7 +671,14 @@
     TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max());
     TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1));
     TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, static_cast<Src>(-1));
+
+    // Additional saturation tests.
+    EXPECT_EQ(DstLimits::max(), saturated_cast<Dst>(SrcLimits::max()));
+    EXPECT_EQ(DstLimits::lowest(), saturated_cast<Dst>(SrcLimits::lowest()));
+
     if (SrcLimits::is_iec559) {
+      EXPECT_EQ(Dst(0), saturated_cast<Dst>(SrcLimits::quiet_NaN()));
+
       TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::max() * -1);
       TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity());
       TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1);
@@ -714,6 +721,10 @@
     TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::lowest());
     TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max());
     TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1));
+
+    // Additional saturation tests.
+    EXPECT_EQ(DstLimits::max(), saturated_cast<Dst>(SrcLimits::max()));
+    EXPECT_EQ(Dst(0), saturated_cast<Dst>(SrcLimits::lowest()));
   }
 };
 
diff --git a/chrome/VERSION b/chrome/VERSION
index 31c6f095..15eeeb6 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=57
 MINOR=0
-BUILD=2957
+BUILD=2958
 PATCH=0
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index 275111d..f105606 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -111,6 +111,7 @@
   "+third_party/WebKit/public/platform/modules/permissions/permission_status.mojom.h",
   "+third_party/WebKit/public/platform/modules/shapedetection/barcodedetection.mojom.h",
   "+third_party/WebKit/public/platform/modules/webshare/webshare.mojom.h",
+  "+third_party/WebKit/public/platform/site_engagement.mojom.h",
   "+third_party/WebKit/public/public_features.h",
   "+third_party/WebKit/public/web/WebCache.h",
   "+third_party/WebKit/public/web/WebContextMenuData.h",
diff --git a/chrome/browser/engagement/important_sites_util.cc b/chrome/browser/engagement/important_sites_util.cc
index e50ebc91..cdb5ff7 100644
--- a/chrome/browser/engagement/important_sites_util.cc
+++ b/chrome/browser/engagement/important_sites_util.cc
@@ -26,6 +26,7 @@
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "third_party/WebKit/public/platform/site_engagement.mojom.h"
 #include "url/gurl.h"
 
 namespace {
@@ -210,7 +211,7 @@
 
 void PopulateInfoMapWithSiteEngagement(
     Profile* profile,
-    SiteEngagementService::EngagementLevel minimum_engagement,
+    blink::mojom::EngagementLevel minimum_engagement,
     std::map<GURL, double>* engagement_map,
     base::hash_map<std::string, ImportantDomainInfo>* output) {
   SiteEngagementService* service = SiteEngagementService::Get(profile);
@@ -275,7 +276,7 @@
                  [service](const BookmarkModel::URLAndTitle& entry) {
                    return service->IsEngagementAtLeast(
                        entry.url.GetOrigin(),
-                       SiteEngagementService::ENGAGEMENT_LEVEL_LOW);
+                       blink::mojom::EngagementLevel::LOW);
                  });
     std::sort(result_bookmarks.begin(), result_bookmarks.end(),
               [&engagement_map](const BookmarkModel::URLAndTitle& a,
@@ -326,7 +327,7 @@
   std::map<GURL, double> engagement_map;
 
   PopulateInfoMapWithSiteEngagement(
-      profile, SiteEngagementService::ENGAGEMENT_LEVEL_MEDIUM, &engagement_map,
+      profile, blink::mojom::EngagementLevel::MEDIUM, &engagement_map,
       &important_info);
 
   PopulateInfoMapWithContentTypeAllowed(
@@ -438,5 +439,5 @@
   site_engagement_service->ResetScoreForURL(
       origin, SiteEngagementScore::GetMediumEngagementBoundary());
   DCHECK(site_engagement_service->IsEngagementAtLeast(
-      origin, SiteEngagementService::ENGAGEMENT_LEVEL_MEDIUM));
+      origin, blink::mojom::EngagementLevel::MEDIUM));
 }
diff --git a/chrome/browser/engagement/site_engagement_helper.cc b/chrome/browser/engagement/site_engagement_helper.cc
index 14d2fe5d..dbef378 100644
--- a/chrome/browser/engagement/site_engagement_helper.cc
+++ b/chrome/browser/engagement/site_engagement_helper.cc
@@ -6,13 +6,19 @@
 
 #include <utility>
 
+#include "base/bind.h"
+#include "base/callback.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
 #include "chrome/browser/engagement/site_engagement_service.h"
 #include "chrome/browser/prerender/prerender_contents.h"
 #include "chrome/browser/profiles/profile.h"
 #include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/associated_interface_provider.h"
+#include "url/gurl.h"
+#include "url/origin.h"
 
 namespace {
 
@@ -25,6 +31,40 @@
 
 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SiteEngagementService::Helper);
 
+// static
+void SiteEngagementService::Helper::SetSecondsBetweenUserInputCheck(
+    int seconds) {
+  g_seconds_to_pause_engagement_detection = seconds;
+}
+
+// static
+void SiteEngagementService::Helper::SetSecondsTrackingDelayAfterNavigation(
+    int seconds) {
+  g_seconds_delay_after_navigation = seconds;
+}
+
+// static
+void SiteEngagementService::Helper::SetSecondsTrackingDelayAfterShow(
+    int seconds) {
+  g_seconds_delay_after_show = seconds;
+}
+
+SiteEngagementService::Helper::~Helper() {
+  service_->HelperDeleted(this);
+  if (web_contents()) {
+    input_tracker_.Stop();
+    media_tracker_.Stop();
+  }
+}
+
+void SiteEngagementService::Helper::OnEngagementLevelChanged(
+    const GURL& url,
+    blink::mojom::EngagementLevel level) {
+  web_contents()->ForEachFrame(base::Bind(
+      &SiteEngagementService::Helper::SendEngagementLevelToFramesMatchingOrigin,
+      base::Unretained(this), url::Origin(url), level));
+}
+
 SiteEngagementService::Helper::PeriodicTracker::PeriodicTracker(
     SiteEngagementService::Helper* helper)
     : helper_(helper), pause_timer_(new base::Timer(true, false)) {}
@@ -157,19 +197,14 @@
   is_hidden_ = true;
 }
 
-SiteEngagementService::Helper::~Helper() {
-  if (web_contents()) {
-    input_tracker_.Stop();
-    media_tracker_.Stop();
-  }
-}
-
 SiteEngagementService::Helper::Helper(content::WebContents* web_contents)
     : content::WebContentsObserver(web_contents),
       input_tracker_(this, web_contents),
       media_tracker_(this, web_contents),
       service_(SiteEngagementService::Get(
-          Profile::FromBrowserContext(web_contents->GetBrowserContext()))) {}
+          Profile::FromBrowserContext(web_contents->GetBrowserContext()))) {
+  service_->HelperCreated(this);
+}
 
 void SiteEngagementService::Helper::RecordUserInput(
     SiteEngagementMetrics::EngagementType type) {
@@ -185,6 +220,24 @@
     service_->HandleMediaPlaying(contents, is_hidden);
 }
 
+void SiteEngagementService::Helper::SendEngagementLevelToFramesMatchingOrigin(
+    const url::Origin& origin,
+    blink::mojom::EngagementLevel level,
+    content::RenderFrameHost* render_frame_host) {
+  if (origin == render_frame_host->GetLastCommittedOrigin()) {
+    SendEngagementLevelToFrame(origin, level, render_frame_host);
+  }
+}
+
+void SiteEngagementService::Helper::SendEngagementLevelToFrame(
+    const url::Origin& origin,
+    blink::mojom::EngagementLevel level,
+    content::RenderFrameHost* render_frame_host) {
+  blink::mojom::EngagementClientAssociatedPtr client;
+  render_frame_host->GetRemoteAssociatedInterfaces()->GetInterface(&client);
+  client->SetEngagementLevel(origin, level);
+}
+
 void SiteEngagementService::Helper::DidFinishNavigation(
     content::NavigationHandle* handle) {
   // Ignore uncommitted, non main-frame, same page, or error page navigations.
@@ -218,6 +271,17 @@
       base::TimeDelta::FromSeconds(g_seconds_delay_after_navigation));
 }
 
+void SiteEngagementService::Helper::ReadyToCommitNavigation(
+    content::NavigationHandle* handle) {
+  if (service_->ShouldRecordEngagement(handle->GetURL())) {
+    // Don't bother sending the engagement if we wouldn't have recorded any for
+    // the URL. These will have NONE engagement by default.
+    SendEngagementLevelToFrame(url::Origin(handle->GetURL()),
+                               service_->GetEngagementLevel(handle->GetURL()),
+                               handle->GetRenderFrameHost());
+  }
+}
+
 void SiteEngagementService::Helper::WasShown() {
   // Ensure that the input callbacks are registered when we come into view.
   input_tracker_.Start(
@@ -228,21 +292,3 @@
   // Ensure that the input callbacks are not registered when hidden.
   input_tracker_.Stop();
 }
-
-// static
-void SiteEngagementService::Helper::SetSecondsBetweenUserInputCheck(
-    int seconds) {
-  g_seconds_to_pause_engagement_detection = seconds;
-}
-
-// static
-void SiteEngagementService::Helper::SetSecondsTrackingDelayAfterNavigation(
-    int seconds) {
-  g_seconds_delay_after_navigation = seconds;
-}
-
-// static
-void SiteEngagementService::Helper::SetSecondsTrackingDelayAfterShow(
-    int seconds) {
-  g_seconds_delay_after_show = seconds;
-}
diff --git a/chrome/browser/engagement/site_engagement_helper.h b/chrome/browser/engagement/site_engagement_helper.h
index 134f5f0..7518e8f6 100644
--- a/chrome/browser/engagement/site_engagement_helper.h
+++ b/chrome/browser/engagement/site_engagement_helper.h
@@ -11,10 +11,16 @@
 #include "chrome/browser/engagement/site_engagement_service.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
+#include "third_party/WebKit/public/platform/site_engagement.mojom.h"
+
+class GURL;
 
 namespace content {
 class NavigationHandle;
-class WebContents;
+}
+
+namespace url {
+class Origin;
 }
 
 // Per-WebContents class to handle updating the site engagement scores for
@@ -23,12 +29,15 @@
     : public content::WebContentsObserver,
       public content::WebContentsUserData<SiteEngagementService::Helper> {
  public:
-  ~Helper() override;
-
   static void SetSecondsBetweenUserInputCheck(int seconds);
   static void SetSecondsTrackingDelayAfterNavigation(int seconds);
   static void SetSecondsTrackingDelayAfterShow(int seconds);
 
+  ~Helper() override;
+
+  void OnEngagementLevelChanged(const GURL& url,
+                                blink::mojom::EngagementLevel level);
+
  private:
   // Class to encapsulate the periodic detection of site engagement.
   //
@@ -160,8 +169,17 @@
   // current WebContents URL.
   void RecordMediaPlaying(bool is_hidden);
 
+  void SendEngagementLevelToFramesMatchingOrigin(
+      const url::Origin& origin,
+      blink::mojom::EngagementLevel level,
+      content::RenderFrameHost* render_frame_host);
+  void SendEngagementLevelToFrame(const url::Origin& origin,
+                                  blink::mojom::EngagementLevel level,
+                                  content::RenderFrameHost* render_frame_host);
+
   // content::WebContentsObserver overrides.
   void DidFinishNavigation(content::NavigationHandle* handle) override;
+  void ReadyToCommitNavigation(content::NavigationHandle* handle) override;
   void WasShown() override;
   void WasHidden() override;
 
diff --git a/chrome/browser/engagement/site_engagement_score.cc b/chrome/browser/engagement/site_engagement_score.cc
index d38d2ad..d9cae36 100644
--- a/chrome/browser/engagement/site_engagement_score.cc
+++ b/chrome/browser/engagement/site_engagement_score.cc
@@ -247,6 +247,28 @@
       std::move(score_dict_));
 }
 
+blink::mojom::EngagementLevel SiteEngagementScore::GetEngagementLevel() const {
+  DCHECK_LT(GetMediumEngagementBoundary(), GetHighEngagementBoundary());
+
+  double score = GetScore();
+  if (score == 0)
+    return blink::mojom::EngagementLevel::NONE;
+
+  if (score < 1)
+    return blink::mojom::EngagementLevel::MINIMAL;
+
+  if (score < GetMediumEngagementBoundary())
+    return blink::mojom::EngagementLevel::LOW;
+
+  if (score < GetHighEngagementBoundary())
+    return blink::mojom::EngagementLevel::MEDIUM;
+
+  if (score < SiteEngagementScore::kMaxPoints)
+    return blink::mojom::EngagementLevel::HIGH;
+
+  return blink::mojom::EngagementLevel::MAX;
+}
+
 bool SiteEngagementScore::MaxPointsPerDayAdded() const {
   if (!last_engagement_time_.is_null() &&
       clock_->Now().LocalMidnight() != last_engagement_time_.LocalMidnight()) {
diff --git a/chrome/browser/engagement/site_engagement_score.h b/chrome/browser/engagement/site_engagement_score.h
index c2fe659..bb29a78 100644
--- a/chrome/browser/engagement/site_engagement_score.h
+++ b/chrome/browser/engagement/site_engagement_score.h
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "base/time/time.h"
 #include "base/values.h"
+#include "third_party/WebKit/public/platform/site_engagement.mojom.h"
 #include "url/gurl.h"
 
 namespace base {
@@ -129,6 +130,9 @@
   // Writes the values in this score into |settings_map_|.
   void Commit();
 
+  // Returns the discrete engagement level for this score.
+  blink::mojom::EngagementLevel GetEngagementLevel() const;
+
   // Returns true if the maximum number of points today has been added.
   bool MaxPointsPerDayAdded() const;
 
diff --git a/chrome/browser/engagement/site_engagement_service.cc b/chrome/browser/engagement/site_engagement_service.cc
index 7104d0d..7ebb7b6 100644
--- a/chrome/browser/engagement/site_engagement_service.cc
+++ b/chrome/browser/engagement/site_engagement_service.cc
@@ -20,6 +20,7 @@
 #include "base/values.h"
 #include "chrome/browser/banners/app_banner_settings_helper.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
+#include "chrome/browser/engagement/site_engagement_helper.h"
 #include "chrome/browser/engagement/site_engagement_metrics.h"
 #include "chrome/browser/engagement/site_engagement_score.h"
 #include "chrome/browser/engagement/site_engagement_service_factory.h"
@@ -32,7 +33,9 @@
 #include "components/history/core/browser/history_service.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/associated_interface_provider.h"
 #include "url/gurl.h"
 
 #if defined(OS_ANDROID)
@@ -126,24 +129,12 @@
     history->RemoveObserver(this);
 }
 
-SiteEngagementService::EngagementLevel
+blink::mojom::EngagementLevel
 SiteEngagementService::GetEngagementLevel(const GURL& url) const {
-  DCHECK_LT(SiteEngagementScore::GetMediumEngagementBoundary(),
-            SiteEngagementScore::GetHighEngagementBoundary());
-  double score = GetScore(url);
-  if (score == 0)
-    return ENGAGEMENT_LEVEL_NONE;
+  if (IsLastEngagementStale())
+    CleanupEngagementScores(true);
 
-  if (score < SiteEngagementScore::GetMediumEngagementBoundary())
-    return ENGAGEMENT_LEVEL_LOW;
-
-  if (score < SiteEngagementScore::GetHighEngagementBoundary())
-    return ENGAGEMENT_LEVEL_MEDIUM;
-
-  if (score < SiteEngagementScore::kMaxPoints)
-    return ENGAGEMENT_LEVEL_HIGH;
-
-  return ENGAGEMENT_LEVEL_MAX;
+  return CreateEngagementScore(url).GetEngagementLevel();
 }
 
 std::map<GURL, double> SiteEngagementService::GetScoreMap() const {
@@ -169,21 +160,24 @@
          SiteEngagementScore::GetBootstrapPoints();
 }
 
-bool SiteEngagementService::IsEngagementAtLeast(const GURL& url,
-                                                EngagementLevel level) const {
+bool SiteEngagementService::IsEngagementAtLeast(
+    const GURL& url,
+    blink::mojom::EngagementLevel level) const {
   DCHECK_LT(SiteEngagementScore::GetMediumEngagementBoundary(),
             SiteEngagementScore::GetHighEngagementBoundary());
   double score = GetScore(url);
   switch (level) {
-    case ENGAGEMENT_LEVEL_NONE:
+    case blink::mojom::EngagementLevel::NONE:
       return true;
-    case ENGAGEMENT_LEVEL_LOW:
+    case blink::mojom::EngagementLevel::MINIMAL:
       return score > 0;
-    case ENGAGEMENT_LEVEL_MEDIUM:
+    case blink::mojom::EngagementLevel::LOW:
+      return score >= 1;
+    case blink::mojom::EngagementLevel::MEDIUM:
       return score >= SiteEngagementScore::GetMediumEngagementBoundary();
-    case ENGAGEMENT_LEVEL_HIGH:
+    case blink::mojom::EngagementLevel::HIGH:
       return score >= SiteEngagementScore::GetHighEngagementBoundary();
-    case ENGAGEMENT_LEVEL_MAX:
+    case blink::mojom::EngagementLevel::MAX:
       return score == SiteEngagementScore::kMaxPoints;
   }
   NOTREACHED();
@@ -222,6 +216,16 @@
   score.Commit();
 }
 
+void SiteEngagementService::HelperCreated(
+    SiteEngagementService::Helper* helper) {
+  helpers_.insert(helper);
+}
+
+void SiteEngagementService::HelperDeleted(
+    SiteEngagementService::Helper* helper) {
+  helpers_.erase(helper);
+}
+
 double SiteEngagementService::GetScore(const GURL& url) const {
   // Ensure that if engagement is stale, we clean things up before fetching the
   // score.
@@ -273,10 +277,16 @@
     CleanupEngagementScores(true);
 
   SiteEngagementScore score = CreateEngagementScore(url);
+  blink::mojom::EngagementLevel old_level = score.GetEngagementLevel();
+
   score.AddPoints(points);
   score.Commit();
 
   SetLastEngagementTime(score.last_engagement_time());
+
+  blink::mojom::EngagementLevel new_level = score.GetEngagementLevel();
+  if (old_level != new_level)
+    SendLevelChangeToHelpers(url, new_level);
 }
 
 void SiteEngagementService::AfterStartupTask() {
@@ -498,6 +508,13 @@
     observer.OnEngagementIncreased(web_contents, url, GetScore(url));
 }
 
+void SiteEngagementService::SendLevelChangeToHelpers(
+    const GURL& url,
+    blink::mojom::EngagementLevel level) {
+  for (SiteEngagementService::Helper* helper : helpers_)
+    helper->OnEngagementLevelChanged(url, level);
+}
+
 bool SiteEngagementService::IsLastEngagementStale() const {
   // Only happens on first run when no engagement has ever been recorded.
   base::Time last_engagement_time = GetLastEngagementTime();
diff --git a/chrome/browser/engagement/site_engagement_service.h b/chrome/browser/engagement/site_engagement_service.h
index 350d30a9..cb1d47b 100644
--- a/chrome/browser/engagement/site_engagement_service.h
+++ b/chrome/browser/engagement/site_engagement_service.h
@@ -19,6 +19,7 @@
 #include "chrome/browser/engagement/site_engagement_observer.h"
 #include "components/history/core/browser/history_service_observer.h"
 #include "components/keyed_service/core/keyed_service.h"
+#include "third_party/WebKit/public/platform/site_engagement.mojom.h"
 #include "ui/base/page_transition_types.h"
 
 namespace base {
@@ -75,14 +76,6 @@
   // the service of them.
   class Helper;
 
-  enum EngagementLevel {
-    ENGAGEMENT_LEVEL_NONE,
-    ENGAGEMENT_LEVEL_LOW,
-    ENGAGEMENT_LEVEL_MEDIUM,
-    ENGAGEMENT_LEVEL_HIGH,
-    ENGAGEMENT_LEVEL_MAX,
-  };
-
   // The name of the site engagement variation field trial.
   static const char kEngagementParams[];
 
@@ -113,7 +106,7 @@
   ~SiteEngagementService() override;
 
   // Returns the engagement level of |url|.
-  EngagementLevel GetEngagementLevel(const GURL& url) const;
+  blink::mojom::EngagementLevel GetEngagementLevel(const GURL& url) const;
 
   // Returns a map of all stored origins and their engagement scores.
   std::map<GURL, double> GetScoreMap() const;
@@ -124,7 +117,8 @@
   bool IsBootstrapped() const;
 
   // Returns whether |url| has at least the given |level| of engagement.
-  bool IsEngagementAtLeast(const GURL& url, EngagementLevel level) const;
+  bool IsEngagementAtLeast(const GURL& url,
+                           blink::mojom::EngagementLevel level) const;
 
   // Resets the engagement score |url| to |score|, clearing daily limits.
   void ResetScoreForURL(const GURL& url, double score);
@@ -133,6 +127,9 @@
   // clock_->Now().
   void SetLastShortcutLaunchTime(const GURL& url);
 
+  void HelperCreated(SiteEngagementService::Helper* helper);
+  void HelperDeleted(SiteEngagementService::Helper* helper);
+
   // Overridden from SiteEngagementScoreProvider.
   double GetScore(const GURL& url) const override;
   double GetTotalEngagementPoints() const override;
@@ -231,6 +228,11 @@
   void HandleUserInput(content::WebContents* web_contents,
                        SiteEngagementMetrics::EngagementType type);
 
+  // Called if |url| changes to |level| engagement, and informs every Helper of
+  // the change.
+  void SendLevelChangeToHelpers(const GURL& url,
+                                blink::mojom::EngagementLevel level);
+
   // Returns true if the last engagement increasing event seen by the site
   // engagement service was sufficiently long ago that we need to reset all
   // scores to be relative to now. This ensures that users who do not use the
@@ -277,6 +279,9 @@
   // upload.
   base::Time last_metrics_time_;
 
+  // All helpers currently attached to a WebContents.
+  std::set<SiteEngagementService::Helper*> helpers_;
+
   // A list of observers. When any origin registers an engagement-increasing
   // event, each observer's OnEngagementIncreased method will be called.
   base::ObserverList<SiteEngagementObserver> observer_list_;
diff --git a/chrome/browser/engagement/site_engagement_service_unittest.cc b/chrome/browser/engagement/site_engagement_service_unittest.cc
index 69f813f3..c7dca74 100644
--- a/chrome/browser/engagement/site_engagement_service_unittest.cc
+++ b/chrome/browser/engagement/site_engagement_service_unittest.cc
@@ -1196,17 +1196,17 @@
 }
 
 TEST_F(SiteEngagementServiceTest, EngagementLevel) {
-  static_assert(SiteEngagementService::ENGAGEMENT_LEVEL_NONE !=
-                    SiteEngagementService::ENGAGEMENT_LEVEL_LOW,
+  static_assert(blink::mojom::EngagementLevel::NONE !=
+                    blink::mojom::EngagementLevel::LOW,
                 "enum values should not be equal");
-  static_assert(SiteEngagementService::ENGAGEMENT_LEVEL_LOW !=
-                    SiteEngagementService::ENGAGEMENT_LEVEL_MEDIUM,
+  static_assert(blink::mojom::EngagementLevel::LOW !=
+                    blink::mojom::EngagementLevel::MEDIUM,
                 "enum values should not be equal");
-  static_assert(SiteEngagementService::ENGAGEMENT_LEVEL_MEDIUM !=
-                    SiteEngagementService::ENGAGEMENT_LEVEL_HIGH,
+  static_assert(blink::mojom::EngagementLevel::MEDIUM !=
+                    blink::mojom::EngagementLevel::HIGH,
                 "enum values should not be equal");
-  static_assert(SiteEngagementService::ENGAGEMENT_LEVEL_HIGH !=
-                    SiteEngagementService::ENGAGEMENT_LEVEL_MAX,
+  static_assert(blink::mojom::EngagementLevel::HIGH !=
+                    blink::mojom::EngagementLevel::MAX,
                 "enum values should not be equal");
 
   base::SimpleTestClock* clock = new base::SimpleTestClock();
@@ -1219,54 +1219,79 @@
   GURL url1("https://www.google.com/");
   GURL url2("http://www.google.com/");
 
-  EXPECT_EQ(SiteEngagementService::ENGAGEMENT_LEVEL_NONE,
+  EXPECT_EQ(blink::mojom::EngagementLevel::NONE,
             service->GetEngagementLevel(url1));
-  EXPECT_EQ(SiteEngagementService::ENGAGEMENT_LEVEL_NONE,
+  EXPECT_EQ(blink::mojom::EngagementLevel::NONE,
             service->GetEngagementLevel(url2));
+  EXPECT_TRUE(
+      service->IsEngagementAtLeast(url1, blink::mojom::EngagementLevel::NONE));
+  EXPECT_FALSE(service->IsEngagementAtLeast(
+      url1, blink::mojom::EngagementLevel::MINIMAL));
+  EXPECT_FALSE(
+      service->IsEngagementAtLeast(url1, blink::mojom::EngagementLevel::LOW));
+  EXPECT_FALSE(service->IsEngagementAtLeast(
+      url1, blink::mojom::EngagementLevel::MEDIUM));
+  EXPECT_FALSE(
+      service->IsEngagementAtLeast(url1, blink::mojom::EngagementLevel::HIGH));
+  EXPECT_FALSE(
+      service->IsEngagementAtLeast(url1, blink::mojom::EngagementLevel::MAX));
+
+  // Bring url2 to MINIMAL engagement.
+  service->AddPoints(url2, 0.5);
+  EXPECT_EQ(blink::mojom::EngagementLevel::NONE,
+            service->GetEngagementLevel(url1));
+  EXPECT_EQ(blink::mojom::EngagementLevel::MINIMAL,
+            service->GetEngagementLevel(url2));
+  EXPECT_TRUE(
+      service->IsEngagementAtLeast(url2, blink::mojom::EngagementLevel::NONE));
   EXPECT_TRUE(service->IsEngagementAtLeast(
-      url1, SiteEngagementService::ENGAGEMENT_LEVEL_NONE));
+      url2, blink::mojom::EngagementLevel::MINIMAL));
+  EXPECT_FALSE(
+      service->IsEngagementAtLeast(url2, blink::mojom::EngagementLevel::LOW));
   EXPECT_FALSE(service->IsEngagementAtLeast(
-      url1, SiteEngagementService::ENGAGEMENT_LEVEL_LOW));
-  EXPECT_FALSE(service->IsEngagementAtLeast(
-      url1, SiteEngagementService::ENGAGEMENT_LEVEL_MEDIUM));
-  EXPECT_FALSE(service->IsEngagementAtLeast(
-      url1, SiteEngagementService::ENGAGEMENT_LEVEL_HIGH));
-  EXPECT_FALSE(service->IsEngagementAtLeast(
-      url1, SiteEngagementService::ENGAGEMENT_LEVEL_MAX));
+      url2, blink::mojom::EngagementLevel::MEDIUM));
+  EXPECT_FALSE(
+      service->IsEngagementAtLeast(url2, blink::mojom::EngagementLevel::HIGH));
+  EXPECT_FALSE(
+      service->IsEngagementAtLeast(url2, blink::mojom::EngagementLevel::MAX));
 
   // Bring url1 to LOW engagement.
   service->AddPoints(url1, 1.0);
-  EXPECT_EQ(SiteEngagementService::ENGAGEMENT_LEVEL_LOW,
+  EXPECT_EQ(blink::mojom::EngagementLevel::LOW,
             service->GetEngagementLevel(url1));
-  EXPECT_EQ(SiteEngagementService::ENGAGEMENT_LEVEL_NONE,
+  EXPECT_EQ(blink::mojom::EngagementLevel::MINIMAL,
             service->GetEngagementLevel(url2));
+  EXPECT_TRUE(
+      service->IsEngagementAtLeast(url1, blink::mojom::EngagementLevel::NONE));
   EXPECT_TRUE(service->IsEngagementAtLeast(
-      url1, SiteEngagementService::ENGAGEMENT_LEVEL_NONE));
-  EXPECT_TRUE(service->IsEngagementAtLeast(
-      url1, SiteEngagementService::ENGAGEMENT_LEVEL_LOW));
+      url1, blink::mojom::EngagementLevel::MINIMAL));
+  EXPECT_TRUE(
+      service->IsEngagementAtLeast(url1, blink::mojom::EngagementLevel::LOW));
   EXPECT_FALSE(service->IsEngagementAtLeast(
-      url1, SiteEngagementService::ENGAGEMENT_LEVEL_MEDIUM));
-  EXPECT_FALSE(service->IsEngagementAtLeast(
-      url1, SiteEngagementService::ENGAGEMENT_LEVEL_HIGH));
-  EXPECT_FALSE(service->IsEngagementAtLeast(
-      url1, SiteEngagementService::ENGAGEMENT_LEVEL_MAX));
+      url1, blink::mojom::EngagementLevel::MEDIUM));
+  EXPECT_FALSE(
+      service->IsEngagementAtLeast(url1, blink::mojom::EngagementLevel::HIGH));
+  EXPECT_FALSE(
+      service->IsEngagementAtLeast(url1, blink::mojom::EngagementLevel::MAX));
 
   // Bring url2 to MEDIUM engagement.
-  service->AddPoints(url2, 5.0);
-  EXPECT_EQ(SiteEngagementService::ENGAGEMENT_LEVEL_LOW,
+  service->AddPoints(url2, 4.5);
+  EXPECT_EQ(blink::mojom::EngagementLevel::LOW,
             service->GetEngagementLevel(url1));
-  EXPECT_EQ(SiteEngagementService::ENGAGEMENT_LEVEL_MEDIUM,
+  EXPECT_EQ(blink::mojom::EngagementLevel::MEDIUM,
             service->GetEngagementLevel(url2));
+  EXPECT_TRUE(
+      service->IsEngagementAtLeast(url2, blink::mojom::EngagementLevel::NONE));
   EXPECT_TRUE(service->IsEngagementAtLeast(
-      url2, SiteEngagementService::ENGAGEMENT_LEVEL_NONE));
+      url2, blink::mojom::EngagementLevel::MINIMAL));
+  EXPECT_TRUE(
+      service->IsEngagementAtLeast(url2, blink::mojom::EngagementLevel::LOW));
   EXPECT_TRUE(service->IsEngagementAtLeast(
-      url2, SiteEngagementService::ENGAGEMENT_LEVEL_LOW));
-  EXPECT_TRUE(service->IsEngagementAtLeast(
-      url2, SiteEngagementService::ENGAGEMENT_LEVEL_MEDIUM));
-  EXPECT_FALSE(service->IsEngagementAtLeast(
-      url2, SiteEngagementService::ENGAGEMENT_LEVEL_HIGH));
-  EXPECT_FALSE(service->IsEngagementAtLeast(
-      url2, SiteEngagementService::ENGAGEMENT_LEVEL_MAX));
+      url2, blink::mojom::EngagementLevel::MEDIUM));
+  EXPECT_FALSE(
+      service->IsEngagementAtLeast(url2, blink::mojom::EngagementLevel::HIGH));
+  EXPECT_FALSE(
+      service->IsEngagementAtLeast(url2, blink::mojom::EngagementLevel::MAX));
 
   // Bring url2 to HIGH engagement.
   for (int i = 0; i < 9; ++i) {
@@ -1274,19 +1299,21 @@
     clock->SetNow(current_day);
     service->AddPoints(url2, 5.0);
   }
-  EXPECT_EQ(SiteEngagementService::ENGAGEMENT_LEVEL_HIGH,
+  EXPECT_EQ(blink::mojom::EngagementLevel::HIGH,
             service->GetEngagementLevel(url2));
 
+  EXPECT_TRUE(
+      service->IsEngagementAtLeast(url2, blink::mojom::EngagementLevel::NONE));
   EXPECT_TRUE(service->IsEngagementAtLeast(
-      url2, SiteEngagementService::ENGAGEMENT_LEVEL_NONE));
+      url2, blink::mojom::EngagementLevel::MINIMAL));
+  EXPECT_TRUE(
+      service->IsEngagementAtLeast(url2, blink::mojom::EngagementLevel::LOW));
   EXPECT_TRUE(service->IsEngagementAtLeast(
-      url2, SiteEngagementService::ENGAGEMENT_LEVEL_LOW));
-  EXPECT_TRUE(service->IsEngagementAtLeast(
-      url2, SiteEngagementService::ENGAGEMENT_LEVEL_MEDIUM));
-  EXPECT_TRUE(service->IsEngagementAtLeast(
-      url2, SiteEngagementService::ENGAGEMENT_LEVEL_HIGH));
-  EXPECT_FALSE(service->IsEngagementAtLeast(
-      url2, SiteEngagementService::ENGAGEMENT_LEVEL_MAX));
+      url2, blink::mojom::EngagementLevel::MEDIUM));
+  EXPECT_TRUE(
+      service->IsEngagementAtLeast(url2, blink::mojom::EngagementLevel::HIGH));
+  EXPECT_FALSE(
+      service->IsEngagementAtLeast(url2, blink::mojom::EngagementLevel::MAX));
 
   // Bring url2 to MAX engagement.
   for (int i = 0; i < 10; ++i) {
@@ -1294,18 +1321,20 @@
     clock->SetNow(current_day);
     service->AddPoints(url2, 5.0);
   }
-  EXPECT_EQ(SiteEngagementService::ENGAGEMENT_LEVEL_MAX,
+  EXPECT_EQ(blink::mojom::EngagementLevel::MAX,
             service->GetEngagementLevel(url2));
+  EXPECT_TRUE(
+      service->IsEngagementAtLeast(url2, blink::mojom::EngagementLevel::NONE));
   EXPECT_TRUE(service->IsEngagementAtLeast(
-      url2, SiteEngagementService::ENGAGEMENT_LEVEL_NONE));
+      url2, blink::mojom::EngagementLevel::MINIMAL));
+  EXPECT_TRUE(
+      service->IsEngagementAtLeast(url2, blink::mojom::EngagementLevel::LOW));
   EXPECT_TRUE(service->IsEngagementAtLeast(
-      url2, SiteEngagementService::ENGAGEMENT_LEVEL_LOW));
-  EXPECT_TRUE(service->IsEngagementAtLeast(
-      url2, SiteEngagementService::ENGAGEMENT_LEVEL_MEDIUM));
-  EXPECT_TRUE(service->IsEngagementAtLeast(
-      url2, SiteEngagementService::ENGAGEMENT_LEVEL_HIGH));
-  EXPECT_TRUE(service->IsEngagementAtLeast(
-      url2, SiteEngagementService::ENGAGEMENT_LEVEL_MAX));
+      url2, blink::mojom::EngagementLevel::MEDIUM));
+  EXPECT_TRUE(
+      service->IsEngagementAtLeast(url2, blink::mojom::EngagementLevel::HIGH));
+  EXPECT_TRUE(
+      service->IsEngagementAtLeast(url2, blink::mojom::EngagementLevel::MAX));
 }
 
 TEST_F(SiteEngagementServiceTest, Observers) {
diff --git a/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc b/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc
index e43687e4..40f4f5c4 100644
--- a/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc
+++ b/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc
@@ -311,17 +311,12 @@
   EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
 }
 
-// http://crbug.com/177163
-#if defined(OS_WIN) && !defined(NDEBUG)
-#define MAYBE_FullscreenEvents DISABLED_FullscreenEvents
-#else
-#define MAYBE_FullscreenEvents FullscreenEvents
-#endif
+// Flaky: http://crbug.com/675851
 // Tests that fullscreen transitions during a tab capture session dispatch
 // events to the onStatusChange listener.  The test loads a page that toggles
 // fullscreen mode, using the Fullscreen Javascript API, in response to mouse
 // clicks.
-IN_PROC_BROWSER_TEST_F(TabCaptureApiTest, MAYBE_FullscreenEvents) {
+IN_PROC_BROWSER_TEST_F(TabCaptureApiTest, DISABLED_FullscreenEvents) {
   AddExtensionToCommandLineWhitelist();
 
   ExtensionTestMessageListener capture_started("tab_capture_started", false);
diff --git a/chrome/browser/media/protected_media_identifier_permission_context.cc b/chrome/browser/media/protected_media_identifier_permission_context.cc
index 6d172d8ec..ea8bd5c 100644
--- a/chrome/browser/media/protected_media_identifier_permission_context.cc
+++ b/chrome/browser/media/protected_media_identifier_permission_context.cc
@@ -83,9 +83,10 @@
 }
 #endif  // defined(OS_CHROMEOS)
 
-ContentSetting ProtectedMediaIdentifierPermissionContext::GetPermissionStatus(
-      const GURL& requesting_origin,
-      const GURL& embedding_origin) const {
+ContentSetting
+ProtectedMediaIdentifierPermissionContext::GetPermissionStatusInternal(
+    const GURL& requesting_origin,
+    const GURL& embedding_origin) const {
   DVLOG(1) << __func__ << ": (" << requesting_origin.spec() << ", "
            << embedding_origin.spec() << ")";
 
@@ -94,8 +95,9 @@
     return CONTENT_SETTING_BLOCK;
   }
 
-  ContentSetting content_setting = PermissionContextBase::GetPermissionStatus(
-      requesting_origin, embedding_origin);
+  ContentSetting content_setting =
+      PermissionContextBase::GetPermissionStatusInternal(requesting_origin,
+                                                         embedding_origin);
   DCHECK(content_setting == CONTENT_SETTING_ALLOW ||
          content_setting == CONTENT_SETTING_BLOCK ||
          content_setting == CONTENT_SETTING_ASK);
diff --git a/chrome/browser/media/protected_media_identifier_permission_context.h b/chrome/browser/media/protected_media_identifier_permission_context.h
index 8b00f4a..b5e22f7 100644
--- a/chrome/browser/media/protected_media_identifier_permission_context.h
+++ b/chrome/browser/media/protected_media_identifier_permission_context.h
@@ -45,7 +45,7 @@
                         bool user_gesture,
                         const BrowserPermissionCallback& callback) override;
 #endif  // defined(OS_CHROMEOS)
-  ContentSetting GetPermissionStatus(
+  ContentSetting GetPermissionStatusInternal(
       const GURL& requesting_origin,
       const GURL& embedding_origin) const override;
   void CancelPermissionRequest(content::WebContents* web_contents,
diff --git a/chrome/browser/media/webrtc/media_stream_device_permission_context.cc b/chrome/browser/media/webrtc/media_stream_device_permission_context.cc
index 171c207..8220b34 100644
--- a/chrome/browser/media/webrtc/media_stream_device_permission_context.cc
+++ b/chrome/browser/media/webrtc/media_stream_device_permission_context.cc
@@ -33,7 +33,7 @@
   callback.Run(CONTENT_SETTING_BLOCK);
 }
 
-ContentSetting MediaStreamDevicePermissionContext::GetPermissionStatus(
+ContentSetting MediaStreamDevicePermissionContext::GetPermissionStatusInternal(
     const GURL& requesting_origin,
     const GURL& embedding_origin) const {
   // TODO(raymes): Merge this policy check into content settings
@@ -63,7 +63,7 @@
 
   // Check the content setting. TODO(raymes): currently mic/camera permission
   // doesn't consider the embedder.
-  ContentSetting setting = PermissionContextBase::GetPermissionStatus(
+  ContentSetting setting = PermissionContextBase::GetPermissionStatusInternal(
       requesting_origin, requesting_origin);
 
   if (setting == CONTENT_SETTING_DEFAULT)
diff --git a/chrome/browser/media/webrtc/media_stream_device_permission_context.h b/chrome/browser/media/webrtc/media_stream_device_permission_context.h
index 14b8844..b9ccf177 100644
--- a/chrome/browser/media/webrtc/media_stream_device_permission_context.h
+++ b/chrome/browser/media/webrtc/media_stream_device_permission_context.h
@@ -31,7 +31,7 @@
 
   // TODO(xhwang): GURL.GetOrigin() shouldn't be used as the origin. Need to
   // refactor to use url::Origin. crbug.com/527149 is filed for this.
-  ContentSetting GetPermissionStatus(
+  ContentSetting GetPermissionStatusInternal(
       const GURL& requesting_origin,
       const GURL& embedding_origin) const override;
 
diff --git a/chrome/browser/notifications/notification_permission_context.cc b/chrome/browser/notifications/notification_permission_context.cc
index 5f0aa58..88a0263 100644
--- a/chrome/browser/notifications/notification_permission_context.cc
+++ b/chrome/browser/notifications/notification_permission_context.cc
@@ -172,7 +172,7 @@
 
 NotificationPermissionContext::~NotificationPermissionContext() {}
 
-ContentSetting NotificationPermissionContext::GetPermissionStatus(
+ContentSetting NotificationPermissionContext::GetPermissionStatusInternal(
     const GURL& requesting_origin,
     const GURL& embedding_origin) const {
   // Push messaging is only allowed to be granted on top-level origins.
@@ -181,8 +181,8 @@
     return CONTENT_SETTING_BLOCK;
   }
 
-  return PermissionContextBase::GetPermissionStatus(requesting_origin,
-                                                    embedding_origin);
+  return PermissionContextBase::GetPermissionStatusInternal(requesting_origin,
+                                                            embedding_origin);
 }
 
 void NotificationPermissionContext::ResetPermission(
diff --git a/chrome/browser/notifications/notification_permission_context.h b/chrome/browser/notifications/notification_permission_context.h
index 06053da2..c9ab989 100644
--- a/chrome/browser/notifications/notification_permission_context.h
+++ b/chrome/browser/notifications/notification_permission_context.h
@@ -19,7 +19,7 @@
   ~NotificationPermissionContext() override;
 
   // PermissionContextBase implementation.
-  ContentSetting GetPermissionStatus(
+  ContentSetting GetPermissionStatusInternal(
       const GURL& requesting_origin,
       const GURL& embedding_origin) const override;
   void ResetPermission(const GURL& requesting_origin,
diff --git a/chrome/browser/permissions/permission_context_base.cc b/chrome/browser/permissions/permission_context_base.cc
index 4fbe7f9a..42ea34f 100644
--- a/chrome/browser/permissions/permission_context_base.cc
+++ b/chrome/browser/permissions/permission_context_base.cc
@@ -124,7 +124,6 @@
 ContentSetting PermissionContextBase::GetPermissionStatus(
     const GURL& requesting_origin,
     const GURL& embedding_origin) const {
-
   // If the permission has been disabled through Finch, block all requests.
   if (IsPermissionKillSwitchOn())
     return CONTENT_SETTING_BLOCK;
@@ -134,9 +133,7 @@
     return CONTENT_SETTING_BLOCK;
   }
 
-  return HostContentSettingsMapFactory::GetForProfile(profile_)
-      ->GetContentSetting(requesting_origin, embedding_origin,
-                          content_settings_type_, std::string());
+  return GetPermissionStatusInternal(requesting_origin, embedding_origin);
 }
 
 void PermissionContextBase::ResetPermission(
@@ -169,6 +166,22 @@
   }
 }
 
+bool PermissionContextBase::IsPermissionKillSwitchOn() const {
+  const std::string param = variations::GetVariationParamValue(
+      kPermissionsKillSwitchFieldStudy,
+      PermissionUtil::GetPermissionString(permission_type_));
+
+  return param == kPermissionsKillSwitchBlockedValue;
+}
+
+ContentSetting PermissionContextBase::GetPermissionStatusInternal(
+    const GURL& requesting_origin,
+    const GURL& embedding_origin) const {
+  return HostContentSettingsMapFactory::GetForProfile(profile_)
+      ->GetContentSetting(requesting_origin, embedding_origin,
+                          content_settings_type_, std::string());
+}
+
 void PermissionContextBase::DecidePermission(
     content::WebContents* web_contents,
     const PermissionRequestID& id,
@@ -310,11 +323,3 @@
                                       content_settings_type_, std::string(),
                                       content_setting);
 }
-
-bool PermissionContextBase::IsPermissionKillSwitchOn() const {
-  const std::string param = variations::GetVariationParamValue(
-      kPermissionsKillSwitchFieldStudy,
-      PermissionUtil::GetPermissionString(permission_type_));
-
-  return param == kPermissionsKillSwitchBlockedValue;
-}
diff --git a/chrome/browser/permissions/permission_context_base.h b/chrome/browser/permissions/permission_context_base.h
index f556165e..4f59689 100644
--- a/chrome/browser/permissions/permission_context_base.h
+++ b/chrome/browser/permissions/permission_context_base.h
@@ -81,9 +81,8 @@
                                  const BrowserPermissionCallback& callback);
 
   // Returns whether the permission has been granted, denied...
-  virtual ContentSetting GetPermissionStatus(
-      const GURL& requesting_origin,
-      const GURL& embedding_origin) const;
+  ContentSetting GetPermissionStatus(const GURL& requesting_origin,
+                                     const GURL& embedding_origin) const;
 
   // Resets the permission to its default value.
   virtual void ResetPermission(const GURL& requesting_origin,
@@ -100,6 +99,10 @@
   bool IsPermissionKillSwitchOn() const;
 
  protected:
+  virtual ContentSetting GetPermissionStatusInternal(
+      const GURL& requesting_origin,
+      const GURL& embedding_origin) const;
+
   // Decide whether the permission should be granted.
   // Calls PermissionDecided if permission can be decided non-interactively,
   // or NotifyPermissionSet if permission decided by presenting an infobar.
diff --git a/chrome/browser/plugins/flash_permission_context.cc b/chrome/browser/plugins/flash_permission_context.cc
index 4056b9a..7e7eb93f 100644
--- a/chrome/browser/plugins/flash_permission_context.cc
+++ b/chrome/browser/plugins/flash_permission_context.cc
@@ -37,7 +37,7 @@
 
 FlashPermissionContext::~FlashPermissionContext() {}
 
-ContentSetting FlashPermissionContext::GetPermissionStatus(
+ContentSetting FlashPermissionContext::GetPermissionStatusInternal(
     const GURL& requesting_origin,
     const GURL& embedding_origin) const {
   HostContentSettingsMap* host_content_settings_map =
diff --git a/chrome/browser/plugins/flash_permission_context.h b/chrome/browser/plugins/flash_permission_context.h
index 1705946..7370c65 100644
--- a/chrome/browser/plugins/flash_permission_context.h
+++ b/chrome/browser/plugins/flash_permission_context.h
@@ -18,7 +18,7 @@
 
  private:
   // PermissionContextBase:
-  ContentSetting GetPermissionStatus(
+  ContentSetting GetPermissionStatusInternal(
       const GURL& requesting_origin,
       const GURL& embedding_origin) const override;
   void UpdateTabContext(const PermissionRequestID& id,
diff --git a/chrome/browser/resources/md_downloads/toolbar.html b/chrome/browser/resources/md_downloads/toolbar.html
index 2713ab3..d2cd8e2 100644
--- a/chrome/browser/resources/md_downloads/toolbar.html
+++ b/chrome/browser/resources/md_downloads/toolbar.html
@@ -26,23 +26,7 @@
       }
 
       #toolbar {
-        --cr-toolbar-field-end-padding: 0;
         --cr-toolbar-field-width: var(--downloads-card-width);
-        --cr-toolbar-header-wide: {
-          -webkit-margin-start: 24px;
-          -webkit-margin-end: 16px;  /* Only matters around 900px in Russian. */
-        };
-        --cr-toolbar-left-content-wide: {
-          -webkit-padding-start: 0;
-          flex: 1 0 1px;
-          max-width: none;
-          position: static;
-        };
-        --cr-toolbar-right-content-wide: {
-          flex: 1 0 1px;
-          position: static;
-        };
-        align-items: center;
         flex: 1;
       }
 
@@ -56,15 +40,9 @@
         };
       }
 
-      .more-actions {
-        -webkit-margin-end: 16px;
-        -webkit-margin-start: 8px;
-        text-align: end;
-      }
-
       #more {
         --paper-menu-button: {
-          padding: 0;
+          padding: 6px;
         };
       }
 
diff --git a/chrome/browser/resources/md_downloads/vulcanized.html b/chrome/browser/resources/md_downloads/vulcanized.html
index e2c4fe97..fd1b423 100644
--- a/chrome/browser/resources/md_downloads/vulcanized.html
+++ b/chrome/browser/resources/md_downloads/vulcanized.html
@@ -2964,13 +2964,12 @@
 }
 
 paper-spinner-lite {
-  --paper-spinner-color: white;
-        height: 20px;
+  ;
+        --paper-spinner-color: white;
         margin: 0 6px;
         opacity: 0;
         padding: 6px;
         position: absolute;
-        width: 20px;
 }
 
 paper-spinner-lite[active] {
@@ -3079,7 +3078,7 @@
 
 h1 {
   -webkit-margin-start: 6px;
-        -webkit-padding-end: 2px;
+        -webkit-padding-end: 12px;
         flex: 1;
         font-size: 123%;
         font-weight: 400;
@@ -3089,14 +3088,16 @@
 }
 
 #leftContent {
-  -webkit-padding-start: 18px;
-        align-items: center;
-        box-sizing: border-box;
-        display: flex;
-        position: absolute;
+  -webkit-margin-start: 12px;
         transition: opacity 100ms;
 }
 
+#leftSpacer {
+  -webkit-margin-start: 6px;
+        align-items: center;
+        display: flex;
+}
+
 #menuButton {
   height: 32px;
         margin-bottom: 6px;
@@ -3109,28 +3110,10 @@
 #centeredContent {
   display: flex;
         flex: 1 1 0;
-        justify-content: center;
 }
 
-:host([narrow_]) #centeredContent {
-  -webkit-padding-end: var(--cr-toolbar-field-end-padding, 12px);
-}
-
-:host(:not([narrow_])) h1 {
-  -webkit-margin-start: var(--cr-toolbar-header-wide_-_-webkit-margin-start); -webkit-margin-end: var(--cr-toolbar-header-wide_-_-webkit-margin-end);
-}
-
-:host(:not([narrow_])) #leftContent {
-  max-width: calc((100% - var(--cr-toolbar-field-width)) / 2);
-        -webkit-padding-start: var(--cr-toolbar-left-content-wide_-_-webkit-padding-start); flex: var(--cr-toolbar-left-content-wide_-_flex); max-width: var(--cr-toolbar-left-content-wide_-_max-width, calc((100% - var(--cr-toolbar-field-width)) / 2)); position: var(--cr-toolbar-left-content-wide_-_position);
-}
-
-:host(:not([narrow_])) #centeredContent {
-  -webkit-margin-start: var(--cr-toolbar-field-margin, 0);
-}
-
-:host(:not([narrow_])) #rightContent {
-  flex: var(--cr-toolbar-right-content-wide_-_flex); position: var(--cr-toolbar-right-content-wide_-_position);
+#rightContent {
+  -webkit-margin-end: 12px;
 }
 
 :host([narrow_]) #centeredContent {
@@ -3138,7 +3121,17 @@
 }
 
 :host([narrow_][showing-search_]) #leftContent {
-  opacity: 0;
+  position: absolute;
+        opacity: 0;
+}
+
+:host(:not([narrow_])) #leftContent {
+  flex: 1 1 var(--cr-toolbar-field-margin, 0);
+}
+
+:host(:not([narrow_])) #rightContent {
+  flex: 1 1 0;
+        text-align: end;
 }
 
 #menuPromo {
@@ -3163,7 +3156,7 @@
 #menuPromo::before {
   background: inherit;
         
-        clip-path: polygon(0 105%, 100% 105%, 50% 0);  
+        clip-path: polygon(0 105%, 100% 105%, 50% 0);
         content: '';
         display: block;
         left: 10px;
@@ -3192,18 +3185,20 @@
 
 </style>
     <div id="leftContent">
-      
-      <template is="dom-if" if="[[showMenu]]" restamp="">
-        <paper-icon-button id="menuButton" icon="cr:menu" on-tap="onMenuTap_" title="[[titleIfNotShowMenuPromo_(menuLabel, showMenuPromo)]]" aria-label$="[[menuLabel]]">
-        </paper-icon-button>
-        <template is="dom-if" if="[[showMenuPromo]]">
-          <div id="menuPromo" role="tooltip">
-            [[menuPromo]]
-            <button id="closePromo" on-tap="onClosePromoTap_" aria-label$="[[closeMenuPromo]]">βœ•</button>
-          
-        </div></template>
-      </template>
-      <h1>[[pageName]]</h1>
+      <div id="leftSpacer">
+        
+        <template is="dom-if" if="[[showMenu]]" restamp="">
+          <paper-icon-button id="menuButton" icon="cr:menu" on-tap="onMenuTap_" title="[[titleIfNotShowMenuPromo_(menuLabel, showMenuPromo)]]" aria-label$="[[menuLabel]]">
+          </paper-icon-button>
+          <template is="dom-if" if="[[showMenuPromo]]">
+            <div id="menuPromo" role="tooltip">
+              [[menuPromo]]
+              <button id="closePromo" on-tap="onClosePromoTap_" aria-label$="[[closeMenuPromo]]">βœ•</button>
+            
+          </div></template>
+        </template>
+        <h1>[[pageName]]</h1>
+      </div>
     </div>
 
     <div id="centeredContent">
@@ -3233,12 +3228,7 @@
 }
 
 #toolbar {
-  --cr-toolbar-field-end-padding: 0;
-        --cr-toolbar-field-width: var(--downloads-card-width);
-        --cr-toolbar-header-wide_-_-webkit-margin-start:  24px; --cr-toolbar-header-wide_-_-webkit-margin-end:  16px;;
-        --cr-toolbar-left-content-wide_-_-webkit-padding-start:  0; --cr-toolbar-left-content-wide_-_flex:  1 0 1px; --cr-toolbar-left-content-wide_-_max-width:  none; --cr-toolbar-left-content-wide_-_position:  static;;
-        --cr-toolbar-right-content-wide_-_flex:  1 0 1px; --cr-toolbar-right-content-wide_-_position:  static;;
-        align-items: center;
+  --cr-toolbar-field-width: var(--downloads-card-width);
         flex: 1;
 }
 
@@ -3248,14 +3238,8 @@
         --paper-icon-button_-_height:  32px; --paper-icon-button_-_padding:  6px; --paper-icon-button_-_width:  32px;;
 }
 
-.more-actions {
-  -webkit-margin-end: 16px;
-        -webkit-margin-start: 8px;
-        text-align: end;
-}
-
 #more {
-  --paper-menu-button_-_padding:  0;;
+  --paper-menu-button_-_padding:  6px;;
 }
 
 paper-menu {
diff --git a/chrome/browser/resources/md_history/app.vulcanized.html b/chrome/browser/resources/md_history/app.vulcanized.html
index 08b740a..1b59cfea 100644
--- a/chrome/browser/resources/md_history/app.vulcanized.html
+++ b/chrome/browser/resources/md_history/app.vulcanized.html
@@ -1832,13 +1832,12 @@
 }
 
 paper-spinner-lite {
-  --paper-spinner-color: white;
-        height: 20px;
+  height: var(--cr-icon-size_-_height); width: var(--cr-icon-size_-_width);
+        --paper-spinner-color: white;
         margin: 0 6px;
         opacity: 0;
         padding: 6px;
         position: absolute;
-        width: 20px;
 }
 
 paper-spinner-lite[active] {
@@ -1947,7 +1946,7 @@
 
 h1 {
   -webkit-margin-start: 6px;
-        -webkit-padding-end: 2px;
+        -webkit-padding-end: 12px;
         flex: 1;
         font-size: 123%;
         font-weight: 400;
@@ -1957,14 +1956,16 @@
 }
 
 #leftContent {
-  -webkit-padding-start: 18px;
-        align-items: center;
-        box-sizing: border-box;
-        display: flex;
-        position: absolute;
+  -webkit-margin-start: 12px;
         transition: opacity 100ms;
 }
 
+#leftSpacer {
+  -webkit-margin-start: 6px;
+        align-items: center;
+        display: flex;
+}
+
 #menuButton {
   height: 32px;
         margin-bottom: 6px;
@@ -1977,28 +1978,10 @@
 #centeredContent {
   display: flex;
         flex: 1 1 0;
-        justify-content: center;
 }
 
-:host([narrow_]) #centeredContent {
-  -webkit-padding-end: var(--cr-toolbar-field-end-padding, 12px);
-}
-
-:host(:not([narrow_])) h1 {
-  ;
-}
-
-:host(:not([narrow_])) #leftContent {
-  max-width: calc((100% - var(--cr-toolbar-field-width)) / 2);
-        ;
-}
-
-:host(:not([narrow_])) #centeredContent {
-  -webkit-margin-start: var(--cr-toolbar-field-margin, 0);
-}
-
-:host(:not([narrow_])) #rightContent {
-  position: var(--cr-toolbar-right-content-wide_-_position); left: var(--cr-toolbar-right-content-wide_-_left); right: var(--cr-toolbar-right-content-wide_-_right);
+#rightContent {
+  -webkit-margin-end: 12px;
 }
 
 :host([narrow_]) #centeredContent {
@@ -2006,7 +1989,17 @@
 }
 
 :host([narrow_][showing-search_]) #leftContent {
-  opacity: 0;
+  position: absolute;
+        opacity: 0;
+}
+
+:host(:not([narrow_])) #leftContent {
+  flex: 1 1 var(--cr-toolbar-field-margin, 0);
+}
+
+:host(:not([narrow_])) #rightContent {
+  flex: 1 1 0;
+        text-align: end;
 }
 
 #menuPromo {
@@ -2031,7 +2024,7 @@
 #menuPromo::before {
   background: inherit;
         
-        clip-path: polygon(0 105%, 100% 105%, 50% 0);  
+        clip-path: polygon(0 105%, 100% 105%, 50% 0);
         content: '';
         display: block;
         left: 10px;
@@ -2060,18 +2053,20 @@
 
 </style>
     <div id="leftContent">
-      
-      <template is="dom-if" if="[[showMenu]]" restamp="">
-        <paper-icon-button id="menuButton" icon="cr:menu" on-tap="onMenuTap_" title="[[titleIfNotShowMenuPromo_(menuLabel, showMenuPromo)]]" aria-label$="[[menuLabel]]">
-        </paper-icon-button>
-        <template is="dom-if" if="[[showMenuPromo]]">
-          <div id="menuPromo" role="tooltip">
-            [[menuPromo]]
-            <button id="closePromo" on-tap="onClosePromoTap_" aria-label$="[[closeMenuPromo]]">βœ•</button>
-          
-        </div></template>
-      </template>
-      <h1>[[pageName]]</h1>
+      <div id="leftSpacer">
+        
+        <template is="dom-if" if="[[showMenu]]" restamp="">
+          <paper-icon-button id="menuButton" icon="cr:menu" on-tap="onMenuTap_" title="[[titleIfNotShowMenuPromo_(menuLabel, showMenuPromo)]]" aria-label$="[[menuLabel]]">
+          </paper-icon-button>
+          <template is="dom-if" if="[[showMenuPromo]]">
+            <div id="menuPromo" role="tooltip">
+              [[menuPromo]]
+              <button id="closePromo" on-tap="onClosePromoTap_" aria-label$="[[closeMenuPromo]]">βœ•</button>
+            
+          </div></template>
+        </template>
+        <h1>[[pageName]]</h1>
+      </div>
     </div>
 
     <div id="centeredContent">
@@ -2320,23 +2315,13 @@
 }
 
 cr-toolbar {
-  --cr-toolbar-field-end-padding: 0;
-        --cr-toolbar-field-margin: var(--side-bar-width);
-        --cr-toolbar-right-content-wide_-_position:  absolute; --cr-toolbar-right-content-wide_-_right:  0; --cr-toolbar-right-content-wide_-_left: initial;;
-}
-
-:host-context([dir=rtl]) cr-toolbar {
-  --cr-toolbar-right-content-wide_-_position:  absolute; --cr-toolbar-right-content-wide_-_left:  0; --cr-toolbar-right-content-wide_-_right: initial;;
+  --cr-toolbar-field-margin: var(--side-bar-width);
 }
 
 :host([has-drawer]) cr-toolbar {
   --cr-toolbar-field-margin: 0;
 }
 
-cr-toolbar .more-actions {
-  -webkit-margin-end: 12px;
-}
-
 #info-button {
   background: none;
         border: none;
@@ -2512,6 +2497,7 @@
     --cr-focused-item-color: var(--google-grey-300);
     
     --cr-icon-padding: 8px;
+    --cr-icon-size_-_height:  20px; --cr-icon-size_-_width:  20px;
     --cr-selectable-focus_-_background-color:  var(--cr-focused-item-color); --cr-selectable-focus_-_outline:  none;
     --cr-separator-line: 1px solid rgba(0, 0, 0, 0.06);
     --paper-checkbox-ink-size: 40px;
@@ -2550,6 +2536,22 @@
   cursor: var(--cr-actionable_-_cursor);
 }
 
+button[is='paper-icon-button-light'].subpage-arrow {
+  background-image: url("chrome://resources/images/arrow_right.svg");
+}
+
+button[is='paper-icon-button-light'].icon-external {
+  background-image: url("chrome://resources/images/open_in_new.svg");
+}
+
+.subpage-arrow, .icon-external {
+  display: none;
+}
+
+[actionable] :-webkit-any(.subpage-arrow, .icon-external), [actionable]:-webkit-any(.subpage-arrow, .icon-external) {
+  display: block;
+}
+
 [scrollable] {
   border-color: transparent;
         border-style: solid;
@@ -3244,6 +3246,22 @@
   cursor: var(--cr-actionable_-_cursor);
 }
 
+button[is='paper-icon-button-light'].subpage-arrow {
+  background-image: url("chrome://resources/images/arrow_right.svg");
+}
+
+button[is='paper-icon-button-light'].icon-external {
+  background-image: url("chrome://resources/images/open_in_new.svg");
+}
+
+.subpage-arrow, .icon-external {
+  display: none;
+}
+
+[actionable] :-webkit-any(.subpage-arrow, .icon-external), [actionable]:-webkit-any(.subpage-arrow, .icon-external) {
+  display: block;
+}
+
 [scrollable] {
   border-color: transparent;
         border-style: solid;
diff --git a/chrome/browser/resources/md_history/history_toolbar.html b/chrome/browser/resources/md_history/history_toolbar.html
index a534da4..d7d3a5f 100644
--- a/chrome/browser/resources/md_history/history_toolbar.html
+++ b/chrome/browser/resources/md_history/history_toolbar.html
@@ -40,29 +40,13 @@
       }
 
       cr-toolbar {
-        --cr-toolbar-field-end-padding: 0;
         --cr-toolbar-field-margin: var(--side-bar-width);
-        --cr-toolbar-right-content-wide: {
-          position: absolute;
-          right: 0;
-        };
-      }
-
-      :host-context([dir=rtl]) cr-toolbar {
-        --cr-toolbar-right-content-wide: {
-          position: absolute;
-          left: 0;
-        };
       }
 
       :host([has-drawer]) cr-toolbar {
         --cr-toolbar-field-margin: 0;
       }
 
-      cr-toolbar .more-actions {
-        -webkit-margin-end: 12px;
-      }
-
       /* Info button and dropdown. */
 
       #info-button {
diff --git a/chrome/browser/resources/md_history/lazy_load.vulcanized.html b/chrome/browser/resources/md_history/lazy_load.vulcanized.html
index 23ee209..1e60803 100644
--- a/chrome/browser/resources/md_history/lazy_load.vulcanized.html
+++ b/chrome/browser/resources/md_history/lazy_load.vulcanized.html
@@ -900,6 +900,22 @@
   cursor: var(--cr-actionable_-_cursor);
 }
 
+button[is='paper-icon-button-light'].subpage-arrow {
+  background-image: url("chrome://resources/images/arrow_right.svg");
+}
+
+button[is='paper-icon-button-light'].icon-external {
+  background-image: url("chrome://resources/images/open_in_new.svg");
+}
+
+.subpage-arrow, .icon-external {
+  display: none;
+}
+
+[actionable] :-webkit-any(.subpage-arrow, .icon-external), [actionable]:-webkit-any(.subpage-arrow, .icon-external) {
+  display: block;
+}
+
 [scrollable] {
   border-color: transparent;
         border-style: solid;
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
index 3072bb23..116c0211 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
@@ -179,7 +179,8 @@
 - (void)setTabTrackingAreasEnabled:(BOOL)enabled;
 - (void)droppingURLsAt:(NSPoint)point
             givesIndex:(NSInteger*)index
-           disposition:(WindowOpenDisposition*)disposition;
+           disposition:(WindowOpenDisposition*)disposition
+           activateTab:(BOOL)activateTab;
 - (void)setNewTabButtonHoverState:(BOOL)showHover;
 - (void)themeDidChangeNotification:(NSNotification*)notification;
 - (BOOL)doesAnyOtherWebContents:(content::WebContents*)selected
@@ -2038,7 +2039,8 @@
 // to the left, it inserts to the left, and similarly for the right.
 - (void)droppingURLsAt:(NSPoint)point
             givesIndex:(NSInteger*)index
-           disposition:(WindowOpenDisposition*)disposition {
+           disposition:(WindowOpenDisposition*)disposition
+           activateTab:(BOOL)activateTab {
   // Proportion of the tab which is considered the "middle" (and causes things
   // to drop on that tab).
   const double kMiddleProportion = 0.5;
@@ -2069,7 +2071,11 @@
     // Drop in a new tab before  tab |i|?
     if (isRTL ? point.x > rightEdge : point.x < leftEdge) {
       *index = i;
-      *disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
+      if (activateTab) {
+        *disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
+      } else {
+        *disposition = WindowOpenDisposition::NEW_BACKGROUND_TAB;
+      }
       return;
     }
 
@@ -2087,10 +2093,17 @@
 
   // If we've made it here, we want to append a new tab to the end.
   *index = -1;
-  *disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
+  if (activateTab) {
+    *disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
+  } else {
+    *disposition = WindowOpenDisposition::NEW_BACKGROUND_TAB;
+  }
 }
 
-- (void)openURL:(GURL*)url inView:(NSView*)view at:(NSPoint)point {
+- (void)openURL:(GURL*)url
+         inView:(NSView*)view
+             at:(NSPoint)point
+    activateTab:(BOOL)activateTab {
   // Security: Block JavaScript to prevent self-XSS.
   if (url->SchemeIs(url::kJavaScriptScheme))
     return;
@@ -2100,11 +2113,13 @@
   WindowOpenDisposition disposition;
   [self droppingURLsAt:point
             givesIndex:&index
-           disposition:&disposition];
+           disposition:&disposition
+           activateTab:activateTab];
 
   // Either insert a new tab or open in a current tab.
   switch (disposition) {
-    case WindowOpenDisposition::NEW_FOREGROUND_TAB: {
+    case WindowOpenDisposition::NEW_FOREGROUND_TAB:
+    case WindowOpenDisposition::NEW_BACKGROUND_TAB: {
       content::RecordAction(UserMetricsAction("Tab_DropURLBetweenTabs"));
       chrome::NavigateParams params(browser_, *url,
                                     ui::PAGE_TRANSITION_TYPED);
@@ -2137,19 +2152,22 @@
     return;
   }
 
-  //TODO(viettrungluu): dropping multiple URLs.
-  if ([urls count] > 1)
-    NOTIMPLEMENTED();
+  for (NSInteger index = [urls count] - 1; index >= 0; index--) {
+    // Refactor this code.
+    // https://crbug.com/665261.
+    GURL url = url_formatter::FixupURL(
+        base::SysNSStringToUTF8([urls objectAtIndex:index]), std::string());
 
-  // Get the first URL and fix it up.
-  GURL url(GURL(url_formatter::FixupURL(
-      base::SysNSStringToUTF8([urls objectAtIndex:0]), std::string())));
+    // If the URL isn't valid, don't bother.
+    if (!url.is_valid())
+      continue;
 
-  // If the URL isn't valid, don't bother.
-  if (!url.is_valid())
-    return;
-
-  [self openURL:&url inView:view at:point];
+    if (index == static_cast<NSInteger>([urls count]) - 1) {
+      [self openURL:&url inView:view at:point activateTab:YES];
+    } else {
+      [self openURL:&url inView:view at:point activateTab:NO];
+    }
+  }
 }
 
 // (URLDropTargetController protocol)
@@ -2163,7 +2181,7 @@
       metrics::OmniboxEventProto::BLANK, &match, NULL);
   GURL url(match.destination_url);
 
-  [self openURL:&url inView:view at:point];
+  [self openURL:&url inView:view at:point activateTab:YES];
 }
 
 // (URLDropTargetController protocol)
@@ -2178,7 +2196,8 @@
   WindowOpenDisposition disposition;
   [self droppingURLsAt:point
             givesIndex:&index
-           disposition:&disposition];
+           disposition:&disposition
+           activateTab:YES];
 
   NSPoint arrowPos = NSMakePoint(0, arrowBaseY);
   if (index == -1) {
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
index 403bd8d..73ce5ce8 100644
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
+++ b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
@@ -1025,24 +1025,30 @@
     return;
   }
 
-  // TODO(viettrungluu): dropping multiple URLs?
-  if ([urls count] > 1)
-    NOTIMPLEMENTED();
+  for (NSUInteger index = 0; index < [urls count]; index++) {
+    // Refactor this code.
+    // https://crbug.com/665261.
+    GURL url = url_formatter::FixupURL(
+        base::SysNSStringToUTF8([urls objectAtIndex:index]), std::string());
 
-  // Get the first URL and fix it up.
-  GURL url(url_formatter::FixupURL(
-      base::SysNSStringToUTF8([urls objectAtIndex:0]), std::string()));
+    // If the URL isn't valid, don't bother.
+    if (!url.is_valid())
+      continue;
 
-  // Security: Sanitize text to prevent self-XSS.
-  if (url.SchemeIs(url::kJavaScriptScheme)) {
-    browser_->window()->GetLocationBar()->GetOmniboxView()->SetUserText(
-          OmniboxView::StripJavascriptSchemas(base::UTF8ToUTF16(url.spec())));
-    return;
+    // Security: Sanitize text to prevent self-XSS.
+    if (url.SchemeIs(url::kJavaScriptScheme))
+      continue;
+
+    WindowOpenDisposition disposition;
+    if (index == 0)
+      disposition = WindowOpenDisposition::CURRENT_TAB;
+    else
+      disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
+
+    OpenURLParams params(url, Referrer(), disposition,
+                         ui::PAGE_TRANSITION_TYPED, false);
+    browser_->tab_strip_model()->GetActiveWebContents()->OpenURL(params);
   }
-
-  OpenURLParams params(url, Referrer(), WindowOpenDisposition::CURRENT_TAB,
-                       ui::PAGE_TRANSITION_TYPED, false);
-  browser_->tab_strip_model()->GetActiveWebContents()->OpenURL(params);
 }
 
 // (URLDropTargetController protocol)
diff --git a/components/cryptauth/remote_device.cc b/components/cryptauth/remote_device.cc
index 2787438..386ea671 100644
--- a/components/cryptauth/remote_device.cc
+++ b/components/cryptauth/remote_device.cc
@@ -30,28 +30,34 @@
 RemoteDevice::~RemoteDevice() {}
 
 std::string RemoteDevice::GetDeviceId() const {
-   std::string to_return;
-   base::Base64Encode(public_key, &to_return);
-   return to_return;
+  std::string to_return;
+  base::Base64Encode(public_key, &to_return);
+  return to_return;
 }
 
 std::string RemoteDevice::GetTruncatedDeviceIdForLogs() const {
-   std::string id = GetDeviceId();
-   if (id.length() <= 10) {
-      return id;
-   }
-
-   return id.substr(0, 5) + "..." + id.substr(id.length() - 5, id.length());
+  return RemoteDevice::TruncateDeviceIdForLogs(GetDeviceId());
 }
 
 bool RemoteDevice::operator==(const RemoteDevice& other) const {
-   return user_id == other.user_id
-         && name == other.name
-         && public_key == other.public_key
-         && bluetooth_type == other.bluetooth_type
-         && bluetooth_address == other.bluetooth_address
-         && persistent_symmetric_key == other.persistent_symmetric_key
-         && sign_in_challenge == other.sign_in_challenge;
+  return user_id == other.user_id
+      && name == other.name
+      && public_key == other.public_key
+      && bluetooth_type == other.bluetooth_type
+      && bluetooth_address == other.bluetooth_address
+      && persistent_symmetric_key == other.persistent_symmetric_key
+      && sign_in_challenge == other.sign_in_challenge;
+}
+
+// static
+std::string RemoteDevice::TruncateDeviceIdForLogs(const std::string& full_id) {
+  if (full_id.length() <= 10) {
+    return full_id;
+  }
+
+  return full_id.substr(0, 5)
+      + "..."
+      + full_id.substr(full_id.length() - 5, full_id.length());
 }
 
 }  // namespace cryptauth
diff --git a/components/cryptauth/remote_device.h b/components/cryptauth/remote_device.h
index 5539055..79411ac 100644
--- a/components/cryptauth/remote_device.h
+++ b/components/cryptauth/remote_device.h
@@ -42,6 +42,9 @@
   std::string GetTruncatedDeviceIdForLogs() const;
 
   bool operator==(const RemoteDevice& other) const;
+
+  // Static method for truncated device ID for logs.
+  static std::string TruncateDeviceIdForLogs(const std::string& full_id);
 };
 
 typedef std::vector<RemoteDevice> RemoteDeviceList;
diff --git a/components/test_runner/spell_check_client.cc b/components/test_runner/spell_check_client.cc
index e9c450a..2173211 100644
--- a/components/test_runner/spell_check_client.cc
+++ b/components/test_runner/spell_check_client.cc
@@ -13,6 +13,8 @@
 #include "components/test_runner/mock_grammar_check.h"
 #include "components/test_runner/test_runner.h"
 #include "components/test_runner/web_test_delegate.h"
+#include "third_party/WebKit/public/web/WebFrame.h"
+#include "third_party/WebKit/public/web/WebKit.h"
 #include "third_party/WebKit/public/web/WebTextCheckingCompletion.h"
 #include "third_party/WebKit/public/web/WebTextCheckingResult.h"
 
@@ -36,6 +38,11 @@
   enabled_ = enabled;
 }
 
+void SpellCheckClient::Reset() {
+  enabled_ = false;
+  resolved_callback_.Reset();
+}
+
 // blink::WebSpellCheckClient
 void SpellCheckClient::spellCheck(
     const blink::WebString& text,
@@ -58,13 +65,17 @@
     const blink::WebVector<unsigned>& marker_offsets,
     blink::WebTextCheckingCompletion* completion) {
   if (!enabled_ || text.isEmpty()) {
-    if (completion)
+    if (completion) {
       completion->didCancelCheckingText();
+      RequestResolved();
+    }
     return;
   }
 
-  if (last_requested_text_checking_completion_)
+  if (last_requested_text_checking_completion_) {
     last_requested_text_checking_completion_->didCancelCheckingText();
+    RequestResolved();
+  }
 
   last_requested_text_checking_completion_ = completion;
   last_requested_text_check_string_ = text;
@@ -115,9 +126,41 @@
   }
   last_requested_text_checking_completion_->didFinishCheckingText(results);
   last_requested_text_checking_completion_ = 0;
+  RequestResolved();
 
   if (test_runner_->shouldDumpSpellCheckCallbacks())
     delegate_->PrintMessage("SpellCheckEvent: FinishLastTextCheck\n");
 }
 
+void SpellCheckClient::SetSpellCheckResolvedCallback(
+    v8::Local<v8::Function> callback) {
+  resolved_callback_.Reset(blink::mainThreadIsolate(), callback);
+}
+
+void SpellCheckClient::RemoveSpellCheckResolvedCallback() {
+  resolved_callback_.Reset();
+}
+
+void SpellCheckClient::RequestResolved() {
+  if (resolved_callback_.IsEmpty())
+    return;
+
+  v8::Isolate* isolate = blink::mainThreadIsolate();
+  v8::HandleScope handle_scope(isolate);
+
+  blink::WebFrame* frame = test_runner_->mainFrame();
+  if (!frame || frame->isWebRemoteFrame())
+    return;
+
+  v8::Local<v8::Context> context = frame->mainWorldScriptContext();
+  if (context.IsEmpty())
+    return;
+
+  v8::Context::Scope context_scope(context);
+
+  frame->callFunctionEvenIfScriptDisabled(
+      v8::Local<v8::Function>::New(isolate, resolved_callback_),
+      context->Global(), 0, nullptr);
+}
+
 }  // namespace test_runner
diff --git a/components/test_runner/spell_check_client.h b/components/test_runner/spell_check_client.h
index af23e133..cb0d7ab 100644
--- a/components/test_runner/spell_check_client.h
+++ b/components/test_runner/spell_check_client.h
@@ -13,6 +13,7 @@
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/platform/WebVector.h"
 #include "third_party/WebKit/public/web/WebSpellCheckClient.h"
+#include "v8/include/v8.h"
 
 namespace blink {
 class WebTextCheckingCompletion;
@@ -31,6 +32,14 @@
   void SetDelegate(WebTestDelegate* delegate);
   void SetEnabled(bool enabled);
 
+  // Sets a callback that will be invoked after each request is revoled.
+  void SetSpellCheckResolvedCallback(v8::Local<v8::Function> callback);
+
+  // Remove the above callback. Beware: don't call it inside the callback.
+  void RemoveSpellCheckResolvedCallback();
+
+  void Reset();
+
   // blink::WebSpellCheckClient implementation.
   void spellCheck(
       const blink::WebString& text,
@@ -47,6 +56,8 @@
  private:
   void FinishLastTextCheck();
 
+  void RequestResolved();
+
   // Do not perform any checking when |enabled_ == false|.
   // Tests related to spell checking should enable it manually.
   bool enabled_ = false;
@@ -57,6 +68,8 @@
   blink::WebString last_requested_text_check_string_;
   blink::WebTextCheckingCompletion* last_requested_text_checking_completion_;
 
+  v8::Persistent<v8::Function> resolved_callback_;
+
   TestRunner* test_runner_;
   WebTestDelegate* delegate_;
 
diff --git a/components/test_runner/test_runner.cc b/components/test_runner/test_runner.cc
index dbbc994..4207762 100644
--- a/components/test_runner/test_runner.cc
+++ b/components/test_runner/test_runner.cc
@@ -181,6 +181,7 @@
                                         const std::string& destination_protocol,
                                         const std::string& destination_host,
                                         bool allow_destination_subdomains);
+  void RemoveSpellCheckResolvedCallback();
   void RemoveWebPageOverlay();
   void ResetDeviceLight();
   void ResetTestHelperControllers();
@@ -241,6 +242,7 @@
   void SetPrinting();
   void SetScriptsAllowed(bool allowed);
   void SetShouldStayOnPageAfterHandlingBeforeUnload(bool value);
+  void SetSpellCheckResolvedCallback(v8::Local<v8::Function> callback);
   void SetStorageAllowed(bool allowed);
   void SetTabKeyCyclesThroughElements(bool tab_key_cycles_through_elements);
   void SetTextDirection(const std::string& direction_name);
@@ -469,6 +471,8 @@
       .SetMethod("queueReload", &TestRunnerBindings::QueueReload)
       .SetMethod("removeOriginAccessWhitelistEntry",
                  &TestRunnerBindings::RemoveOriginAccessWhitelistEntry)
+      .SetMethod("removeSpellCheckResolvedCallback",
+                 &TestRunnerBindings::RemoveSpellCheckResolvedCallback)
       .SetMethod("removeWebPageOverlay",
                  &TestRunnerBindings::RemoveWebPageOverlay)
       .SetMethod("resetDeviceLight", &TestRunnerBindings::ResetDeviceLight)
@@ -560,6 +564,8 @@
       .SetMethod(
           "setShouldStayOnPageAfterHandlingBeforeUnload",
           &TestRunnerBindings::SetShouldStayOnPageAfterHandlingBeforeUnload)
+      .SetMethod("setSpellCheckResolvedCallback",
+                 &TestRunnerBindings::SetSpellCheckResolvedCallback)
       .SetMethod("setStorageAllowed", &TestRunnerBindings::SetStorageAllowed)
       .SetMethod("setTabKeyCyclesThroughElements",
                  &TestRunnerBindings::SetTabKeyCyclesThroughElements)
@@ -748,6 +754,17 @@
     runner_->SetMockSpellCheckerEnabled(enabled);
 }
 
+void TestRunnerBindings::SetSpellCheckResolvedCallback(
+    v8::Local<v8::Function> callback) {
+  if (runner_)
+    runner_->spellcheck_->SetSpellCheckResolvedCallback(callback);
+}
+
+void TestRunnerBindings::RemoveSpellCheckResolvedCallback() {
+  if (runner_)
+    runner_->spellcheck_->RemoveSpellCheckResolvedCallback();
+}
+
 v8::Local<v8::Value>
 TestRunnerBindings::EvaluateScriptInIsolatedWorldAndReturnValue(
     int world_id, const std::string& script) {
@@ -1682,7 +1699,7 @@
   else
     close_remaining_windows_ = true;
 
-  spellcheck_->SetEnabled(false);
+  spellcheck_->Reset();
 }
 
 void TestRunner::SetTestIsRunning(bool running) {
@@ -1924,6 +1941,10 @@
   return top_loading_frame_;
 }
 
+WebFrame* TestRunner::mainFrame() const {
+  return main_view_->mainFrame();
+}
+
 void TestRunner::policyDelegateDone() {
   DCHECK(layout_test_runtime_flags_.wait_until_done());
   delegate_->TestFinished();
diff --git a/components/test_runner/test_runner.h b/components/test_runner/test_runner.h
index 1578370..efdbfb9 100644
--- a/components/test_runner/test_runner.h
+++ b/components/test_runner/test_runner.h
@@ -155,6 +155,7 @@
   // pending load requests in WorkQueue).
   bool tryToClearTopLoadingFrame(blink::WebFrame*);
 
+  blink::WebFrame* mainFrame() const;
   blink::WebFrame* topLoadingFrame() const;
   void policyDelegateDone();
   bool policyDelegateEnabled() const;
diff --git a/content/browser/frame_host/navigation_controller_android.cc b/content/browser/frame_host/navigation_controller_android.cc
index 2360efd..0808ba3 100644
--- a/content/browser/frame_host/navigation_controller_android.cc
+++ b/content/browser/frame_host/navigation_controller_android.cc
@@ -340,8 +340,7 @@
   if (reload_on_state_change) {
     // Reloading the page will send the override down as part of the
     // navigation IPC message.
-    // TODO(toyoshim): Should this call use |true| for check_for_post argument?
-    navigation_controller_->Reload(ReloadType::ORIGINAL_REQUEST_URL, false);
+    navigation_controller_->Reload(ReloadType::ORIGINAL_REQUEST_URL, true);
   }
 }
 
diff --git a/content/browser/frame_host/render_widget_host_view_guest.cc b/content/browser/frame_host/render_widget_host_view_guest.cc
index b14a741c..4c649d3 100644
--- a/content/browser/frame_host/render_widget_host_view_guest.cc
+++ b/content/browser/frame_host/render_widget_host_view_guest.cc
@@ -544,8 +544,9 @@
 
 RenderWidgetHostViewBase*
 RenderWidgetHostViewGuest::GetOwnerRenderWidgetHostView() const {
-  return static_cast<RenderWidgetHostViewBase*>(
-      guest_->GetOwnerRenderWidgetHostView());
+  return guest_ ? static_cast<RenderWidgetHostViewBase*>(
+                      guest_->GetOwnerRenderWidgetHostView())
+                : nullptr;
 }
 
 // TODO(wjmaclean): When we remove BrowserPlugin, delete this code.
diff --git a/content/browser/loader/DEPS b/content/browser/loader/DEPS
index 4eadb25f..2db05138 100644
--- a/content/browser/loader/DEPS
+++ b/content/browser/loader/DEPS
@@ -354,6 +354,7 @@
   ],
   "url_loader_factory_impl_unittest\.cc": [
     "-content",
+    "+content/browser/child_process_security_policy_impl.h",
     "+content/browser/loader/mojo_async_resource_handler.h",
     "+content/browser/loader/test_url_loader_client.h",
     "+content/browser/loader/resource_dispatcher_host_impl.h",
diff --git a/content/browser/loader/mojo_async_resource_handler.cc b/content/browser/loader/mojo_async_resource_handler.cc
index ea94fad..0d10365 100644
--- a/content/browser/loader/mojo_async_resource_handler.cc
+++ b/content/browser/loader/mojo_async_resource_handler.cc
@@ -164,6 +164,8 @@
   }
 
   NetLogObserver::PopulateResponseInfo(request(), response);
+  response->head.encoded_data_length = request()->raw_header_size();
+  reported_total_received_bytes_ = response->head.encoded_data_length;
 
   response->head.request_start = request()->creation_time();
   response->head.response_start = base::TimeTicks::Now();
@@ -245,6 +247,13 @@
   if (!bytes_read)
     return true;
 
+  const ResourceRequestInfoImpl* info = GetRequestInfo();
+  if (info->ShouldReportRawHeaders()) {
+    auto transfer_size_diff = CalculateRecentlyReceivedBytes();
+    if (transfer_size_diff > 0)
+      url_loader_client_->OnTransferSizeUpdated(transfer_size_diff);
+  }
+
   if (is_using_io_buffer_not_from_writer_) {
     // Couldn't allocate a buffer on the data pipe in OnWillRead.
     DCHECK_EQ(0u, buffer_bytes_read_);
@@ -272,13 +281,8 @@
 }
 
 void MojoAsyncResourceHandler::OnDataDownloaded(int bytes_downloaded) {
-  int64_t total_received_bytes = request()->GetTotalReceivedBytes();
-  int64_t bytes_to_report =
-      total_received_bytes - reported_total_received_bytes_;
-  reported_total_received_bytes_ = total_received_bytes;
-  DCHECK_LE(0, bytes_to_report);
-
-  url_loader_client_->OnDataDownloaded(bytes_downloaded, bytes_to_report);
+  url_loader_client_->OnDataDownloaded(bytes_downloaded,
+                                       CalculateRecentlyReceivedBytes());
 }
 
 void MojoAsyncResourceHandler::FollowRedirect() {
@@ -450,6 +454,15 @@
       GlobalRequestID(info->GetChildID(), info->GetRequestID()));
 }
 
+int64_t MojoAsyncResourceHandler::CalculateRecentlyReceivedBytes() {
+  int64_t total_received_bytes = request()->GetTotalReceivedBytes();
+  int64_t bytes_to_report =
+      total_received_bytes - reported_total_received_bytes_;
+  reported_total_received_bytes_ = total_received_bytes;
+  DCHECK_LE(0, bytes_to_report);
+  return bytes_to_report;
+}
+
 void MojoAsyncResourceHandler::ReportBadMessage(const std::string& error) {
   mojo::ReportBadMessage(error);
 }
diff --git a/content/browser/loader/mojo_async_resource_handler.h b/content/browser/loader/mojo_async_resource_handler.h
index 81a2f85a..894ff84 100644
--- a/content/browser/loader/mojo_async_resource_handler.h
+++ b/content/browser/loader/mojo_async_resource_handler.h
@@ -91,6 +91,10 @@
   bool CheckForSufficientResource();
   void OnWritable(MojoResult result);
   void Cancel();
+  // Calculates the diff between URLRequest::GetTotalReceivedBytes() and
+  // |reported_total_received_bytes_|, returns it, and updates
+  // |reported_total_received_bytes_|.
+  int64_t CalculateRecentlyReceivedBytes();
   // This function can be overriden only for tests.
   virtual void ReportBadMessage(const std::string& error);
 
diff --git a/content/browser/loader/test_url_loader_client.cc b/content/browser/loader/test_url_loader_client.cc
index f3720ee..d87ee13 100644
--- a/content/browser/loader/test_url_loader_client.cc
+++ b/content/browser/loader/test_url_loader_client.cc
@@ -45,6 +45,11 @@
     quit_closure_for_on_data_downloaded_.Run();
 }
 
+void TestURLLoaderClient::OnTransferSizeUpdated(int32_t transfer_size_diff) {
+  EXPECT_GT(transfer_size_diff, 0);
+  body_transfer_size_ += transfer_size_diff;
+}
+
 void TestURLLoaderClient::OnStartLoadingResponseBody(
     mojo::ScopedDataPipeConsumerHandle body) {
   response_body_ = std::move(body);
diff --git a/content/browser/loader/test_url_loader_client.h b/content/browser/loader/test_url_loader_client.h
index 7fa83cf..8776f44 100644
--- a/content/browser/loader/test_url_loader_client.h
+++ b/content/browser/loader/test_url_loader_client.h
@@ -33,6 +33,7 @@
   void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
                          const ResourceResponseHead& response_head) override;
   void OnDataDownloaded(int64_t data_length, int64_t encoded_length) override;
+  void OnTransferSizeUpdated(int32_t transfer_size_diff) override;
   void OnStartLoadingResponseBody(
       mojo::ScopedDataPipeConsumerHandle body) override;
   void OnComplete(const ResourceRequestCompletionStatus& status) override;
@@ -51,6 +52,7 @@
   int64_t encoded_download_data_length() const {
     return encoded_download_data_length_;
   }
+  int64_t body_transfer_size() const { return body_transfer_size_; }
 
   void ClearHasReceivedRedirect();
   // Creates an AssociatedPtrInfo, binds it to |*this| and returns it. The
@@ -85,6 +87,7 @@
   mojom::URLLoaderFactoryPtr url_loader_factory_;
   int64_t download_data_length_ = 0;
   int64_t encoded_download_data_length_ = 0;
+  int64_t body_transfer_size_ = 0;
 
   DISALLOW_COPY_AND_ASSIGN(TestURLLoaderClient);
 };
diff --git a/content/browser/loader/url_loader_factory_impl_unittest.cc b/content/browser/loader/url_loader_factory_impl_unittest.cc
index 8eefe67..104e39c 100644
--- a/content/browser/loader/url_loader_factory_impl_unittest.cc
+++ b/content/browser/loader/url_loader_factory_impl_unittest.cc
@@ -20,6 +20,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
+#include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/loader/mojo_async_resource_handler.h"
 #include "content/browser/loader/navigation_resource_throttle.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
@@ -89,6 +90,12 @@
             nullptr,
             base::Bind(&URLLoaderFactoryImplTest::GetContexts,
                        base::Unretained(this)))) {
+    // Some tests specify request.report_raw_headers, but the RDH checks the
+    // CanReadRawCookies permission before enabling it.
+    ChildProcessSecurityPolicyImpl::GetInstance()->Add(kChildId);
+    ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadRawCookies(
+        kChildId);
+
     resource_message_filter_->InitializeForTest();
     MojoAsyncResourceHandler::SetAllocationSizeForTesting(GetParam());
     rdh_.SetLoaderDelegate(&loader_deleate_);
@@ -103,6 +110,7 @@
   }
 
   ~URLLoaderFactoryImplTest() override {
+    ChildProcessSecurityPolicyImpl::GetInstance()->Remove(kChildId);
     rdh_.SetDelegate(nullptr);
     net::URLRequestFilter::GetInstance()->ClearHandlers();
 
@@ -204,10 +212,15 @@
   base::ReadFileToString(
       root.Append(base::FilePath(FILE_PATH_LITERAL("hello.html"))), &expected);
   EXPECT_EQ(expected, contents);
-  EXPECT_EQ(static_cast<int64_t>(expected.size()),
+  EXPECT_EQ(static_cast<int64_t>(expected.size()) +
+                client.response_head().encoded_data_length,
             client.completion_status().encoded_data_length);
   EXPECT_EQ(static_cast<int64_t>(expected.size()),
             client.completion_status().encoded_body_length);
+  // OnTransferSizeUpdated is not dispatched as report_raw_headers is not set.
+  EXPECT_EQ(0, client.body_transfer_size());
+  EXPECT_GT(client.response_head().encoded_data_length, 0);
+  EXPECT_GT(client.completion_status().encoded_data_length, 0);
 }
 
 TEST_P(URLLoaderFactoryImplTest, GetFailedResponse) {
@@ -382,7 +395,8 @@
   base::ReadFileToString(
       root.Append(base::FilePath(FILE_PATH_LITERAL("hello.html"))), &expected);
   EXPECT_EQ(expected, contents);
-  EXPECT_EQ(static_cast<int64_t>(expected.size()),
+  EXPECT_EQ(static_cast<int64_t>(expected.size()) +
+                client.response_head().encoded_data_length,
             client.completion_status().encoded_data_length);
   EXPECT_EQ(static_cast<int64_t>(expected.size()),
             client.completion_status().encoded_body_length);
@@ -447,6 +461,67 @@
   EXPECT_EQ(net::ERR_ABORTED, client.completion_status().error_code);
 }
 
+TEST_P(URLLoaderFactoryImplTest, OnTransferSizeUpdated) {
+  constexpr int32_t kRoutingId = 81;
+  constexpr int32_t kRequestId = 28;
+  NavigationResourceThrottle::set_ui_checks_always_succeed_for_testing(true);
+  mojom::URLLoaderAssociatedPtr loader;
+  base::FilePath root;
+  PathService::Get(DIR_TEST_DATA, &root);
+  net::URLRequestMockHTTPJob::AddUrlHandlers(root,
+                                             BrowserThread::GetBlockingPool());
+  ResourceRequest request;
+  TestURLLoaderClient client;
+  // Assume the file contents is small enough to be stored in the data pipe.
+  request.url = net::URLRequestMockHTTPJob::GetMockUrl("gzip-content.svgz");
+  request.method = "GET";
+  // |resource_type| can't be a frame type. It is because when PlzNavigate is
+  // enabled, the url scheme of frame type requests from the renderer process
+  // must be blob scheme.
+  request.resource_type = RESOURCE_TYPE_XHR;
+  // Need to set |request_initiator| for non main frame type request.
+  request.request_initiator = url::Origin();
+  request.report_raw_headers = true;
+  factory_->CreateLoaderAndStart(
+      mojo::GetProxy(&loader, factory_.associated_group()), kRoutingId,
+      kRequestId, request,
+      client.CreateRemoteAssociatedPtrInfo(factory_.associated_group()));
+
+  client.RunUntilComplete();
+
+  std::string contents;
+  while (true) {
+    char buffer[16];
+    uint32_t read_size = sizeof(buffer);
+    MojoResult r = mojo::ReadDataRaw(client.response_body(), buffer, &read_size,
+                                     MOJO_READ_DATA_FLAG_NONE);
+    if (r == MOJO_RESULT_FAILED_PRECONDITION)
+      break;
+    if (r == MOJO_RESULT_SHOULD_WAIT)
+      continue;
+    ASSERT_EQ(MOJO_RESULT_OK, r);
+    contents.append(buffer, read_size);
+  }
+
+  std::string expected_encoded_body;
+  base::ReadFileToString(
+      root.Append(base::FilePath(FILE_PATH_LITERAL("gzip-content.svgz"))),
+      &expected_encoded_body);
+
+  EXPECT_GT(client.response_head().encoded_data_length, 0);
+  EXPECT_GT(client.completion_status().encoded_data_length, 0);
+  EXPECT_EQ(static_cast<int64_t>(expected_encoded_body.size()),
+            client.body_transfer_size());
+  EXPECT_EQ(200, client.response_head().headers->response_code());
+  EXPECT_EQ(
+      client.response_head().encoded_data_length + client.body_transfer_size(),
+      client.completion_status().encoded_data_length);
+  EXPECT_NE(client.body_transfer_size(), static_cast<int64_t>(contents.size()));
+  EXPECT_EQ(client.body_transfer_size(),
+            client.completion_status().encoded_body_length);
+  EXPECT_EQ(contents, "Hello World!\n");
+}
+
 // Removing the loader in the remote side will cancel the request.
 TEST_P(URLLoaderFactoryImplTest, CancelFromRenderer) {
   constexpr int32_t kRoutingId = 81;
diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.cc b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
index 553e01b..d8d1ad6d 100644
--- a/content/browser/service_worker/service_worker_fetch_dispatcher.cc
+++ b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
@@ -81,6 +81,9 @@
   void OnDataDownloaded(int64_t data_length, int64_t encoded_length) override {
     client_->OnDataDownloaded(data_length, encoded_length);
   }
+  void OnTransferSizeUpdated(int32_t transfer_size_diff) override {
+    client_->OnTransferSizeUpdated(transfer_size_diff);
+  }
   void OnReceiveResponse(
       const ResourceResponseHead& head,
       mojom::DownloadedTempFilePtr downloaded_file) override {
diff --git a/content/child/resource_dispatcher.cc b/content/child/resource_dispatcher.cc
index bdabb9f8..fcd3270 100644
--- a/content/child/resource_dispatcher.cc
+++ b/content/child/resource_dispatcher.cc
@@ -114,6 +114,11 @@
         ResourceMsg_DataDownloaded(request_id_, data_len, encoded_data_len));
   }
 
+  void OnTransferSizeUpdated(int32_t transfer_size_diff) override {
+    resource_dispatcher_->OnTransferSizeUpdated(request_id_,
+                                                transfer_size_diff);
+  }
+
   void OnStartLoadingResponseBody(
       mojo::ScopedDataPipeConsumerHandle body) override {
     DCHECK(!body_consumer_);
@@ -549,12 +554,11 @@
 }
 
 void ResourceDispatcher::SetDefersLoading(int request_id, bool value) {
-  PendingRequestMap::iterator it = pending_requests_.find(request_id);
-  if (it == pending_requests_.end()) {
+  PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
+  if (!request_info) {
     DLOG(ERROR) << "unknown request";
     return;
   }
-  PendingRequestInfo* request_info = it->second.get();
   if (value) {
     request_info->is_deferred = value;
   } else if (request_info->is_deferred) {
@@ -576,6 +580,18 @@
       request_id, new_priority, intra_priority_value));
 }
 
+void ResourceDispatcher::OnTransferSizeUpdated(int request_id,
+                                               int32_t transfer_size_diff) {
+  DCHECK_GT(transfer_size_diff, 0);
+  PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
+  if (!request_info)
+    return;
+
+  // TODO(yhirano): Consider using int64_t in
+  // RequestPeer::OnTransferSizeUpdated.
+  request_info->peer->OnTransferSizeUpdated(transfer_size_diff);
+}
+
 ResourceDispatcher::PendingRequestInfo::PendingRequestInfo(
     std::unique_ptr<RequestPeer> peer,
     ResourceType resource_type,
diff --git a/content/child/resource_dispatcher.h b/content/child/resource_dispatcher.h
index 2f918ee..48a7f57 100644
--- a/content/child/resource_dispatcher.h
+++ b/content/child/resource_dispatcher.h
@@ -149,6 +149,8 @@
     return weak_factory_.GetWeakPtr();
   }
 
+  void OnTransferSizeUpdated(int request_id, int32_t transfer_size_diff);
+
  private:
   friend class URLResponseBodyConsumer;
   friend class ResourceDispatcherTest;
diff --git a/content/common/url_loader.mojom b/content/common/url_loader.mojom
index f77988b..c0e63c87 100644
--- a/content/common/url_loader.mojom
+++ b/content/common/url_loader.mojom
@@ -44,8 +44,21 @@
   // Called when some data from a resource request has been downloaded to the
   // file. This is only called in the 'download_to_file' case and replaces
   // OnStartLoadingResponseBody in the call sequence in that case.
+  // TODO(yhirano): Remove |encoded_length| and use OnTransferSizeUpdated
+  // instead.
   OnDataDownloaded(int64 data_length, int64 encoded_length);
 
+  // Called when the transfer size is updated. This is only called if
+  // |report_raw_headers| is set and |download_to_file| is unset in the request.
+  // The transfer size is the length of the response (including both headers
+  // and the body) over the network. |transfer_size_diff| is the difference from
+  // the value previously reported one (including the one in OnReceiveResponse
+  // and OnReceiveRedirect). It must be positive.
+  // TODO(yhirano): Dispatch this notification even when |download_to_file| is
+  // set.
+  // TODO(yhirano): Consider using an unsigned type.
+  OnTransferSizeUpdated(int32 transfer_size_diff);
+
   // Called when the loader starts loading response body.
   OnStartLoadingResponseBody(handle<data_pipe_consumer> body);
 
diff --git a/content/public/app/mojo/content_renderer_manifest.json b/content/public/app/mojo/content_renderer_manifest.json
index 2c0b321..eacc854 100644
--- a/content/public/app/mojo/content_renderer_manifest.json
+++ b/content/public/app/mojo/content_renderer_manifest.json
@@ -29,6 +29,7 @@
       "provides": {
         "browser": [
           "blink::mojom::AppBannerController",
+          "blink::mojom::EngagementClient",
           "blink::mojom::InstallationService",
           "content::mojom::ImageDownloader",
           "mojom::MediaDevicesListener"
diff --git a/content/public/common/browser_side_navigation_policy.cc b/content/public/common/browser_side_navigation_policy.cc
index a94eff1..aaf6f60 100644
--- a/content/public/common/browser_side_navigation_policy.cc
+++ b/content/public/common/browser_side_navigation_policy.cc
@@ -10,8 +10,7 @@
 namespace content {
 
 bool IsBrowserSideNavigationEnabled() {
-  return base::CommandLine::ForCurrentProcess()->HasSwitch(
-      switches::kEnableBrowserSideNavigation);
+  return true;
 }
 
 }  // namespace content
diff --git a/content/renderer/mus/render_widget_mus_connection.cc b/content/renderer/mus/render_widget_mus_connection.cc
index 80464706..15f72077 100644
--- a/content/renderer/mus/render_widget_mus_connection.cc
+++ b/content/renderer/mus/render_widget_mus_connection.cc
@@ -11,7 +11,6 @@
 #include "content/renderer/mus/compositor_mus_connection.h"
 #include "content/renderer/render_thread_impl.h"
 #include "content/renderer/render_view_impl.h"
-#include "services/ui/public/cpp/context_provider.h"
 #include "services/ui/public/cpp/window_compositor_frame_sink.h"
 #include "services/ui/public/interfaces/window_tree.mojom.h"
 
@@ -40,16 +39,15 @@
 
 std::unique_ptr<cc::CompositorFrameSink>
 RenderWidgetMusConnection::CreateCompositorFrameSink(
-    scoped_refptr<gpu::GpuChannelHost> gpu_channel_host,
+    scoped_refptr<cc::ContextProvider> context_provider,
     gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!window_compositor_frame_sink_binding_);
 
   std::unique_ptr<cc::CompositorFrameSink> compositor_frame_sink(
       ui::WindowCompositorFrameSink::Create(
-          make_scoped_refptr(
-              new ui::ContextProvider(std::move(gpu_channel_host))),
-          gpu_memory_buffer_manager, &window_compositor_frame_sink_binding_));
+          std::move(context_provider), gpu_memory_buffer_manager,
+          &window_compositor_frame_sink_binding_));
   if (compositor_mus_connection_) {
     compositor_mus_connection_->AttachCompositorFrameSinkOnMainThread(
         std::move(window_compositor_frame_sink_binding_));
diff --git a/content/renderer/mus/render_widget_mus_connection.h b/content/renderer/mus/render_widget_mus_connection.h
index 88c30b9c..fcdd2a2 100644
--- a/content/renderer/mus/render_widget_mus_connection.h
+++ b/content/renderer/mus/render_widget_mus_connection.h
@@ -8,12 +8,12 @@
 #include "base/macros.h"
 #include "base/threading/thread_checker.h"
 #include "cc/output/compositor_frame_sink.h"
+#include "cc/output/context_provider.h"
 #include "content/common/content_export.h"
 #include "content/renderer/input/render_widget_input_handler_delegate.h"
 #include "content/renderer/mus/compositor_mus_connection.h"
 
 namespace gpu {
-class GpuChannelHost;
 class GpuMemoryBufferManager;
 }
 
@@ -28,7 +28,7 @@
 
   // Create a cc output surface.
   std::unique_ptr<cc::CompositorFrameSink> CreateCompositorFrameSink(
-      scoped_refptr<gpu::GpuChannelHost> gpu_channel_host,
+      scoped_refptr<cc::ContextProvider> context_provider,
       gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager);
 
   static RenderWidgetMusConnection* Get(int routing_id);
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 16932e64..9f1f38d2 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -1122,6 +1122,7 @@
       focused_pepper_plugin_(nullptr),
       pepper_last_mouse_event_target_(nullptr),
 #endif
+      engagement_binding_(this),
       frame_binding_(this),
       host_zoom_binding_(this),
       has_accessed_initial_document_(false),
@@ -1640,8 +1641,13 @@
                    std::unique_ptr<StreamOverrideParameters>());
 }
 
-void RenderFrameImpl::Bind(mojom::FrameRequest request,
-                           mojom::FrameHostPtr host) {
+void RenderFrameImpl::BindEngagement(
+    blink::mojom::EngagementClientAssociatedRequest request) {
+  engagement_binding_.Bind(std::move(request));
+}
+
+void RenderFrameImpl::BindFrame(mojom::FrameRequest request,
+                                mojom::FrameHostPtr host) {
   frame_binding_.Bind(std::move(request));
   frame_host_ = std::move(host);
   frame_host_->GetInterfaceProvider(
@@ -2647,6 +2653,20 @@
   return is_pasting_;
 }
 
+// blink::mojom::EngagementClient implementation -------------------------------
+
+void RenderFrameImpl::SetEngagementLevel(const url::Origin& origin,
+                                         blink::mojom::EngagementLevel level) {
+  // Set the engagement level on |frame_| if its origin matches the one we have
+  // been provided with.
+  if (frame_ && url::Origin(frame_->getSecurityOrigin()) == origin) {
+    frame_->setEngagementLevel(level);
+    return;
+  }
+
+  engagement_levels_[origin] = level;
+}
+
 // mojom::Frame implementation -------------------------------------------------
 
 void RenderFrameImpl::GetInterfaceProvider(
@@ -4758,6 +4778,14 @@
   InternalDocumentStateData* internal_data =
       InternalDocumentStateData::FromDocumentState(document_state);
 
+  // Set the correct engagement level on the frame.
+  EngagementLevels::iterator engagement_level =
+      engagement_levels_.find(url::Origin(frame_->getSecurityOrigin()));
+
+  if (engagement_level != engagement_levels_.end())
+    frame_->setEngagementLevel(engagement_level->second);
+  engagement_levels_.clear();
+
   FrameHostMsg_DidCommitProvisionalLoad_Params params;
   params.http_status_code = response.httpStatusCode();
   params.url_is_unreachable = ds->hasUnreachableURL();
@@ -6511,6 +6539,9 @@
 #endif  // ENABLE_PLUGINS
 
 void RenderFrameImpl::RegisterMojoInterfaces() {
+  GetAssociatedInterfaceRegistry()->AddInterface(
+      base::Bind(&RenderFrameImpl::BindEngagement, weak_factory_.GetWeakPtr()));
+
   if (!frame_->parent()) {
     // Only main frame have ImageDownloader service.
     GetInterfaceRegistry()->AddInterface(base::Bind(
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index bcde1e4e..e1e5f6f4 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -56,6 +56,7 @@
 #include "third_party/WebKit/public/platform/WebLoadingBehaviorFlag.h"
 #include "third_party/WebKit/public/platform/WebMediaPlayer.h"
 #include "third_party/WebKit/public/platform/WebPageVisibilityState.h"
+#include "third_party/WebKit/public/platform/site_engagement.mojom.h"
 #include "third_party/WebKit/public/web/WebAXObject.h"
 #include "third_party/WebKit/public/web/WebDataSource.h"
 #include "third_party/WebKit/public/web/WebFrameClient.h"
@@ -66,6 +67,7 @@
 #include "third_party/WebKit/public/web/WebScriptExecutionCallback.h"
 #include "ui/gfx/range/range.h"
 #include "url/gurl.h"
+#include "url/origin.h"
 
 #if BUILDFLAG(ENABLE_PLUGINS)
 #include "content/renderer/pepper/plugin_power_saver_helper.h"
@@ -167,6 +169,7 @@
 
 class CONTENT_EXPORT RenderFrameImpl
     : public RenderFrame,
+      NON_EXPORTED_BASE(blink::mojom::EngagementClient),
       NON_EXPORTED_BASE(mojom::Frame),
       NON_EXPORTED_BASE(mojom::HostZoom),
       NON_EXPORTED_BASE(public blink::WebFrameClient),
@@ -442,6 +445,10 @@
   blink::WebPageVisibilityState GetVisibilityState() const override;
   bool IsBrowserSideNavigationPending() override;
 
+  // blink::mojom::EngagementClient implementation:
+  void SetEngagementLevel(const url::Origin& origin,
+                          blink::mojom::EngagementLevel level) override;
+
   // mojom::Frame implementation:
   void GetInterfaceProvider(
       service_manager::mojom::InterfaceProviderRequest request) override;
@@ -650,8 +657,11 @@
       blink::WebFrameSerializerClient::FrameSerializationStatus status)
       override;
 
+  // Binds to the site engagement service in the browser.
+  void BindEngagement(blink::mojom::EngagementClientAssociatedRequest request);
+
   // Binds to the FrameHost in the browser.
-  void Bind(mojom::FrameRequest frame, mojom::FrameHostPtr frame_host);
+  void BindFrame(mojom::FrameRequest request, mojom::FrameHostPtr frame_host);
 
   ManifestManager* manifest_manager();
 
@@ -749,6 +759,7 @@
   };
 
   typedef std::map<GURL, double> HostZoomLevels;
+  typedef std::map<url::Origin, blink::mojom::EngagementLevel> EngagementLevels;
 
   // Creates a new RenderFrame. |render_view| is the RenderView object that this
   // frame belongs to.
@@ -1326,7 +1337,9 @@
 #endif
 
   HostZoomLevels host_zoom_levels_;
+  EngagementLevels engagement_levels_;
 
+  mojo::AssociatedBinding<blink::mojom::EngagementClient> engagement_binding_;
   mojo::Binding<mojom::Frame> frame_binding_;
   mojo::AssociatedBinding<mojom::HostZoom> host_zoom_binding_;
   mojom::FrameHostPtr frame_host_;
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 8620ba2..4157af71 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -352,7 +352,7 @@
       return;
     }
 
-    frame->Bind(std::move(frame_request), std::move(frame_host));
+    frame->BindFrame(std::move(frame_request), std::move(frame_host));
   }
 
  private:
@@ -1129,7 +1129,7 @@
     return;
 
   scoped_refptr<PendingFrameCreate> create(it->second);
-  frame->Bind(it->second->TakeFrameRequest(), it->second->TakeFrameHost());
+  frame->BindFrame(it->second->TakeFrameRequest(), it->second->TakeFrameHost());
   pending_frame_creates_.erase(it);
 }
 
@@ -1779,10 +1779,9 @@
   if (!RendererIsHidden())
     return;
   if (base::FeatureList::IsEnabled(features::kPurgeAndSuspend)) {
-    // TODO(tasak): After enabling MemoryCoordinator, remove this Notify
-    // and follow MemoryCoordinator's request.
-    base::MemoryCoordinatorClientRegistry::GetInstance()->Notify(
-        base::MemoryState::SUSPENDED);
+    // TODO(tasak,bashi): After enabling MemoryCoordinator, stop calling
+    // SuspendRenderer() here.
+    SuspendRenderer();
   }
   // Since purging is not a synchronous task (e.g. v8 GC, oilpan GC, ...),
   // we need to wait until the task is finished. So wait 15 seconds and
@@ -1890,10 +1889,9 @@
   if (!RendererIsHidden())
     return;
   if (base::FeatureList::IsEnabled(features::kPurgeAndSuspend)) {
-    // TODO(tasak): after enabling MemoryCoordinator, remove this Notify
-    // and follow MemoryCoordinator's request.
-    base::MemoryCoordinatorClientRegistry::GetInstance()->Notify(
-        base::MemoryState::NORMAL);
+    // TODO(tasak,bashi): After enabling MemoryCoordinator, stop calling
+    // ResumeRenderer() here.
+    ResumeRenderer();
   }
 }
 
@@ -1933,10 +1931,9 @@
       command_line.HasSwitch(switches::kUseMusInRenderer)) {
     RenderWidgetMusConnection* connection =
         RenderWidgetMusConnection::GetOrCreate(routing_id);
-    scoped_refptr<gpu::GpuChannelHost> gpu_channel_host =
-        EstablishGpuChannelSync();
-    return connection->CreateCompositorFrameSink(std::move(gpu_channel_host),
-                                                 GetGpuMemoryBufferManager());
+    return connection->CreateCompositorFrameSink(
+        gpu_->CreateContextProvider(EstablishGpuChannelSync()),
+        GetGpuMemoryBufferManager());
   }
 #endif
 
@@ -2261,10 +2258,10 @@
   }
   switch (state) {
     case base::MemoryState::NORMAL:
-      ResumeRenderer();
+      // TODO(bashi): When the renderer is suspended, resume it.
       break;
     case base::MemoryState::THROTTLED:
-      ResumeRenderer();
+      // TODO(bashi): When the renderer is suspended, resume it.
       // TODO(bashi): Figure out what kind of strategy is suitable on
       // THROTTLED state. crbug.com/674815
 #if defined(OS_ANDROID)
@@ -2276,7 +2273,10 @@
       ReleaseFreeMemory();
       break;
     case base::MemoryState::SUSPENDED:
-      SuspendRenderer();
+      // TODO(bashi): Suspend the renderer.
+      OnTrimMemoryImmediately();
+      ReleaseFreeMemory();
+      ClearMemory();
       break;
     case base::MemoryState::UNKNOWN:
       NOTREACHED();
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index c4b51fb..ce0bce7 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -289,6 +289,10 @@
     NOTREACHED();
   }
 
+  void OnTransferSizeUpdated(int32_t transfer_size_diff) override {
+    NOTREACHED();
+  }
+
   void OnStartLoadingResponseBody(
       mojo::ScopedDataPipeConsumerHandle body) override {
     DCHECK(!body_.is_valid());
diff --git a/content/test/data/gzip-content.svgz b/content/test/data/gzip-content.svgz
new file mode 100644
index 0000000..eb478f7
--- /dev/null
+++ b/content/test/data/gzip-content.svgz
Binary files differ
diff --git a/content/test/data/gzip-content.svgz.mock-http-headers b/content/test/data/gzip-content.svgz.mock-http-headers
new file mode 100644
index 0000000..8837b20
--- /dev/null
+++ b/content/test/data/gzip-content.svgz.mock-http-headers
@@ -0,0 +1,5 @@
+HTTP/1.1 200 OK
+Content-Length: 13
+Content-Type: text/plain; charset=utf-8
+Content-Encoding: gzip
+
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
index 1c24fd6..58f7445 100644
--- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -583,6 +583,8 @@
     # Linux Intel with ANGLE only
     self.Fail('deqp/functional/gles3/framebufferblit/conversion_07.html',
         ['linux', 'intel', 'opengl'], bug=598902)
+    self.Fail('conformance2/rendering/read-draw-when-missing-image.html',
+        ['linux', 'intel', 'opengl'], bug=672719) # WebGL 2.0.1
 
     # Linux AMD only.
     # It looks like AMD shader compiler rejects many valid ES3 semantics.
diff --git a/device/generic_sensor/BUILD.gn b/device/generic_sensor/BUILD.gn
index 110970c..2a0570bf 100644
--- a/device/generic_sensor/BUILD.gn
+++ b/device/generic_sensor/BUILD.gn
@@ -53,7 +53,6 @@
 
   public_deps = [
     "//device/generic_sensor/public/cpp",
-    "//device/generic_sensor/public/interfaces",
   ]
 
   if (is_android) {
diff --git a/device/generic_sensor/linux/sensor_device_manager.h b/device/generic_sensor/linux/sensor_device_manager.h
index 09528e8..3715a79 100644
--- a/device/generic_sensor/linux/sensor_device_manager.h
+++ b/device/generic_sensor/linux/sensor_device_manager.h
@@ -8,6 +8,7 @@
 #include "base/scoped_observer.h"
 
 #include "device/base/device_monitor_linux.h"
+#include "device/generic_sensor/generic_sensor_export.h"
 #include "device/generic_sensor/public/interfaces/sensor.mojom.h"
 
 namespace device {
diff --git a/device/generic_sensor/platform_sensor_provider_linux.h b/device/generic_sensor/platform_sensor_provider_linux.h
index 7e15590..5b6a67d 100644
--- a/device/generic_sensor/platform_sensor_provider_linux.h
+++ b/device/generic_sensor/platform_sensor_provider_linux.h
@@ -7,6 +7,7 @@
 
 #include "device/generic_sensor/platform_sensor_provider.h"
 
+#include "device/generic_sensor/generic_sensor_export.h"
 #include "device/generic_sensor/linux/sensor_device_manager.h"
 
 namespace base {
diff --git a/device/generic_sensor/platform_sensor_reader_linux.h b/device/generic_sensor/platform_sensor_reader_linux.h
index 755ad26..10983e536 100644
--- a/device/generic_sensor/platform_sensor_reader_linux.h
+++ b/device/generic_sensor/platform_sensor_reader_linux.h
@@ -6,7 +6,6 @@
 #define DEVICE_GENERIC_SENSOR_PLATFORM_SENSOR_READER_LINUX_H_
 
 #include "base/memory/ref_counted.h"
-#include "device/generic_sensor/generic_sensor_export.h"
 
 namespace base {
 class SingleThreadTaskRunner;
diff --git a/device/generic_sensor/public/cpp/BUILD.gn b/device/generic_sensor/public/cpp/BUILD.gn
index 0833277..420fffb 100644
--- a/device/generic_sensor/public/cpp/BUILD.gn
+++ b/device/generic_sensor/public/cpp/BUILD.gn
@@ -10,11 +10,14 @@
     "sensor_reading.h",
   ]
 
-  defines = [ "DEVICE_GENERIC_SENSOR_IMPLEMENTATION" ]
+  defines = [ "DEVICE_GENERIC_SENSOR_PUBLIC_IMPLEMENTATION" ]
+
+  public_deps = [
+    "//device/generic_sensor/public/interfaces",
+  ]
 
   deps = [
     "//base",
     "//device/base/synchronization",
-    "//device/generic_sensor/public/interfaces",
   ]
 }
diff --git a/device/generic_sensor/public/cpp/generic_sensor_public_export.h b/device/generic_sensor/public/cpp/generic_sensor_public_export.h
new file mode 100644
index 0000000..fba05003
--- /dev/null
+++ b/device/generic_sensor/public/cpp/generic_sensor_public_export.h
@@ -0,0 +1,30 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_GENERIC_SENSOR_PUBLIC_CPP_GENERIC_SENSOR_PUBLIC_EXPORT_H_
+#define DEVICE_GENERIC_SENSOR_PUBLIC_CPP_GENERIC_SENSOR_PUBLIC_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(DEVICE_GENERIC_SENSOR_PUBLIC_IMPLEMENTATION)
+#define DEVICE_GENERIC_SENSOR_PUBLIC_EXPORT __declspec(dllexport)
+#else
+#define DEVICE_GENERIC_SENSOR_PUBLIC_EXPORT __declspec(dllimport)
+#endif  // defined(DEVICE_GENERIC_SENSOR_PUBLIC_IMPLEMENTATION)
+
+#else  // defined(WIN32)
+#if defined(DEVICE_GENERIC_SENSOR_PUBLIC_IMPLEMENTATION)
+#define DEVICE_GENERIC_SENSOR_PUBLIC_EXPORT \
+  __attribute__((visibility("default")))
+#else
+#define DEVICE_GENERIC_SENSOR_PUBLIC_EXPORT
+#endif
+#endif
+
+#else  // defined(COMPONENT_BUILD)
+#define DEVICE_GENERIC_SENSOR_PUBLIC_EXPORT
+#endif
+
+#endif  // DEVICE_GENERIC_SENSOR_PUBLIC_CPP_GENERIC_SENSOR_PUBLIC_EXPORT_H_
diff --git a/device/generic_sensor/public/cpp/platform_sensor_configuration.h b/device/generic_sensor/public/cpp/platform_sensor_configuration.h
index d18a5d1..e124eaa 100644
--- a/device/generic_sensor/public/cpp/platform_sensor_configuration.h
+++ b/device/generic_sensor/public/cpp/platform_sensor_configuration.h
@@ -6,11 +6,11 @@
 #define DEVICE_GENERIC_SENSOR_PLATFORM_SENSOR_CONFIGURATION_H_
 
 #include "base/logging.h"
-#include "device/generic_sensor/generic_sensor_export.h"
+#include "device/generic_sensor/public/cpp/generic_sensor_public_export.h"
 
 namespace device {
 
-class DEVICE_GENERIC_SENSOR_EXPORT PlatformSensorConfiguration {
+class DEVICE_GENERIC_SENSOR_PUBLIC_EXPORT PlatformSensorConfiguration {
  public:
   PlatformSensorConfiguration();
   explicit PlatformSensorConfiguration(double frequency);
diff --git a/device/generic_sensor/public/cpp/sensor_reading.h b/device/generic_sensor/public/cpp/sensor_reading.h
index 7e8dd64..bd1f7d0 100644
--- a/device/generic_sensor/public/cpp/sensor_reading.h
+++ b/device/generic_sensor/public/cpp/sensor_reading.h
@@ -6,7 +6,7 @@
 #define DEVICE_GENERIC_SENSOR_PUBLIC_CPP_SENSOR_READING_H_
 
 #include "device/base/synchronization/one_writer_seqlock.h"
-#include "device/generic_sensor/generic_sensor_export.h"
+#include "device/generic_sensor/public/cpp/generic_sensor_public_export.h"
 #include "device/generic_sensor/public/interfaces/sensor.mojom.h"
 
 namespace device {
@@ -40,7 +40,7 @@
 };
 
 // This structure represents sensor reading data: timestamp and 3 values.
-struct DEVICE_GENERIC_SENSOR_EXPORT SensorReading {
+struct DEVICE_GENERIC_SENSOR_PUBLIC_EXPORT SensorReading {
   SensorReading();
   ~SensorReading();
   SensorReading(const SensorReading& other);
@@ -50,7 +50,7 @@
 
 // This structure represents sensor reading buffer: sensor reading and seqlock
 // for synchronization.
-struct DEVICE_GENERIC_SENSOR_EXPORT SensorReadingSharedBuffer {
+struct DEVICE_GENERIC_SENSOR_PUBLIC_EXPORT SensorReadingSharedBuffer {
   SensorReadingSharedBuffer();
   ~SensorReadingSharedBuffer();
   SensorReadingField<OneWriterSeqLock> seqlock;
diff --git a/device/generic_sensor/public/interfaces/BUILD.gn b/device/generic_sensor/public/interfaces/BUILD.gn
index f02c8e0c..b9671e5 100644
--- a/device/generic_sensor/public/interfaces/BUILD.gn
+++ b/device/generic_sensor/public/interfaces/BUILD.gn
@@ -5,9 +5,10 @@
 import("//mojo/public/tools/bindings/mojom.gni")
 
 mojom("interfaces") {
-  export_class_attribute = "DEVICE_GENERIC_SENSOR_EXPORT"
-  export_define = "DEVICE_GENERIC_SENSOR_IMPLEMENTATION=1"
-  export_header = "device/generic_sensor/generic_sensor_export.h"
+  export_class_attribute = "DEVICE_GENERIC_SENSOR_PUBLIC_EXPORT"
+  export_define = "DEVICE_GENERIC_SENSOR_PUBLIC_IMPLEMENTATION=1"
+  export_header =
+      "device/generic_sensor/public/cpp/generic_sensor_public_export.h"
   sources = [
     "sensor.mojom",
     "sensor_provider.mojom",
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.cc b/gpu/command_buffer/common/gles2_cmd_utils.cc
index 74ccfec..7d97aeb6 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils.cc
+++ b/gpu/command_buffer/common/gles2_cmd_utils.cc
@@ -483,8 +483,39 @@
 
 namespace {
 
+// Return the number of bytes per element, based on the element type.
+int BytesPerElement(int type) {
+  switch (type) {
+    case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
+      return 8;
+    case GL_FLOAT:
+    case GL_UNSIGNED_INT_24_8_OES:
+    case GL_UNSIGNED_INT:
+    case GL_INT:
+    case GL_UNSIGNED_INT_2_10_10_10_REV:
+    case GL_UNSIGNED_INT_10F_11F_11F_REV:
+    case GL_UNSIGNED_INT_5_9_9_9_REV:
+      return 4;
+    case GL_HALF_FLOAT:
+    case GL_HALF_FLOAT_OES:
+    case GL_UNSIGNED_SHORT:
+    case GL_SHORT:
+    case GL_UNSIGNED_SHORT_5_6_5:
+    case GL_UNSIGNED_SHORT_4_4_4_4:
+    case GL_UNSIGNED_SHORT_5_5_5_1:
+      return 2;
+    case GL_UNSIGNED_BYTE:
+    case GL_BYTE:
+      return 1;
+    default:
+      return 0;
+  }
+}
+
+}  // anonymous namespace
+
 // Return the number of elements per group of a specified format.
-int ElementsPerGroup(int format, int type) {
+int GLES2Util::ElementsPerGroup(int format, int type) {
   switch (type) {
     case GL_UNSIGNED_SHORT_5_6_5:
     case GL_UNSIGNED_SHORT_4_4_4_4:
@@ -529,37 +560,6 @@
   }
 }
 
-// Return the number of bytes per element, based on the element type.
-int BytesPerElement(int type) {
-  switch (type) {
-    case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
-      return 8;
-    case GL_FLOAT:
-    case GL_UNSIGNED_INT_24_8_OES:
-    case GL_UNSIGNED_INT:
-    case GL_INT:
-    case GL_UNSIGNED_INT_2_10_10_10_REV:
-    case GL_UNSIGNED_INT_10F_11F_11F_REV:
-    case GL_UNSIGNED_INT_5_9_9_9_REV:
-      return 4;
-    case GL_HALF_FLOAT:
-    case GL_HALF_FLOAT_OES:
-    case GL_UNSIGNED_SHORT:
-    case GL_SHORT:
-    case GL_UNSIGNED_SHORT_5_6_5:
-    case GL_UNSIGNED_SHORT_4_4_4_4:
-    case GL_UNSIGNED_SHORT_5_5_5_1:
-       return 2;
-    case GL_UNSIGNED_BYTE:
-    case GL_BYTE:
-       return 1;
-    default:
-       return 0;
-  }
-}
-
-}  // anonymous namespace
-
 uint32_t GLES2Util::ComputeImageGroupSize(int format, int type) {
   int bytes_per_element = BytesPerElement(type);
   DCHECK_GE(8, bytes_per_element);
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.h b/gpu/command_buffer/common/gles2_cmd_utils.h
index 1fb75ae..8d0f16ba 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils.h
@@ -140,6 +140,7 @@
   // function is called. If 0 is returned the id is invalid.
   int GLGetNumValuesReturned(int id) const;
 
+  static int ElementsPerGroup(int format, int type);
   // Computes the size of a single group of elements from a format and type pair
   static uint32_t ComputeImageGroupSize(int format, int type);
 
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index 49b6fca..45062e1 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -591,6 +591,7 @@
         extensions.Contains("GL_EXT_sRGB")) ||
        feature_flags_.desktop_srgb_support) &&
        IsWebGL1OrES2Context()) {
+    feature_flags_.ext_srgb = true;
     AddExtensionString("GL_EXT_sRGB");
     validators_.texture_internal_format.AddValue(GL_SRGB_EXT);
     validators_.texture_internal_format.AddValue(GL_SRGB_ALPHA_EXT);
diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h
index 8128c72..278616a4 100644
--- a/gpu/command_buffer/service/feature_info.h
+++ b/gpu/command_buffer/service/feature_info.h
@@ -99,6 +99,7 @@
     bool chromium_bind_generates_resource = false;
     bool angle_webgl_compatibility = false;
     bool ext_srgb_write_control = false;
+    bool ext_srgb = false;
   };
 
   FeatureInfo();
diff --git a/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.cc b/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.cc
index a8d5e43..0d936aa5 100644
--- a/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.cc
+++ b/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.cc
@@ -250,7 +250,7 @@
         copier->DoCopySubTexture(
             decoder, GL_TEXTURE_2D, rgba8_texture_, GL_RGBA8, GL_TEXTURE_2D,
             source_texture, internal_format, 0, 0, 0, 0, width_, height_,
-            width_, height_, width_, height_, false, false, false);
+            width_, height_, width_, height_, false, false, false, DIRECT_DRAW);
       } else {
         ApplyCMAAEffectTexture(source_texture, source_texture, do_copy);
       }
diff --git a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
index e6e3035c..ce09a0dc 100644
--- a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
+++ b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
@@ -10,6 +10,7 @@
 
 #include "gpu/command_buffer/service/gl_utils.h"
 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/texture_manager.h"
 #include "ui/gl/gl_version_info.h"
 
 namespace {
@@ -19,113 +20,311 @@
                                      0.0f, 0.0f, 1.0f, 0.0f,
                                      0.0f, 0.0f, 0.0f, 1.0f};
 
-enum FragmentShaderId {
-  FRAGMENT_SHADER_COPY_TEXTURE_2D,
-  FRAGMENT_SHADER_COPY_TEXTURE_RECTANGLE_ARB,
-  FRAGMENT_SHADER_COPY_TEXTURE_EXTERNAL_OES,
-  FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_2D,
-  FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_RECTANGLE_ARB,
-  FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_EXTERNAL_OES,
-  FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_2D,
-  FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_RECTANGLE_ARB,
-  FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_EXTERNAL_OES,
-  NUM_FRAGMENT_SHADERS,
+enum {
+  SAMPLER_2D,
+  SAMPLER_RECTANGLE_ARB,
+  SAMPLER_EXTERNAL_OES,
+  NUM_SAMPLERS
 };
 
+enum {
+  S_FORMAT_ALPHA,
+  S_FORMAT_LUMINANCE,
+  S_FORMAT_LUMINANCE_ALPHA,
+  S_FORMAT_RED,
+  S_FORMAT_RGB,
+  S_FORMAT_RGBA,
+  S_FORMAT_RGB8,
+  S_FORMAT_RGBA8,
+  S_FORMAT_BGRA_EXT,
+  S_FORMAT_BGRA8_EXT,
+  S_FORMAT_RGB_YCBCR_420V_CHROMIUM,
+  S_FORMAT_RGB_YCBCR_422_CHROMIUM,
+  S_FORMAT_COMPRESSED,
+  NUM_S_FORMAT
+};
+
+enum {
+  D_FORMAT_RGB,
+  D_FORMAT_RGBA,
+  D_FORMAT_RGB8,
+  D_FORMAT_RGBA8,
+  D_FORMAT_BGRA_EXT,
+  D_FORMAT_BGRA8_EXT,
+  D_FORMAT_SRGB_EXT,
+  D_FORMAT_SRGB_ALPHA_EXT,
+  D_FORMAT_R8,
+  D_FORMAT_R8UI,
+  D_FORMAT_RG8,
+  D_FORMAT_RG8UI,
+  D_FORMAT_SRGB8,
+  D_FORMAT_RGB565,
+  D_FORMAT_RGB8UI,
+  D_FORMAT_SRGB8_ALPHA8,
+  D_FORMAT_RGB5_A1,
+  D_FORMAT_RGBA4,
+  D_FORMAT_RGBA8UI,
+  D_FORMAT_RGB9_E5,
+  D_FORMAT_R16F,
+  D_FORMAT_R32F,
+  D_FORMAT_RG16F,
+  D_FORMAT_RG32F,
+  D_FORMAT_RGB16F,
+  D_FORMAT_RGB32F,
+  D_FORMAT_RGBA16F,
+  D_FORMAT_RGBA32F,
+  D_FORMAT_R11F_G11F_B10F,
+  NUM_D_FORMAT
+};
+
+const unsigned kNumVertexShaders = NUM_SAMPLERS;
+const unsigned kNumFragmentShaders =
+    4 * NUM_SAMPLERS * NUM_S_FORMAT * NUM_D_FORMAT;
+
+typedef unsigned ShaderId;
+
+ShaderId GetVertexShaderId(GLenum target) {
+  ShaderId id = 0;
+  switch (target) {
+    case GL_TEXTURE_2D:
+      id = SAMPLER_2D;
+      break;
+    case GL_TEXTURE_RECTANGLE_ARB:
+      id = SAMPLER_RECTANGLE_ARB;
+      break;
+    case GL_TEXTURE_EXTERNAL_OES:
+      id = SAMPLER_EXTERNAL_OES;
+      break;
+    default:
+      NOTREACHED();
+      break;
+  }
+  return id;
+}
+
 // Returns the correct fragment shader id to evaluate the copy operation for
 // the premultiply alpha pixel store settings and target.
-FragmentShaderId GetFragmentShaderId(bool premultiply_alpha,
+ShaderId GetFragmentShaderId(bool premultiply_alpha,
                                      bool unpremultiply_alpha,
-                                     GLenum target) {
-  enum {
-    SAMPLER_2D,
-    SAMPLER_RECTANGLE_ARB,
-    SAMPLER_EXTERNAL_OES,
-    NUM_SAMPLERS
-  };
+                                     GLenum target,
+                                     GLenum source_format,
+                                     GLenum dest_format) {
+  unsigned alphaIndex = 0;
+  unsigned targetIndex = 0;
+  unsigned sourceFormatIndex = 0;
+  unsigned destFormatIndex = 0;
 
-  // bit 0: premultiply alpha
-  // bit 1: unpremultiply alpha
-  static FragmentShaderId shader_ids[][NUM_SAMPLERS] = {
-      {
-       FRAGMENT_SHADER_COPY_TEXTURE_2D,
-       FRAGMENT_SHADER_COPY_TEXTURE_RECTANGLE_ARB,
-       FRAGMENT_SHADER_COPY_TEXTURE_EXTERNAL_OES,
-      },
-      {
-       FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_2D,
-       FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_RECTANGLE_ARB,
-       FRAGMENT_SHADER_COPY_TEXTURE_PREMULTIPLY_ALPHA_EXTERNAL_OES,
-      },
-      {
-       FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_2D,
-       FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_RECTANGLE_ARB,
-       FRAGMENT_SHADER_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_EXTERNAL_OES,
-      },
-      {
-       FRAGMENT_SHADER_COPY_TEXTURE_2D,
-       FRAGMENT_SHADER_COPY_TEXTURE_RECTANGLE_ARB,
-       FRAGMENT_SHADER_COPY_TEXTURE_EXTERNAL_OES,
-      }};
-
-  unsigned index = (premultiply_alpha   ? (1 << 0) : 0) |
-                   (unpremultiply_alpha ? (1 << 1) : 0);
+  alphaIndex = (premultiply_alpha   ? (1 << 0) : 0) |
+               (unpremultiply_alpha ? (1 << 1) : 0);
 
   switch (target) {
     case GL_TEXTURE_2D:
-      return shader_ids[index][SAMPLER_2D];
+      targetIndex = SAMPLER_2D;
+      break;
     case GL_TEXTURE_RECTANGLE_ARB:
-      return shader_ids[index][SAMPLER_RECTANGLE_ARB];
+      targetIndex = SAMPLER_RECTANGLE_ARB;
+      break;
     case GL_TEXTURE_EXTERNAL_OES:
-      return shader_ids[index][SAMPLER_EXTERNAL_OES];
+      targetIndex = SAMPLER_EXTERNAL_OES;
+      break;
     default:
+      NOTREACHED();
       break;
   }
 
-  NOTREACHED();
-  return shader_ids[0][SAMPLER_2D];
+  switch (source_format) {
+    case GL_ALPHA:
+      sourceFormatIndex = S_FORMAT_ALPHA;
+      break;
+    case GL_LUMINANCE:
+      sourceFormatIndex = S_FORMAT_LUMINANCE;
+      break;
+    case GL_LUMINANCE_ALPHA:
+      sourceFormatIndex = S_FORMAT_LUMINANCE_ALPHA;
+      break;
+    case GL_RED:
+      sourceFormatIndex = S_FORMAT_RED;
+      break;
+    case GL_RGB:
+      sourceFormatIndex = S_FORMAT_RGB;
+      break;
+    case GL_RGBA:
+      sourceFormatIndex = S_FORMAT_RGBA;
+      break;
+    case GL_RGB8:
+      sourceFormatIndex = S_FORMAT_RGB8;
+      break;
+    case GL_RGBA8:
+      sourceFormatIndex = S_FORMAT_RGBA8;
+      break;
+    case GL_BGRA_EXT:
+      sourceFormatIndex = S_FORMAT_BGRA_EXT;
+      break;
+    case GL_BGRA8_EXT:
+      sourceFormatIndex = S_FORMAT_BGRA8_EXT;
+      break;
+    case GL_RGB_YCBCR_420V_CHROMIUM:
+      sourceFormatIndex = S_FORMAT_RGB_YCBCR_420V_CHROMIUM;
+      break;
+    case GL_RGB_YCBCR_422_CHROMIUM:
+      sourceFormatIndex = S_FORMAT_RGB_YCBCR_422_CHROMIUM;
+      break;
+    case GL_ATC_RGB_AMD:
+    case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD:
+    case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+    case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+    case GL_ETC1_RGB8_OES:
+      sourceFormatIndex = S_FORMAT_COMPRESSED;
+      break;
+    default:
+      NOTREACHED();
+      break;
+  }
+
+  switch (dest_format) {
+    case GL_RGB:
+      destFormatIndex = D_FORMAT_RGB;
+      break;
+    case GL_RGBA:
+      destFormatIndex = D_FORMAT_RGBA;
+      break;
+    case GL_RGB8:
+      destFormatIndex = D_FORMAT_RGB8;
+      break;
+    case GL_RGBA8:
+      destFormatIndex = D_FORMAT_RGBA8;
+      break;
+    case GL_BGRA_EXT:
+      destFormatIndex = D_FORMAT_BGRA_EXT;
+      break;
+    case GL_BGRA8_EXT:
+      destFormatIndex = D_FORMAT_BGRA8_EXT;
+      break;
+    case GL_SRGB_EXT:
+      destFormatIndex = D_FORMAT_SRGB_EXT;
+      break;
+    case GL_SRGB_ALPHA_EXT:
+      destFormatIndex = D_FORMAT_SRGB_ALPHA_EXT;
+      break;
+    case GL_R8:
+      destFormatIndex = D_FORMAT_R8;
+      break;
+    case GL_R8UI:
+      destFormatIndex = D_FORMAT_R8UI;
+      break;
+    case GL_RG8:
+      destFormatIndex = D_FORMAT_RG8;
+      break;
+    case GL_RG8UI:
+      destFormatIndex = D_FORMAT_RG8UI;
+      break;
+    case GL_SRGB8:
+      destFormatIndex = D_FORMAT_SRGB8;
+      break;
+    case GL_RGB565:
+      destFormatIndex = D_FORMAT_RGB565;
+      break;
+    case GL_RGB8UI:
+      destFormatIndex = D_FORMAT_RGB8UI;
+      break;
+    case GL_SRGB8_ALPHA8:
+      destFormatIndex = D_FORMAT_SRGB8_ALPHA8;
+      break;
+    case GL_RGB5_A1:
+      destFormatIndex = D_FORMAT_RGB5_A1;
+      break;
+    case GL_RGBA4:
+      destFormatIndex = D_FORMAT_RGBA4;
+      break;
+    case GL_RGBA8UI:
+      destFormatIndex = D_FORMAT_RGBA8UI;
+      break;
+    case GL_RGB9_E5:
+      destFormatIndex = D_FORMAT_RGB9_E5;
+      break;
+    case GL_R16F:
+      destFormatIndex = D_FORMAT_R16F;
+      break;
+    case GL_R32F:
+      destFormatIndex = D_FORMAT_R32F;
+      break;
+    case GL_RG16F:
+      destFormatIndex = D_FORMAT_RG16F;
+      break;
+    case GL_RG32F:
+      destFormatIndex = D_FORMAT_RG32F;
+      break;
+    case GL_RGB16F:
+      destFormatIndex = D_FORMAT_RGB16F;
+      break;
+    case GL_RGB32F:
+      destFormatIndex = D_FORMAT_RGB32F;
+      break;
+    case GL_RGBA16F:
+      destFormatIndex = D_FORMAT_RGBA16F;
+      break;
+    case GL_RGBA32F:
+      destFormatIndex = D_FORMAT_RGBA32F;
+      break;
+    case GL_R11F_G11F_B10F:
+      destFormatIndex = D_FORMAT_R11F_G11F_B10F;
+      break;
+    default:
+      NOTREACHED();
+      break;
+  }
+
+  return alphaIndex + targetIndex * 4 + sourceFormatIndex * 4 * NUM_SAMPLERS +
+         destFormatIndex * 4 * NUM_SAMPLERS * NUM_S_FORMAT;
 }
 
-const char* kShaderPrecisionPreamble = "\
-    #ifdef GL_ES\n\
-    precision mediump float;\n\
-    #define TexCoordPrecision mediump\n\
-    #else\n\
-    #define TexCoordPrecision\n\
-    #endif\n";
+const char* kShaderPrecisionPreamble =
+    "#ifdef GL_ES\n"
+    "precision mediump float;\n"
+    "#define TexCoordPrecision mediump\n"
+    "#else\n"
+    "#define TexCoordPrecision\n"
+    "#endif\n";
 
-std::string GetVertexShaderSource(const gl::GLVersionInfo& gl_version_info) {
+std::string GetVertexShaderSource(const gl::GLVersionInfo& gl_version_info,
+                                  GLenum target) {
   std::string source;
 
-  // Preamble for core and compatibility mode.
-  if (gl_version_info.is_desktop_core_profile) {
-    source += std::string("\
-        #version 150\n\
-        #define ATTRIBUTE in\n\
-        #define VARYING out\n");
+  if (gl_version_info.is_es || gl_version_info.IsLowerThanGL(3, 2)) {
+    if (gl_version_info.is_es3 && target != GL_TEXTURE_EXTERNAL_OES) {
+      source += "#version 300 es\n";
+      source +=
+          "#define ATTRIBUTE in\n"
+          "#define VARYING out\n";
+    } else {
+      source +=
+          "#define ATTRIBUTE attribute\n"
+          "#define VARYING varying\n";
+    }
   } else {
-    source += std::string("\
-        #define ATTRIBUTE attribute\n\
-        #define VARYING varying\n");
+    source += "#version 150\n";
+    source +=
+        "#define ATTRIBUTE in\n"
+        "#define VARYING out\n";
   }
 
   // Preamble for texture precision.
-  source += std::string(kShaderPrecisionPreamble);
+  source += kShaderPrecisionPreamble;
 
   // Main shader source.
-  source += std::string("\
-      uniform vec2 u_vertex_dest_mult;\n\
-      uniform vec2 u_vertex_dest_add;\n\
-      uniform vec2 u_vertex_source_mult;\n\
-      uniform vec2 u_vertex_source_add;\n\
-      ATTRIBUTE vec2 a_position;\n\
-      VARYING TexCoordPrecision vec2 v_uv;\n\
-      void main(void) {\n\
-        gl_Position = vec4(0, 0, 0, 1);\n\
-        gl_Position.xy = a_position.xy * u_vertex_dest_mult + \
-                         u_vertex_dest_add;\n\
-        v_uv = a_position.xy * u_vertex_source_mult + u_vertex_source_add;\n\
-      }\n");
+  source +=
+      "uniform vec2 u_vertex_dest_mult;\n"
+      "uniform vec2 u_vertex_dest_add;\n"
+      "uniform vec2 u_vertex_source_mult;\n"
+      "uniform vec2 u_vertex_source_add;\n"
+      "ATTRIBUTE vec2 a_position;\n"
+      "VARYING TexCoordPrecision vec2 v_uv;\n"
+      "void main(void) {\n"
+      "  gl_Position = vec4(0, 0, 0, 1);\n"
+      "  gl_Position.xy =\n"
+      "      a_position.xy * u_vertex_dest_mult + u_vertex_dest_add;\n"
+      "  v_uv = a_position.xy * u_vertex_source_mult + u_vertex_source_add;\n"
+      "}\n";
 
   return source;
 }
@@ -134,97 +333,175 @@
                                     bool premultiply_alpha,
                                     bool unpremultiply_alpha,
                                     bool nv_egl_stream_consumer_external,
-                                    GLenum target) {
+                                    GLenum target,
+                                    GLenum source_format,
+                                    GLenum dest_format) {
   std::string source;
 
   // Preamble for core and compatibility mode.
-  if (gl_version_info.is_desktop_core_profile) {
-    source += std::string("\
-        #version 150\n\
-        out vec4 frag_color;\n\
-        #define VARYING in\n\
-        #define FRAGCOLOR frag_color\n\
-        #define TextureLookup texture\n");
+  if (gl_version_info.is_es || gl_version_info.IsLowerThanGL(3, 2)) {
+    if (gl_version_info.is_es3 && target != GL_TEXTURE_EXTERNAL_OES) {
+      source += "#version 300 es\n";
+    }
+    if (target == GL_TEXTURE_EXTERNAL_OES) {
+      source += "#extension GL_OES_EGL_image_external : enable\n";
+
+      if (nv_egl_stream_consumer_external) {
+        source += "#extension GL_NV_EGL_stream_consumer_external : enable\n";
+      }
+    }
   } else {
+    source += "#version 150\n";
+  }
+
+  // Preamble for texture precision.
+  source += kShaderPrecisionPreamble;
+
+  if (gpu::gles2::GLES2Util::IsSignedIntegerFormat(dest_format)) {
+    source += "#define TextureType ivec4\n";
+    source += "#define ZERO 0\n";
+    source += "#define MAX_COLOR 255\n";
+    if (gpu::gles2::GLES2Util::IsSignedIntegerFormat(source_format))
+      source += "#define InnerScaleValue 1\n";
+    else if (gpu::gles2::GLES2Util::IsUnsignedIntegerFormat(source_format))
+      source += "#define InnerScaleValue 1u\n";
+    else
+      source += "#define InnerScaleValue 255.0\n";
+    source += "#define OuterScaleValue 1\n";
+  } else if (gpu::gles2::GLES2Util::IsUnsignedIntegerFormat(dest_format)) {
+    source += "#define TextureType uvec4\n";
+    source += "#define ZERO 0u\n";
+    source += "#define MAX_COLOR 255u\n";
+    if (gpu::gles2::GLES2Util::IsSignedIntegerFormat(source_format))
+      source += "#define InnerScaleValue 1\n";
+    else if (gpu::gles2::GLES2Util::IsUnsignedIntegerFormat(source_format))
+      source += "#define InnerScaleValue 1u\n";
+    else
+      source += "#define InnerScaleValue 255.0\n";
+    source += "#define OuterScaleValue 1u\n";
+  } else {
+    source += "#define TextureType vec4\n";
+    source += "#define ZERO 0.0\n";
+    source += "#define MAX_COLOR 1.0\n";
+    if (gpu::gles2::GLES2Util::IsSignedIntegerFormat(source_format)) {
+      source += "#define InnerScaleValue 1\n";
+      source += "#define OuterScaleValue (1.0 / 255.0)\n";
+    } else if (gpu::gles2::GLES2Util::IsUnsignedIntegerFormat(source_format)) {
+      source += "#define InnerScaleValue 1u\n";
+      source += "#define OuterScaleValue (1.0 / 255.0)\n";
+    } else {
+      source += "#define InnerScaleValue 1.0\n";
+      source += "#define OuterScaleValue 1.0\n";
+    }
+  }
+  if (gl_version_info.is_es2 || gl_version_info.IsLowerThanGL(3, 2) ||
+      target == GL_TEXTURE_EXTERNAL_OES) {
     switch (target) {
       case GL_TEXTURE_2D:
-        source += std::string("#define TextureLookup texture2D\n");
-        break;
-      case GL_TEXTURE_RECTANGLE_ARB:
-        source += std::string("#define TextureLookup texture2DRect\n");
-        break;
       case GL_TEXTURE_EXTERNAL_OES:
-        source +=
-            std::string("#extension GL_OES_EGL_image_external : enable\n");
-
-        if (nv_egl_stream_consumer_external) {
-          source += std::string(
-              "#extension GL_NV_EGL_stream_consumer_external : enable\n");
-        }
-
-        source += std::string("#define TextureLookup texture2D\n");
+        source += "#define TextureLookup texture2D\n";
         break;
       default:
         NOTREACHED();
         break;
     }
-    source += std::string("\
-        #define VARYING varying\n\
-        #define FRAGCOLOR gl_FragColor\n");
+
+    source +=
+        "#define VARYING varying\n"
+        "#define FRAGCOLOR gl_FragColor\n";
+  } else {
+    source +=
+        "#define VARYING in\n"
+        "out TextureType frag_color;\n"
+        "#define FRAGCOLOR frag_color\n"
+        "#define TextureLookup texture\n";
   }
 
   // Preamble for sampler type.
   switch (target) {
     case GL_TEXTURE_2D:
-      source += std::string("#define SamplerType sampler2D\n");
+      source += "#define SamplerType sampler2D\n";
       break;
     case GL_TEXTURE_RECTANGLE_ARB:
-      source += std::string("#define SamplerType sampler2DRect\n");
+      source += "#define SamplerType sampler2DRect\n";
       break;
     case GL_TEXTURE_EXTERNAL_OES:
-      source += std::string("#define SamplerType samplerExternalOES\n");
+      source += "#define SamplerType samplerExternalOES\n";
       break;
     default:
       NOTREACHED();
       break;
   }
 
-  // Preamble for texture precision.
-  source += std::string(kShaderPrecisionPreamble);
-
   // Main shader source.
-  source += std::string("\
-      uniform SamplerType u_sampler;\n\
-      uniform mat4 u_tex_coord_transform;\n\
-      VARYING TexCoordPrecision vec2 v_uv;\n\
-      void main(void) {\n\
-        TexCoordPrecision vec4 uv = u_tex_coord_transform * vec4(v_uv, 0, 1);\n\
-        FRAGCOLOR = TextureLookup(u_sampler, uv.st);\n");
+  source +=
+      "uniform SamplerType u_sampler;\n"
+      "uniform mat4 u_tex_coord_transform;\n"
+      "VARYING TexCoordPrecision vec2 v_uv;\n"
+      "void main(void) {\n"
+      "  TexCoordPrecision vec4 uv =\n"
+      "      u_tex_coord_transform * vec4(v_uv, 0, 1);\n"
+      "  vec4 color = TextureLookup(u_sampler, uv.st);\n"
+      "  FRAGCOLOR = TextureType(color * InnerScaleValue) * OuterScaleValue;\n";
 
   // Post-processing to premultiply or un-premultiply alpha.
-  if (premultiply_alpha) {
-    source += std::string("        FRAGCOLOR.rgb *= FRAGCOLOR.a;\n");
-  }
-  if (unpremultiply_alpha) {
-    source += std::string("\
-        if (FRAGCOLOR.a > 0.0)\n\
-          FRAGCOLOR.rgb /= FRAGCOLOR.a;\n");
+  // Check dest format has alpha channel first.
+  if ((gpu::gles2::GLES2Util::GetChannelsForFormat(dest_format) & 0x0008) !=
+      0) {
+    if (premultiply_alpha) {
+      source += "  FRAGCOLOR.rgb *= FRAGCOLOR.a;\n";
+      source += "  FRAGCOLOR.rgb /= MAX_COLOR;\n";
+    }
+    if (unpremultiply_alpha) {
+      source +=
+          "  if (FRAGCOLOR.a > ZERO) {\n"
+          "    FRAGCOLOR.rgb /= FRAGCOLOR.a;\n"
+          "    FRAGCOLOR.rgb *= MAX_COLOR;\n"
+          "  }\n";
+    }
   }
 
   // Main function end.
-  source += std::string("      }\n");
+  source += "}\n";
 
   return source;
 }
 
+GLenum getIntermediateFormat(GLenum format) {
+  switch (format) {
+    case GL_LUMINANCE_ALPHA:
+    case GL_LUMINANCE:
+    case GL_ALPHA:
+      return GL_RGBA;
+    case GL_SRGB_EXT:
+      return GL_SRGB_ALPHA_EXT;
+    case GL_RGB16F:
+      return GL_RGBA16F;
+    case GL_RGB9_E5:
+    case GL_RGB32F:
+      return GL_RGBA32F;
+    case GL_SRGB8:
+      return GL_SRGB8_ALPHA8;
+    case GL_RGB8UI:
+      return GL_RGBA8UI;
+    default:
+      return format;
+  }
+}
+
 void CompileShader(GLuint shader, const char* shader_source) {
   glShaderSource(shader, 1, &shader_source, 0);
   glCompileShader(shader);
-#ifndef NDEBUG
+#if DCHECK_IS_ON()
   GLint compile_status;
   glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
-  if (GL_TRUE != compile_status)
-    DLOG(ERROR) << "CopyTextureCHROMIUM: shader compilation failure.";
+  if (GL_TRUE != compile_status) {
+    char buffer[1024];
+    GLsizei length = 0;
+    glGetShaderInfoLog(shader, sizeof(buffer), &length, buffer);
+    std::string log(buffer, length);
+    DLOG(ERROR) << "CopyTextureCHROMIUM: shader compilation failure: " << log;
+  }
 #endif
 }
 
@@ -327,8 +604,8 @@
 CopyTextureCHROMIUMResourceManager::CopyTextureCHROMIUMResourceManager()
     : initialized_(false),
       nv_egl_stream_consumer_external_(false),
-      vertex_shader_(0u),
-      fragment_shaders_(NUM_FRAGMENT_SHADERS, 0u),
+      vertex_shaders_(kNumVertexShaders, 0u),
+      fragment_shaders_(kNumFragmentShaders, 0u),
       vertex_array_object_id_(0u),
       buffer_id_(0u),
       framebuffer_(0u) {}
@@ -393,7 +670,8 @@
   glDeleteFramebuffersEXT(1, &framebuffer_);
   framebuffer_ = 0;
 
-  DeleteShader(vertex_shader_);
+  std::for_each(
+      vertex_shaders_.begin(), vertex_shaders_.end(), DeleteShader);
   std::for_each(
       fragment_shaders_.begin(), fragment_shaders_.end(), DeleteShader);
 
@@ -419,21 +697,14 @@
     GLsizei height,
     bool flip_y,
     bool premultiply_alpha,
-    bool unpremultiply_alpha) {
+    bool unpremultiply_alpha,
+    CopyTextureMethod method) {
   bool premultiply_alpha_change = premultiply_alpha ^ unpremultiply_alpha;
-  // GL_INVALID_OPERATION is generated if the currently bound framebuffer's
-  // format does not contain a superset of the components required by the base
-  // format of internalformat.
-  // https://www.khronos.org/opengles/sdk/docs/man/xhtml/glCopyTexImage2D.xml
-  bool source_format_contain_superset_of_dest_format =
-      (source_internal_format == dest_internal_format &&
-       source_internal_format != GL_BGRA_EXT) ||
-      (source_internal_format == GL_RGBA && dest_internal_format == GL_RGB);
+
   // GL_TEXTURE_RECTANGLE_ARB on FBO is supported by OpenGL, not GLES2,
   // so restrict this to GL_TEXTURE_2D.
   if (source_target == GL_TEXTURE_2D && dest_target == GL_TEXTURE_2D &&
-      !flip_y && !premultiply_alpha_change &&
-      source_format_contain_superset_of_dest_format) {
+      !flip_y && !premultiply_alpha_change && method == DIRECT_COPY) {
     DoCopyTexImage2D(decoder,
                      source_target,
                      source_id,
@@ -446,10 +717,35 @@
     return;
   }
 
+  GLuint dest_texture = dest_id;
+  GLuint intermediate_texture = 0;
+  if (method == DRAW_AND_COPY) {
+    GLenum adjusted_internal_format =
+        getIntermediateFormat(dest_internal_format);
+    glGenTextures(1, &intermediate_texture);
+    glBindTexture(dest_target, intermediate_texture);
+    GLenum format = TextureManager::ExtractFormatFromStorageFormat(
+        adjusted_internal_format);
+    GLenum type =
+        TextureManager::ExtractTypeFromStorageFormat(adjusted_internal_format);
+
+    glTexImage2D(dest_target, 0, adjusted_internal_format, width, height, 0,
+                 format, type, nullptr);
+    dest_texture = intermediate_texture;
+    dest_internal_format = adjusted_internal_format;
+  }
   // Use kIdentityMatrix if no transform passed in.
-  DoCopyTextureWithTransform(decoder, source_target, source_id, dest_target,
-                             dest_id, width, height, flip_y, premultiply_alpha,
-                             unpremultiply_alpha, kIdentityMatrix);
+  DoCopyTextureWithTransform(
+      decoder, source_target, source_id, source_internal_format, dest_target,
+      dest_texture, dest_internal_format, width, height, flip_y,
+      premultiply_alpha, unpremultiply_alpha, kIdentityMatrix);
+
+  if (method == DRAW_AND_COPY) {
+    DoCopyTexImage2D(decoder, dest_target, intermediate_texture, dest_target,
+                     dest_id, dest_internal_format, width, height,
+                     framebuffer_);
+    glDeleteTextures(1, &intermediate_texture);
+  }
 }
 
 void CopyTextureCHROMIUMResourceManager::DoCopySubTexture(
@@ -472,7 +768,8 @@
     GLsizei source_height,
     bool flip_y,
     bool premultiply_alpha,
-    bool unpremultiply_alpha) {
+    bool unpremultiply_alpha,
+    CopyTextureMethod method) {
   bool use_gl_copy_tex_sub_image_2d = true;
 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
   // glDrawArrays is faster than glCopyTexSubImage2D on IA Mesa driver,
@@ -482,29 +779,53 @@
   use_gl_copy_tex_sub_image_2d = false;
 #endif
   bool premultiply_alpha_change = premultiply_alpha ^ unpremultiply_alpha;
-  // GL_INVALID_OPERATION is generated if the currently bound framebuffer's
-  // format does not contain a superset of the components required by the base
-  // format of internalformat.
-  // https://www.khronos.org/opengles/sdk/docs/man/xhtml/glCopyTexImage2D.xml
-  bool source_format_contain_superset_of_dest_format =
-      (source_internal_format == dest_internal_format &&
-       source_internal_format != GL_BGRA_EXT) ||
-      (source_internal_format == GL_RGBA && dest_internal_format == GL_RGB);
+
   // GL_TEXTURE_RECTANGLE_ARB on FBO is supported by OpenGL, not GLES2,
   // so restrict this to GL_TEXTURE_2D.
   if (use_gl_copy_tex_sub_image_2d && source_target == GL_TEXTURE_2D &&
       dest_target == GL_TEXTURE_2D && !flip_y && !premultiply_alpha_change &&
-      source_format_contain_superset_of_dest_format) {
+      method == DIRECT_COPY) {
     DoCopyTexSubImage2D(decoder, source_target, source_id, dest_target, dest_id,
                         xoffset, yoffset, x, y, width, height, framebuffer_);
     return;
   }
 
+  GLint dest_xoffset = xoffset;
+  GLint dest_yoffset = yoffset;
+  GLuint dest_texture = dest_id;
+  GLuint intermediate_texture = 0;
+  if (method == DRAW_AND_COPY) {
+    GLenum adjusted_internal_format =
+        getIntermediateFormat(dest_internal_format);
+    glGenTextures(1, &intermediate_texture);
+    glBindTexture(dest_target, intermediate_texture);
+    GLenum format = TextureManager::ExtractFormatFromStorageFormat(
+        adjusted_internal_format);
+    GLenum type =
+        TextureManager::ExtractTypeFromStorageFormat(adjusted_internal_format);
+
+    glTexImage2D(dest_target, 0, adjusted_internal_format, width, height, 0,
+                 format, type, nullptr);
+    dest_texture = intermediate_texture;
+    dest_internal_format = adjusted_internal_format;
+    dest_xoffset = 0;
+    dest_yoffset = 0;
+    dest_width = width;
+    dest_height = height;
+  }
+
   DoCopySubTextureWithTransform(
       decoder, source_target, source_id, source_internal_format, dest_target,
-      dest_id, dest_internal_format, xoffset, yoffset, x, y, width, height,
-      dest_width, dest_height, source_width, source_height, flip_y,
-      premultiply_alpha, unpremultiply_alpha, kIdentityMatrix);
+      dest_texture, dest_internal_format, dest_xoffset, dest_yoffset, x, y,
+      width, height, dest_width, dest_height, source_width, source_height,
+      flip_y, premultiply_alpha, unpremultiply_alpha, kIdentityMatrix);
+
+  if (method == DRAW_AND_COPY) {
+    DoCopyTexSubImage2D(decoder, dest_target, intermediate_texture, dest_target,
+                        dest_id, xoffset, yoffset, 0, 0, width, height,
+                        framebuffer_);
+    glDeleteTextures(1, &intermediate_texture);
+  }
 }
 
 void CopyTextureCHROMIUMResourceManager::DoCopySubTextureWithTransform(
@@ -529,18 +850,21 @@
     bool premultiply_alpha,
     bool unpremultiply_alpha,
     const GLfloat transform_matrix[16]) {
-  DoCopyTextureInternal(decoder, source_target, source_id, dest_target, dest_id,
-      xoffset, yoffset, x, y, width, height, dest_width, dest_height,
-      source_width, source_height, flip_y, premultiply_alpha,
-      unpremultiply_alpha, transform_matrix);
+  DoCopyTextureInternal(
+      decoder, source_target, source_id, source_internal_format, dest_target,
+      dest_id, dest_internal_format, xoffset, yoffset, x, y, width, height,
+      dest_width, dest_height, source_width, source_height, flip_y,
+      premultiply_alpha, unpremultiply_alpha, transform_matrix);
 }
 
 void CopyTextureCHROMIUMResourceManager::DoCopyTextureWithTransform(
     const gles2::GLES2Decoder* decoder,
     GLenum source_target,
     GLuint source_id,
+    GLenum source_format,
     GLenum dest_target,
     GLuint dest_id,
+    GLenum dest_format,
     GLsizei width,
     GLsizei height,
     bool flip_y,
@@ -549,18 +873,20 @@
     const GLfloat transform_matrix[16]) {
   GLsizei dest_width = width;
   GLsizei dest_height = height;
-  DoCopyTextureInternal(decoder, source_target, source_id, dest_target, dest_id,
-                        0, 0, 0, 0, width, height, dest_width, dest_height,
-                        width, height, flip_y, premultiply_alpha,
-                        unpremultiply_alpha, transform_matrix);
+  DoCopyTextureInternal(
+      decoder, source_target, source_id, source_format, dest_target, dest_id,
+      dest_format, 0, 0, 0, 0, width, height, dest_width, dest_height, width,
+      height, flip_y, premultiply_alpha, unpremultiply_alpha, transform_matrix);
 }
 
 void CopyTextureCHROMIUMResourceManager::DoCopyTextureInternal(
     const gles2::GLES2Decoder* decoder,
     GLenum source_target,
     GLuint source_id,
+    GLenum source_format,
     GLenum dest_target,
     GLuint dest_id,
+    GLenum dest_format,
     GLint xoffset,
     GLint yoffset,
     GLint x,
@@ -607,8 +933,11 @@
     glVertexAttribPointer(kVertexPositionAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0);
   }
 
-  FragmentShaderId fragment_shader_id = GetFragmentShaderId(
-      premultiply_alpha, unpremultiply_alpha, source_target);
+  ShaderId vertex_shader_id = GetVertexShaderId(source_target);
+  DCHECK_LT(static_cast<size_t>(vertex_shader_id), vertex_shaders_.size());
+  ShaderId fragment_shader_id = GetFragmentShaderId(
+      premultiply_alpha, unpremultiply_alpha, source_target,
+      source_format, dest_format);
   DCHECK_LT(static_cast<size_t>(fragment_shader_id), fragment_shaders_.size());
 
   ProgramMapKey key(fragment_shader_id);
@@ -616,18 +945,21 @@
   // Create program if necessary.
   if (!info->program) {
     info->program = glCreateProgram();
-    if (!vertex_shader_) {
-      vertex_shader_ = glCreateShader(GL_VERTEX_SHADER);
-      std::string source = GetVertexShaderSource(gl_version_info);
-      CompileShader(vertex_shader_, source.c_str());
+    GLuint* vertex_shader = &vertex_shaders_[vertex_shader_id];
+    if (!*vertex_shader) {
+      *vertex_shader = glCreateShader(GL_VERTEX_SHADER);
+      std::string source =
+          GetVertexShaderSource(gl_version_info, source_target);
+      CompileShader(*vertex_shader, source.c_str());
     }
-    glAttachShader(info->program, vertex_shader_);
+    glAttachShader(info->program, *vertex_shader);
     GLuint* fragment_shader = &fragment_shaders_[fragment_shader_id];
     if (!*fragment_shader) {
       *fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
       std::string source = GetFragmentShaderSource(
           gl_version_info, premultiply_alpha, unpremultiply_alpha,
-          nv_egl_stream_consumer_external_, source_target);
+          nv_egl_stream_consumer_external_, source_target, source_format,
+          dest_format);
       CompileShader(*fragment_shader, source.c_str());
     }
     glAttachShader(info->program, *fragment_shader);
diff --git a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h
index dd70532..bb3ff30 100644
--- a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h
+++ b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h
@@ -18,6 +18,28 @@
 
 class GLES2Decoder;
 
+enum CopyTextureMethod {
+  // Use CopyTex{Sub}Image2D to copy from the source to the destination.
+  DIRECT_COPY,
+  // Draw from the source to the destination texture.
+  DIRECT_DRAW,
+  // Draw to an intermediate texture, and then copy to the destination texture.
+  DRAW_AND_COPY,
+  // CopyTexture isn't available.
+  NOT_COPYABLE
+};
+
+// TODOs(qiankun.miao@intel.com):
+// 1. Add readback path for RGB9_E5 and float formats (if extension isn't
+// available and they are not color-renderable).
+// 2. Support faces of cube map texture as valid dest target. The cube map
+// texture may be incomplete currently.
+// 3. Add support for levels other than 0.
+// 4. Support ALPHA, LUMINANCE and LUMINANCE_ALPHA formats on core profile.
+// 5. Update the extension doc after the whole work is done
+// in gpu/GLES2/extensions/CHROMIUM/CHROMIUM_copy_texture.txt. We probably
+// will need a ES2 version and a ES3 version.
+
 // This class encapsulates the resources required to implement the
 // GL_CHROMIUM_copy_texture extension.  The copy operation is performed
 // via glCopyTexImage2D() or a blit to a framebuffer object.
@@ -42,7 +64,8 @@
                      GLsizei height,
                      bool flip_y,
                      bool premultiply_alpha,
-                     bool unpremultiply_alpha);
+                     bool unpremultiply_alpha,
+                     CopyTextureMethod method);
 
   void DoCopySubTexture(const gles2::GLES2Decoder* decoder,
                         GLenum source_target,
@@ -63,7 +86,8 @@
                         GLsizei source_height,
                         bool flip_y,
                         bool premultiply_alpha,
-                        bool unpremultiply_alpha);
+                        bool unpremultiply_alpha,
+                        CopyTextureMethod method);
 
   void DoCopySubTextureWithTransform(const gles2::GLES2Decoder* decoder,
                                      GLenum source_target,
@@ -94,8 +118,10 @@
   void DoCopyTextureWithTransform(const gles2::GLES2Decoder* decoder,
                                   GLenum source_target,
                                   GLuint source_id,
+                                  GLenum source_format,
                                   GLenum dest_target,
                                   GLuint dest_id,
+                                  GLenum dest_format,
                                   GLsizei width,
                                   GLsizei height,
                                   bool flip_y,
@@ -136,8 +162,10 @@
   void DoCopyTextureInternal(const gles2::GLES2Decoder* decoder,
                              GLenum source_target,
                              GLuint source_id,
+                             GLenum source_format,
                              GLenum dest_target,
                              GLuint dest_id,
+                             GLenum dest_format,
                              GLint xoffset,
                              GLint yoffset,
                              GLint x,
@@ -156,7 +184,7 @@
   bool initialized_;
   bool nv_egl_stream_consumer_external_;
   typedef std::vector<GLuint> ShaderVector;
-  GLuint vertex_shader_;
+  ShaderVector vertex_shaders_;
   ShaderVector fragment_shaders_;
   typedef int ProgramMapKey;
   typedef base::hash_map<ProgramMapKey, ProgramInfo> ProgramMap;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index ff50396..9abbd4af 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -890,6 +890,10 @@
       const void* data,
       ContextState::Dimension dimension);
 
+  bool ValidateCopyTexFormatHelper(GLenum internal_format,
+                                   GLenum read_format,
+                                   GLenum read_type,
+                                   std::string* output_error_msg);
   // Validate if |format| is valid for CopyTex{Sub}Image functions.
   // If not, generate a GL error and return false.
   bool ValidateCopyTexFormat(const char* func_name, GLenum internal_format,
@@ -2009,7 +2013,7 @@
   bool ValidateCopyTextureCHROMIUMTextures(const char* function_name,
                                            TextureRef* source_texture_ref,
                                            TextureRef* dest_texture_ref);
-  bool ValidateCopyTextureCHROMIUMInternalFormats(
+  CopyTextureMethod ValidateCopyTextureCHROMIUMInternalFormats(
       const char* function_name,
       TextureRef* source_texture_ref,
       GLenum dest_internal_format);
@@ -13884,12 +13888,14 @@
   return error::kNoError;
 }
 
-bool GLES2DecoderImpl::ValidateCopyTexFormat(
-    const char* func_name, GLenum internal_format,
-    GLenum read_format, GLenum read_type) {
+bool GLES2DecoderImpl::ValidateCopyTexFormatHelper(
+    GLenum internal_format,
+    GLenum read_format,
+    GLenum read_type,
+    std::string* output_error_msg) {
+  DCHECK(output_error_msg);
   if (read_format == 0) {
-    LOCAL_SET_GL_ERROR(
-        GL_INVALID_OPERATION, func_name, "no valid color image");
+    *output_error_msg = std::string("no valid color image");
     return false;
   }
   // Check we have compatible formats.
@@ -13897,8 +13903,7 @@
   uint32_t channels_needed = GLES2Util::GetChannelsForFormat(internal_format);
   if (!channels_needed ||
       (channels_needed & channels_exist) != channels_needed) {
-    LOCAL_SET_GL_ERROR(
-        GL_INVALID_OPERATION, func_name, "incompatible format");
+    *output_error_msg = std::string("incompatible format");
     return false;
   }
   if (feature_info_->IsWebGL2OrES3Context()) {
@@ -13913,15 +13918,13 @@
          GLES2Util::IsSignedIntegerFormat(read_format)) ||
         (GLES2Util::IsUnsignedIntegerFormat(internal_format) !=
          GLES2Util::IsUnsignedIntegerFormat(read_format))) {
-      LOCAL_SET_GL_ERROR(
-          GL_INVALID_OPERATION, func_name, "incompatible format");
+      *output_error_msg = std::string("incompatible format");
       return false;
     }
   }
   if ((channels_needed & (GLES2Util::kDepth | GLES2Util::kStencil)) != 0) {
-    LOCAL_SET_GL_ERROR(
-        GL_INVALID_OPERATION,
-        func_name, "can not be used with depth or stencil textures");
+    *output_error_msg =
+        std::string("can not be used with depth or stencil textures");
     return false;
   }
   if (feature_info_->IsWebGL2OrES3Context()) {
@@ -13938,9 +13941,7 @@
           (dg > 0 && sg != dg) ||
           (db > 0 && sb != db) ||
           (da > 0 && sa != da)) {
-        LOCAL_SET_GL_ERROR(
-            GL_INVALID_OPERATION,
-            func_name, "incompatible color component sizes");
+        *output_error_msg = std::string("incompatible color component sizes");
         return false;
       }
     }
@@ -13948,6 +13949,20 @@
   return true;
 }
 
+bool GLES2DecoderImpl::ValidateCopyTexFormat(const char* func_name,
+                                             GLenum internal_format,
+                                             GLenum read_format,
+                                             GLenum read_type) {
+  std::string output_error_msg;
+  if (!ValidateCopyTexFormatHelper(internal_format, read_format, read_type,
+                                   &output_error_msg)) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, func_name,
+                       output_error_msg.c_str());
+    return false;
+  }
+  return true;
+}
+
 void GLES2DecoderImpl::DoCopyTexImage2D(
     GLenum target,
     GLint level,
@@ -16150,7 +16165,7 @@
   return true;
 }
 
-bool GLES2DecoderImpl::ValidateCopyTextureCHROMIUMInternalFormats(
+CopyTextureMethod GLES2DecoderImpl::ValidateCopyTextureCHROMIUMInternalFormats(
     const char* function_name,
     TextureRef* source_texture_ref,
     GLenum dest_internal_format) {
@@ -16160,14 +16175,59 @@
   source_texture->GetLevelType(source_texture->target(), 0, &source_type,
                                &source_internal_format);
 
-  // The destination format should be GL_RGB, or GL_RGBA. GL_ALPHA,
-  // GL_LUMINANCE, and GL_LUMINANCE_ALPHA are not supported because they are not
-  // renderable on some platforms.
-  bool valid_dest_format =
-      dest_internal_format == GL_RGB || dest_internal_format == GL_RGBA ||
-      dest_internal_format == GL_RGB8 || dest_internal_format == GL_RGBA8 ||
-      dest_internal_format == GL_BGRA_EXT ||
-      dest_internal_format == GL_BGRA8_EXT;
+  bool valid_dest_format = false;
+  // TODO(qiankun.miao@intel.com): ALPHA, LUMINANCE and LUMINANCE_ALPHA formats
+  // are not supported on GL core profile. See crbug.com/577144. Enable the
+  // workaround for glCopyTexImage and glCopyTexSubImage in
+  // gles2_cmd_copy_tex_image.cc for glCopyTextureCHROMIUM implementation.
+  switch (dest_internal_format) {
+    case GL_RGB:
+    case GL_RGBA:
+    case GL_RGB8:
+    case GL_RGBA8:
+      valid_dest_format = true;
+      break;
+    case GL_BGRA_EXT:
+    case GL_BGRA8_EXT:
+      valid_dest_format =
+          feature_info_->feature_flags().ext_texture_format_bgra8888;
+      break;
+    case GL_SRGB_EXT:
+    case GL_SRGB_ALPHA_EXT:
+      valid_dest_format = feature_info_->feature_flags().ext_srgb;
+      break;
+    case GL_R8:
+    case GL_R8UI:
+    case GL_RG8:
+    case GL_RG8UI:
+    case GL_SRGB8:
+    case GL_RGB565:
+    case GL_RGB8UI:
+    case GL_SRGB8_ALPHA8:
+    case GL_RGB5_A1:
+    case GL_RGBA4:
+    case GL_RGBA8UI:
+      valid_dest_format = feature_info_->IsWebGL2OrES3Context();
+      break;
+    case GL_RGB9_E5:
+      valid_dest_format = !gl_version_info().is_es;
+      break;
+    case GL_R16F:
+    case GL_R32F:
+    case GL_RG16F:
+    case GL_RG32F:
+    case GL_RGB16F:
+    case GL_RGB32F:
+    case GL_RGBA16F:
+    case GL_RGBA32F:
+    case GL_R11F_G11F_B10F:
+      valid_dest_format = feature_info_->ext_color_buffer_float_available();
+      break;
+    default:
+      valid_dest_format = false;
+      break;
+  }
+
   bool valid_source_format =
       source_internal_format == GL_RED || source_internal_format == GL_ALPHA ||
       source_internal_format == GL_RGB || source_internal_format == GL_RGBA ||
@@ -16183,16 +16243,38 @@
         GLES2Util::GetStringEnum(source_internal_format);
     LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name,
                        msg.c_str());
-    return false;
+    return NOT_COPYABLE;
   }
   if (!valid_dest_format) {
     std::string msg = "invalid dest internal format " +
         GLES2Util::GetStringEnum(dest_internal_format);
     LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name,
                        msg.c_str());
-    return false;
+    return NOT_COPYABLE;
   }
-  return true;
+
+  bool source_format_color_renderable =
+      Texture::ColorRenderable(GetFeatureInfo(), source_internal_format, false);
+  bool dest_format_color_renderable =
+      Texture::ColorRenderable(GetFeatureInfo(), dest_internal_format, false);
+  std::string output_error_msg;
+
+  // CopyTexImage* should not allow internalformat of GL_BGRA_EXT and
+  // GL_BGRA8_EXT. crbug.com/663086.
+  bool copy_tex_image_format_valid =
+      source_internal_format != GL_BGRA_EXT &&
+      dest_internal_format != GL_BGRA_EXT &&
+      source_internal_format != GL_BGRA8_EXT &&
+      dest_internal_format != GL_BGRA8_EXT &&
+      ValidateCopyTexFormatHelper(dest_internal_format, source_internal_format,
+                                  source_type, &output_error_msg);
+  if (source_format_color_renderable && copy_tex_image_format_valid)
+    return DIRECT_COPY;
+
+  if (dest_format_color_renderable)
+    return DIRECT_DRAW;
+
+  return DRAW_AND_COPY;
 }
 
 bool GLES2DecoderImpl::ValidateCompressedCopyTextureCHROMIUM(
@@ -16256,25 +16338,43 @@
   TextureRef* source_texture_ref = GetTexture(source_id);
   TextureRef* dest_texture_ref = GetTexture(dest_id);
 
-  if (!texture_manager()->ValidateTextureParameters(
-          GetErrorState(), kFunctionName, true, internal_format, dest_type,
-          internal_format, 0))
-    return;
-
   if (!ValidateCopyTextureCHROMIUMTextures(kFunctionName, source_texture_ref,
                                            dest_texture_ref)) {
     return;
   }
 
-  if (!ValidateCopyTextureCHROMIUMInternalFormats(
-          kFunctionName, source_texture_ref, internal_format)) {
-    return;
-  }
-
   Texture* source_texture = source_texture_ref->texture();
   Texture* dest_texture = dest_texture_ref->texture();
   GLenum source_target = source_texture->target();
   GLenum dest_target = dest_texture->target();
+
+  GLenum source_type = 0;
+  GLenum source_internal_format = 0;
+  source_texture->GetLevelType(source_target, 0, &source_type,
+                               &source_internal_format);
+  GLenum format =
+      TextureManager::ExtractFormatFromStorageFormat(internal_format);
+  if (!texture_manager()->ValidateTextureParameters(
+          GetErrorState(), kFunctionName, true, format, dest_type,
+          internal_format, 0)) {
+    return;
+  }
+
+  CopyTextureMethod method = ValidateCopyTextureCHROMIUMInternalFormats(
+      kFunctionName, source_texture_ref, internal_format);
+  // INVALID_OPERATION is already generated by
+  // ValidateCopyTextureCHROMIUMInternalFormats.
+  if (NOT_COPYABLE == method) {
+    return;
+  }
+
+  if (feature_info_->feature_flags().desktop_srgb_support) {
+    bool enable_framebuffer_srgb =
+        GetColorEncodingFromInternalFormat(source_internal_format) == GL_SRGB ||
+        GetColorEncodingFromInternalFormat(internal_format) == GL_SRGB;
+    state_.EnableDisableFramebufferSRGB(enable_framebuffer_srgb);
+  }
+
   int source_width = 0;
   int source_height = 0;
   gl::GLImage* image =
@@ -16306,11 +16406,6 @@
     }
   }
 
-  GLenum source_type = 0;
-  GLenum source_internal_format = 0;
-  source_texture->GetLevelType(source_target, 0, &source_type,
-                               &source_internal_format);
-
   if (dest_texture->IsImmutable()) {
     LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, kFunctionName,
                        "texture is immutable");
@@ -16347,26 +16442,24 @@
     // Ensure that the glTexImage2D succeeds.
     LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER(kFunctionName);
     glBindTexture(dest_target, dest_texture->service_id());
-    glTexImage2D(
-        dest_target, 0, TextureManager::AdjustTexInternalFormat(
-                            feature_info_.get(), internal_format),
-        source_width, source_height, 0,
-        TextureManager::AdjustTexFormat(feature_info_.get(), internal_format),
-        dest_type, NULL);
+    glTexImage2D(dest_target, 0, TextureManager::AdjustTexInternalFormat(
+                                     feature_info_.get(), internal_format),
+                 source_width, source_height, 0,
+                 TextureManager::AdjustTexFormat(feature_info_.get(), format),
+                 dest_type, NULL);
     GLenum error = LOCAL_PEEK_GL_ERROR(kFunctionName);
     if (error != GL_NO_ERROR) {
       RestoreCurrentTextureBindings(&state_, dest_target);
       return;
     }
 
-    texture_manager()->SetLevelInfo(
-        dest_texture_ref, dest_target, 0, internal_format, source_width,
-        source_height, 1, 0, internal_format, dest_type,
-        gfx::Rect(source_width, source_height));
+    texture_manager()->SetLevelInfo(dest_texture_ref, dest_target, 0,
+                                    internal_format, source_width,
+                                    source_height, 1, 0, format, dest_type,
+                                    gfx::Rect(source_width, source_height));
     dest_texture->ApplyFormatWorkarounds(feature_info_.get());
   } else {
-    texture_manager()->SetLevelCleared(dest_texture_ref, dest_target, 0,
-                                       true);
+    texture_manager()->SetLevelCleared(dest_texture_ref, dest_target, 0, true);
   }
 
   // Try using GLImage::CopyTexImage when possible.
@@ -16389,18 +16482,21 @@
       GLfloat transform_matrix[16];
       image->GetTextureMatrix(transform_matrix);
       copy_texture_CHROMIUM_->DoCopyTextureWithTransform(
-          this, source_target, source_texture->service_id(), dest_target,
-          dest_texture->service_id(), source_width, source_height,
+          this, source_target, source_texture->service_id(),
+          source_internal_format, dest_target, dest_texture->service_id(),
+          internal_format, source_width, source_height,
           unpack_flip_y == GL_TRUE, unpack_premultiply_alpha == GL_TRUE,
           unpack_unmultiply_alpha == GL_TRUE, transform_matrix);
       return;
     }
   }
+
   copy_texture_CHROMIUM_->DoCopyTexture(
       this, source_target, source_texture->service_id(), source_internal_format,
       dest_target, dest_texture->service_id(), internal_format, source_width,
       source_height, unpack_flip_y == GL_TRUE,
-      unpack_premultiply_alpha == GL_TRUE, unpack_unmultiply_alpha == GL_TRUE);
+      unpack_premultiply_alpha == GL_TRUE, unpack_unmultiply_alpha == GL_TRUE,
+      method);
 }
 
 void GLES2DecoderImpl::DoCopySubTextureCHROMIUM(
@@ -16502,11 +16598,21 @@
     return;
   }
 
-  if (!ValidateCopyTextureCHROMIUMInternalFormats(
-          kFunctionName, source_texture_ref, dest_internal_format)) {
+  CopyTextureMethod method = ValidateCopyTextureCHROMIUMInternalFormats(
+      kFunctionName, source_texture_ref, dest_internal_format);
+  // INVALID_OPERATION is already generated by
+  // ValidateCopyTextureCHROMIUMInternalFormats.
+  if (NOT_COPYABLE == method) {
     return;
   }
 
+  if (feature_info_->feature_flags().desktop_srgb_support) {
+    bool enable_framebuffer_srgb =
+        GetColorEncodingFromInternalFormat(source_internal_format) == GL_SRGB ||
+        GetColorEncodingFromInternalFormat(dest_internal_format) == GL_SRGB;
+    state_.EnableDisableFramebufferSRGB(enable_framebuffer_srgb);
+  }
+
   // Clear the source texture if necessary.
   if (!texture_manager()->ClearTextureLevel(this, source_texture_ref,
                                             source_target, 0)) {
@@ -16585,7 +16691,8 @@
       dest_target, dest_texture->service_id(), dest_internal_format, xoffset,
       yoffset, x, y, width, height, dest_width, dest_height, source_width,
       source_height, unpack_flip_y == GL_TRUE,
-      unpack_premultiply_alpha == GL_TRUE, unpack_unmultiply_alpha == GL_TRUE);
+      unpack_premultiply_alpha == GL_TRUE, unpack_unmultiply_alpha == GL_TRUE,
+      method);
 }
 
 bool GLES2DecoderImpl::InitializeCopyTexImageBlitter(
@@ -16760,7 +16867,7 @@
       this, source_texture->target(), source_texture->service_id(),
       source_internal_format, dest_texture->target(),
       dest_texture->service_id(), GL_RGBA, source_width, source_height, false,
-      false, false);
+      false, false, DIRECT_DRAW);
 }
 
 void GLES2DecoderImpl::TexStorageImpl(GLenum target,
diff --git a/gpu/command_buffer/service/texture_manager.h b/gpu/command_buffer/service/texture_manager.h
index b0c1aec..8cf2edb 100644
--- a/gpu/command_buffer/service/texture_manager.h
+++ b/gpu/command_buffer/service/texture_manager.h
@@ -325,6 +325,10 @@
 
   bool EmulatingRGB();
 
+  static bool ColorRenderable(const FeatureInfo* feature_info,
+                              GLenum internal_format,
+                              bool immutable);
+
  private:
   friend class MailboxManagerImpl;
   friend class MailboxManagerSync;
@@ -502,10 +506,6 @@
                                  GLenum format,
                                  GLenum type);
 
-  static bool ColorRenderable(const FeatureInfo* feature_info,
-                              GLenum internal_format,
-                              bool immutable);
-
   static bool TextureFilterable(const FeatureInfo* feature_info,
                                 GLenum internal_format,
                                 GLenum type,
diff --git a/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc b/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc
index 44701c96..5d6ace6 100644
--- a/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc
+++ b/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc
@@ -9,6 +9,7 @@
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 #include <GLES2/gl2extchromium.h>
+#include <GLES3/gl3.h>
 #include <stddef.h>
 #include <stdint.h>
 
@@ -16,17 +17,174 @@
 #include "gpu/command_buffer/tests/gl_test_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_version_info.h"
 
 namespace gpu {
 
 namespace {
+
 enum CopyType { TexImage, TexSubImage };
 const CopyType kCopyTypes[] = {
     TexImage,
     TexSubImage,
 };
+
+static const char* kSimpleVertexShaderES3 =
+    "#version 300 es\n"
+    "in vec2 a_position;\n"
+    "out vec2 v_texCoord;\n"
+    "void main() {\n"
+    "  gl_Position = vec4(a_position.x, a_position.y, 0.0, 1.0);\n"
+    "  v_texCoord = (a_position + vec2(1.0, 1.0)) * 0.5;\n"
+    "}\n";
+
+std::string GetFragmentShaderSource(GLenum format) {
+  std::string source;
+  source += std::string(
+      "#version 300 es\n"
+      "precision mediump float;\n");
+  if (gles2::GLES2Util::IsSignedIntegerFormat(format)) {
+    source += std::string("#define SamplerType isampler2D\n");
+    source += std::string("#define TextureType ivec4\n");
+    source += std::string("#define ScaleValue 255.0\n");
+  } else if (gles2::GLES2Util::IsUnsignedIntegerFormat(format)) {
+    source += std::string("#define SamplerType usampler2D\n");
+    source += std::string("#define TextureType uvec4\n");
+    source += std::string("#define ScaleValue 255.0\n");
+  } else {
+    source += std::string("#define SamplerType sampler2D\n");
+    source += std::string("#define TextureType vec4\n");
+    source += std::string("#define ScaleValue 1.0\n");
+  }
+
+  source += std::string(
+      "uniform mediump SamplerType u_texture;\n"
+      "in vec2 v_texCoord;\n"
+      "out vec4 fragData;\n"
+      "void main() {\n"
+      "  TextureType color = texture(u_texture, v_texCoord);\n"
+      "  fragData = vec4(color) / ScaleValue;\n"
+      "}\n");
+  return source;
 }
 
+void setColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a, uint8_t* color) {
+  color[0] = r;
+  color[1] = g;
+  color[2] = b;
+  color[3] = a;
+}
+
+void getExpectedColor(GLenum src_internal_format,
+                      GLenum dest_internal_format,
+                      uint8_t* color,
+                      uint8_t* expected_color,
+                      uint8_t* mask) {
+  uint8_t adjusted_color[4];
+  switch (src_internal_format) {
+    case GL_ALPHA:
+      setColor(0, 0, 0, color[0], adjusted_color);
+      break;
+    case GL_R8:
+      setColor(color[0], 0, 0, 255, adjusted_color);
+      break;
+    case GL_LUMINANCE:
+      setColor(color[0], color[0], color[0], 255, adjusted_color);
+      break;
+    case GL_LUMINANCE_ALPHA:
+      setColor(color[0], color[0], color[0], color[1], adjusted_color);
+      break;
+    case GL_RGB:
+    case GL_RGB8:
+    case GL_RGB_YCBCR_420V_CHROMIUM:
+    case GL_RGB_YCBCR_422_CHROMIUM:
+      setColor(color[0], color[1], color[2], 255, adjusted_color);
+      break;
+    case GL_RGBA:
+    case GL_RGBA8:
+      setColor(color[0], color[1], color[2], color[3], adjusted_color);
+      break;
+    case GL_BGRA_EXT:
+    case GL_BGRA8_EXT:
+      setColor(color[2], color[1], color[0], color[3], adjusted_color);
+      break;
+    default:
+      NOTREACHED();
+      break;
+  }
+
+  switch (dest_internal_format) {
+    case GL_ALPHA:
+      setColor(0, 0, 0, adjusted_color[3], expected_color);
+      setColor(0, 0, 0, 1, mask);
+      break;
+    case GL_R8:
+    case GL_R16F:
+    case GL_R32F:
+    case GL_R8UI:
+      setColor(adjusted_color[0], 0, 0, 0, expected_color);
+      setColor(1, 0, 0, 0, mask);
+      break;
+    case GL_LUMINANCE:
+      setColor(adjusted_color[0], 0, 0, 0, expected_color);
+      setColor(1, 0, 0, 0, mask);
+      break;
+    case GL_LUMINANCE_ALPHA:
+      setColor(adjusted_color[0], 0, 0, adjusted_color[3], expected_color);
+      setColor(1, 0, 0, 1, mask);
+      break;
+    case GL_RG8:
+    case GL_RG16F:
+    case GL_RG32F:
+    case GL_RG8UI:
+      setColor(adjusted_color[0], adjusted_color[1], 0, 0, expected_color);
+      setColor(1, 1, 0, 0, mask);
+      break;
+    case GL_RGB:
+    case GL_RGB8:
+    case GL_SRGB_EXT:
+    case GL_SRGB8:
+    case GL_RGB565:
+    case GL_R11F_G11F_B10F:
+    case GL_RGB9_E5:
+    case GL_RGB16F:
+    case GL_RGB32F:
+    case GL_RGB8UI:
+      setColor(adjusted_color[0], adjusted_color[1], adjusted_color[2], 0,
+               expected_color);
+      setColor(1, 1, 1, 0, mask);
+      break;
+    case GL_RGBA:
+    case GL_RGBA8:
+    case GL_BGRA_EXT:
+    case GL_BGRA8_EXT:
+    case GL_SRGB_ALPHA_EXT:
+    case GL_SRGB8_ALPHA8:
+    case GL_RGBA4:
+    case GL_RGBA16F:
+    case GL_RGBA32F:
+    case GL_RGBA8UI:
+      setColor(adjusted_color[0], adjusted_color[1], adjusted_color[2],
+               adjusted_color[3], expected_color);
+      setColor(1, 1, 1, 1, mask);
+      break;
+    case GL_RGB5_A1:
+      setColor(adjusted_color[0], adjusted_color[1], adjusted_color[2],
+               (adjusted_color[3] >> 7) ? 0xFF : 0x0, expected_color);
+      // TODO(qiankun.miao@intel.com): On some Windows platforms, the alpha
+      // channel of expected color is the source alpha value other than 255.
+      // This should be wrong. Skip the alpha channel check and revisit this in
+      // future.
+      setColor(1, 1, 1, 0, mask);
+      break;
+    default:
+      NOTREACHED();
+      break;
+  }
+}
+
+}  // namespace
+
 // A collection of tests that exercise the GL_CHROMIUM_copy_texture extension.
 class GLCopyTextureCHROMIUMTest
     : public testing::Test,
@@ -92,10 +250,61 @@
   GLuint framebuffer_id_;
 };
 
+class GLCopyTextureCHROMIUMES3Test : public GLCopyTextureCHROMIUMTest {
+ protected:
+  void SetUp() override {
+    GLManager::Options options;
+    options.context_type = gles2::CONTEXT_TYPE_OPENGLES3;
+    options.size = gfx::Size(64, 64);
+    gl_.Initialize(options);
+  }
+
+  void TearDown() override { gl_.Destroy(); }
+
+  // If a driver isn't capable of supporting ES3 context, creating
+  // ContextGroup will fail. Just skip the test.
+  bool ShouldSkipTest() const {
+    return (!gl_.decoder() || !gl_.decoder()->GetContextGroup());
+  }
+
+  // RGB9_E5 isn't accepted by glCopyTexImage2D if underlying context is ES.
+  // TODO(qiankun.miao@intel.com): we should support RGB9_E5 in ES context.
+  // Maybe, we can add a readback path for RGB9_E5 format in ES context.
+  bool ShouldSkipRGB9_E5() const {
+    DCHECK(!ShouldSkipTest());
+    const gl::GLVersionInfo& gl_version_info =
+        gl_.decoder()->GetFeatureInfo()->gl_version_info();
+    return gl_version_info.is_es;
+  }
+
+  // If EXT_color_buffer_float isn't available, float format isn't supported.
+  bool ShouldSkipFloatFormat() const {
+    DCHECK(!ShouldSkipTest());
+    return !gl_.decoder()->GetFeatureInfo()->ext_color_buffer_float_available();
+  }
+
+  bool ShouldSkipBGRA() const {
+    DCHECK(!ShouldSkipTest());
+    return !gl_.decoder()
+                ->GetFeatureInfo()
+                ->feature_flags()
+                .ext_texture_format_bgra8888;
+  }
+
+  bool ShouldSkipSRGBEXT() const {
+    DCHECK(!ShouldSkipTest());
+    return !gl_.decoder()->GetFeatureInfo()->feature_flags().ext_srgb;
+  }
+};
+
 INSTANTIATE_TEST_CASE_P(CopyType,
                         GLCopyTextureCHROMIUMTest,
                         ::testing::ValuesIn(kCopyTypes));
 
+INSTANTIATE_TEST_CASE_P(CopyType,
+                        GLCopyTextureCHROMIUMES3Test,
+                        ::testing::ValuesIn(kCopyTypes));
+
 // Test to ensure that the basic functionality of the extension works.
 TEST_P(GLCopyTextureCHROMIUMTest, Basic) {
   CopyType copy_type = GetParam();
@@ -132,6 +341,207 @@
   EXPECT_TRUE(GL_NO_ERROR == glGetError());
 }
 
+TEST_P(GLCopyTextureCHROMIUMES3Test, FormatCombinations) {
+  if (ShouldSkipTest())
+    return;
+  CopyType copy_type = GetParam();
+
+  struct FormatType {
+    GLenum internal_format;
+    GLenum format;
+    GLenum type;
+  };
+
+  FormatType src_format_types[] = {
+      {GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE},
+      {GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE},
+      {GL_RGB, GL_RGB, GL_UNSIGNED_BYTE},
+      {GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE},
+      {GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE},
+      {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE},
+      {GL_BGRA_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE},
+      {GL_BGRA8_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE},
+  };
+
+  FormatType dest_format_types[] = {
+      // TODO(qiankun.miao@intel.com): ALPHA and LUMINANCE formats have bug on
+      // GL core profile. See crbug.com/577144. Enable these formats after
+      // using workaround in gles2_cmd_copy_tex_image.cc.
+      // {GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE},
+      // {GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE},
+      // {GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE},
+
+      {GL_RGB, GL_RGB, GL_UNSIGNED_BYTE},
+      {GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE},
+      {GL_SRGB_EXT, GL_SRGB_EXT, GL_UNSIGNED_BYTE},
+      {GL_SRGB_ALPHA_EXT, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE},
+      {GL_BGRA_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE},
+      {GL_BGRA8_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE},
+      {GL_R8, GL_RED, GL_UNSIGNED_BYTE},
+      {GL_R16F, GL_RED, GL_HALF_FLOAT},
+      {GL_R16F, GL_RED, GL_FLOAT},
+      {GL_R32F, GL_RED, GL_FLOAT},
+      {GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE},
+      {GL_RG8, GL_RG, GL_UNSIGNED_BYTE},
+      {GL_RG16F, GL_RG, GL_HALF_FLOAT},
+      {GL_RG16F, GL_RG, GL_FLOAT},
+      {GL_RG32F, GL_RG, GL_FLOAT},
+      {GL_RG8UI, GL_RG_INTEGER, GL_UNSIGNED_BYTE},
+      {GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE},
+      {GL_SRGB8, GL_RGB, GL_UNSIGNED_BYTE},
+      {GL_RGB565, GL_RGB, GL_UNSIGNED_BYTE},
+      {GL_R11F_G11F_B10F, GL_RGB, GL_FLOAT},
+      {GL_RGB9_E5, GL_RGB, GL_HALF_FLOAT},
+      {GL_RGB9_E5, GL_RGB, GL_FLOAT},
+      {GL_RGB16F, GL_RGB, GL_HALF_FLOAT},
+      {GL_RGB16F, GL_RGB, GL_FLOAT},
+      {GL_RGB32F, GL_RGB, GL_FLOAT},
+      {GL_RGB8UI, GL_RGB_INTEGER, GL_UNSIGNED_BYTE},
+      {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE},
+      {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE},
+      {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_BYTE},
+      {GL_RGBA4, GL_RGBA, GL_UNSIGNED_BYTE},
+      {GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT},
+      {GL_RGBA16F, GL_RGBA, GL_FLOAT},
+      {GL_RGBA32F, GL_RGBA, GL_FLOAT},
+      {GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE},
+  };
+
+  for (auto src_format_type : src_format_types) {
+    for (auto dest_format_type : dest_format_types) {
+      if (dest_format_type.internal_format == GL_RGB9_E5 && ShouldSkipRGB9_E5())
+        continue;
+      if ((src_format_type.internal_format == GL_BGRA_EXT ||
+           src_format_type.internal_format == GL_BGRA8_EXT ||
+           dest_format_type.internal_format == GL_BGRA_EXT ||
+           dest_format_type.internal_format == GL_BGRA8_EXT) &&
+          ShouldSkipBGRA()) {
+        continue;
+      }
+      if (gles2::GLES2Util::IsFloatFormat(dest_format_type.internal_format) &&
+          ShouldSkipFloatFormat())
+        continue;
+      if ((dest_format_type.internal_format == GL_SRGB_EXT ||
+           dest_format_type.internal_format == GL_SRGB_ALPHA_EXT) &&
+          ShouldSkipSRGBEXT())
+        continue;
+
+      const GLsizei kWidth = 8, kHeight = 8;
+      const int src_channel_count = gles2::GLES2Util::ElementsPerGroup(
+          src_format_type.format, src_format_type.type);
+      uint8_t color[4] = {1, 63, 127, 255};
+      uint8_t pixels[8 * 8 * 4];
+      for (int i = 0; i < kWidth * kHeight * src_channel_count;
+           i += src_channel_count)
+        for (int j = 0; j < src_channel_count; ++j)
+          pixels[i + j] = color[j];
+      uint8_t expected_color[4];
+      uint8_t mask[4];
+      getExpectedColor(src_format_type.internal_format,
+                       dest_format_type.internal_format, color, expected_color,
+                       mask);
+
+      CreateAndBindDestinationTextureAndFBO(GL_TEXTURE_2D);
+      glBindTexture(GL_TEXTURE_2D, textures_[0]);
+      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+      glTexImage2D(GL_TEXTURE_2D, 0, src_format_type.internal_format, kWidth,
+                   kHeight, 0, src_format_type.format, src_format_type.type,
+                   pixels);
+
+      EXPECT_TRUE(glGetError() == GL_NO_ERROR);
+      if (copy_type == TexImage) {
+        glCopyTextureCHROMIUM(textures_[0], textures_[1],
+                              dest_format_type.internal_format,
+                              dest_format_type.type, false, false, false);
+      } else {
+        glBindTexture(GL_TEXTURE_2D, textures_[1]);
+        glTexImage2D(GL_TEXTURE_2D, 0, dest_format_type.internal_format, kWidth,
+                     kHeight, 0, dest_format_type.format, dest_format_type.type,
+                     nullptr);
+
+        glCopySubTextureCHROMIUM(textures_[0], textures_[1], 0, 0, 0, 0, kWidth,
+                                 kHeight, false, false, false);
+      }
+      EXPECT_TRUE(glGetError() == GL_NO_ERROR)
+          << " src_internal_format: "
+          << gles2::GLES2Util::GetStringEnum(src_format_type.internal_format)
+          << " dest_internal_format: "
+          << gles2::GLES2Util::GetStringEnum(dest_format_type.internal_format);
+
+      // Draw destination texture to a fbo with attachment in RGBA format.
+      glBindFramebuffer(GL_FRAMEBUFFER, 0);
+      GLuint framebuffer = 0;
+      glGenFramebuffers(1, &framebuffer);
+      glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
+      GLuint texture = 0;
+      glGenTextures(1, &texture);
+      glBindTexture(GL_TEXTURE_2D, texture);
+      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+      CreateBackingForTexture(GL_TEXTURE_2D, kWidth, kHeight);
+      glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                             GL_TEXTURE_2D, texture, 0);
+      EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
+                glCheckFramebufferStatus(GL_FRAMEBUFFER));
+      glViewport(0, 0, kWidth, kHeight);
+
+      std::string fragment_shader_source =
+          GetFragmentShaderSource(dest_format_type.internal_format);
+      GLuint program = GLTestHelper::LoadProgram(
+          kSimpleVertexShaderES3, fragment_shader_source.c_str());
+      EXPECT_NE(program, 0u);
+      GLint position_loc = glGetAttribLocation(program, "a_position");
+      GLint texture_loc = glGetUniformLocation(program, "u_texture");
+      ASSERT_NE(position_loc, -1);
+      ASSERT_NE(texture_loc, -1);
+      glUseProgram(program);
+
+      GLuint vbo = GLTestHelper::SetupUnitQuad(position_loc);
+      ASSERT_NE(vbo, 0u);
+
+      glActiveTexture(GL_TEXTURE0);
+      glBindTexture(GL_TEXTURE_2D, textures_[1]);
+
+      glDrawArrays(GL_TRIANGLES, 0, 6);
+
+      EXPECT_TRUE(GL_NO_ERROR == glGetError());
+
+      GLsizei size = kWidth * kHeight * 4;
+      std::unique_ptr<uint8_t[]> result(new uint8_t[size]);
+      glReadPixels(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE,
+                   result.get());
+      uint8_t tolerance = dest_format_type.internal_format == GL_RGBA4 ? 20 : 7;
+      for (GLint yy = 0; yy < kHeight; ++yy) {
+        for (GLint xx = 0; xx < kWidth; ++xx) {
+          int offset = yy * kWidth * 4 + xx * 4;
+          for (int jj = 0; jj < 4; ++jj) {
+            uint8_t actual = result[offset + jj];
+            uint8_t expected = expected_color[jj];
+            int diff = actual - expected;
+            diff = diff < 0 ? -diff : diff;
+            if (mask[jj] && diff > tolerance) {
+              EXPECT_EQ(expected, actual)
+                  << " at " << xx << ", " << yy << " channel " << jj
+                  << " src_internal_format: "
+                  << gles2::GLES2Util::GetStringEnum(
+                         src_format_type.internal_format)
+                  << " dest_internal_format: "
+                  << gles2::GLES2Util::GetStringEnum(
+                         dest_format_type.internal_format);
+            }
+          }
+        }
+      }
+
+      glDeleteTextures(1, &texture);
+      glDeleteFramebuffers(1, &framebuffer);
+      glDeleteTextures(2, textures_);
+      glDeleteFramebuffers(1, &framebuffer_id_);
+    }
+  }
+}
+
 TEST_P(GLCopyTextureCHROMIUMTest, ImmutableTexture) {
   if (!GLTestHelper::HasExtension("GL_EXT_texture_storage")) {
     LOG(INFO) << "GL_EXT_texture_storage not supported. Skipping test...";
@@ -230,8 +640,7 @@
   EXPECT_TRUE(GL_NO_ERROR == glGetError());
 
   // Check unsupported format reports error.
-  GLint unsupported_dest_formats[] = {GL_ALPHA, GL_LUMINANCE,
-                                      GL_LUMINANCE_ALPHA};
+  GLint unsupported_dest_formats[] = {GL_RED, GL_RG};
   for (size_t dest_index = 0; dest_index < arraysize(unsupported_dest_formats);
        dest_index++) {
     if (copy_type == TexImage) {
diff --git a/media/base/media_observer.h b/media/base/media_observer.h
index ce81e3b..3135781 100644
--- a/media/base/media_observer.h
+++ b/media/base/media_observer.h
@@ -36,6 +36,10 @@
   // "disableRemotePlayback" media element attribute, as described in the
   // Remote Playback API spec: https://w3c.github.io/remote-playback
   virtual void OnRemotePlaybackDisabled(bool disabled) = 0;
+
+  // Called when the media is playing/paused.
+  virtual void OnPlaying() = 0;
+  virtual void OnPaused() = 0;
 };
 
 }  // namespace media
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index 0499c98..654ba89 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -423,6 +423,9 @@
   if (data_source_)
     data_source_->MediaIsPlaying();
 
+  if (observer_)
+    observer_->OnPlaying();
+
   DCHECK(watch_time_reporter_);
   watch_time_reporter_->OnPlaying();
   media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY));
@@ -454,6 +457,9 @@
   paused_time_ =
       ended_ ? pipeline_.GetMediaDuration() : pipeline_.GetMediaTime();
 
+  if (observer_)
+    observer_->OnPaused();
+
   DCHECK(watch_time_reporter_);
   watch_time_reporter_->OnPaused();
   media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE));
diff --git a/media/gpu/vaapi_video_decode_accelerator.cc b/media/gpu/vaapi_video_decode_accelerator.cc
index 755e9ab..a119f0f 100644
--- a/media/gpu/vaapi_video_decode_accelerator.cc
+++ b/media/gpu/vaapi_video_decode_accelerator.cc
@@ -1734,11 +1734,8 @@
     const Vp9LoopFilterParams& lf,
     const std::vector<scoped_refptr<VP9Picture>>& ref_pictures,
     const base::Closure& done_cb) {
-  // TODO(posciak): We don't currently have the ability to know when the surface
-  // is decoded, as we submit both the decode job and output independently and
-  // don't wait for just the decode to be finished, instead relying on the
-  // driver to execute them in correct order.
-  DCHECK(!done_cb.is_null());
+  // |done_cb| should be null as we return false from IsFrameContextRequired().
+  DCHECK(done_cb.is_null());
 
   VADecPictureParameterBufferVP9 pic_param;
   memset(&pic_param, 0, sizeof(pic_param));
diff --git a/media/remoting/remoting_renderer_controller.cc b/media/remoting/remoting_renderer_controller.cc
index 40506d82..c58c17a 100644
--- a/media/remoting/remoting_renderer_controller.cc
+++ b/media/remoting/remoting_renderer_controller.cc
@@ -204,6 +204,19 @@
   }
 }
 
+void RemotingRendererController::OnPlaying() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  is_paused_ = false;
+  UpdateAndMaybeSwitch();
+}
+
+void RemotingRendererController::OnPaused() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  is_paused_ = true;
+}
+
 bool RemotingRendererController::ShouldBeRemoting() {
   DCHECK(thread_checker_.CalledOnValidThread());
 
@@ -265,6 +278,13 @@
   if (remote_rendering_started_ == should_be_remoting)
     return;
 
+  // Only switch to remoting when media is playing. Since the renderer is
+  // created when video starts loading/playing, receiver will display a black
+  // screen before video starts playing if switching to remoting when paused.
+  // Keep mirroring the video in this case is good for the user experience.
+  if (should_be_remoting && is_paused_)
+    return;
+
   // Switch between local renderer and remoting renderer.
   remote_rendering_started_ = should_be_remoting;
 
diff --git a/media/remoting/remoting_renderer_controller.h b/media/remoting/remoting_renderer_controller.h
index 6d31513..c3a35bd 100644
--- a/media/remoting/remoting_renderer_controller.h
+++ b/media/remoting/remoting_renderer_controller.h
@@ -39,6 +39,8 @@
   void OnSetCdm(CdmContext* cdm_context) override;
   void OnMetadataChanged(const PipelineMetadata& metadata) override;
   void OnRemotePlaybackDisabled(bool disabled) override;
+  void OnPlaying() override;
+  void OnPaused() override;
 
   void SetSwitchRendererCallback(const base::Closure& cb);
   void SetRemoteSinkAvailableChangedCallback(
@@ -120,6 +122,9 @@
   // Indicates whether video is the dominant visible content in the tab.
   bool is_dominant_content_ = false;
 
+  // Indicates whether video is paused.
+  bool is_paused_ = true;
+
   // The callback to switch the media renderer.
   base::Closure switch_renderer_cb_;
 
diff --git a/media/remoting/remoting_renderer_controller_unittest.cc b/media/remoting/remoting_renderer_controller_unittest.cc
index b22e67d..23a052ff 100644
--- a/media/remoting/remoting_renderer_controller_unittest.cc
+++ b/media/remoting/remoting_renderer_controller_unittest.cc
@@ -90,6 +90,9 @@
   EXPECT_FALSE(is_rendering_remotely_);
   remoting_renderer_controller_->OnRemotePlaybackDisabled(false);
   RunUntilIdle();
+  EXPECT_FALSE(is_rendering_remotely_);
+  remoting_renderer_controller_->OnPlaying();
+  RunUntilIdle();
   EXPECT_TRUE(is_rendering_remotely_);  // All requirements now satisfied.
 
   // Leaving fullscreen should shut down remoting.
@@ -114,6 +117,9 @@
   remoting_renderer_controller_->OnRemotePlaybackDisabled(false);
   RunUntilIdle();
   EXPECT_FALSE(is_rendering_remotely_);
+  remoting_renderer_controller_->OnPlaying();
+  RunUntilIdle();
+  EXPECT_FALSE(is_rendering_remotely_);
   remoting_renderer_controller_->OnEnteredFullscreen();
   RunUntilIdle();
   EXPECT_FALSE(is_rendering_remotely_);
@@ -159,6 +165,9 @@
   EXPECT_FALSE(is_rendering_remotely_);
   remoting_renderer_controller_->OnRemotePlaybackDisabled(false);
   RunUntilIdle();
+  EXPECT_FALSE(is_rendering_remotely_);
+  remoting_renderer_controller_->OnPlaying();
+  RunUntilIdle();
   EXPECT_TRUE(is_rendering_remotely_);  // All requirements now satisfied.
 
   // If the page disables remote playback (e.g., by setting the
@@ -190,6 +199,9 @@
   remoting_renderer_controller_->OnRemotePlaybackDisabled(false);
   RunUntilIdle();
   EXPECT_FALSE(is_rendering_remotely_);
+  remoting_renderer_controller_->OnPlaying();
+  RunUntilIdle();
+  EXPECT_FALSE(is_rendering_remotely_);
 }
 
 TEST_F(RemotingRendererControllerTest, EncryptedWithRemotingCdm) {
@@ -202,6 +214,7 @@
   EXPECT_FALSE(is_rendering_remotely_);
   remoting_renderer_controller_->OnMetadataChanged(EncryptedMetadata());
   remoting_renderer_controller_->OnRemotePlaybackDisabled(false);
+  remoting_renderer_controller_->OnPlaying();
   RunUntilIdle();
   EXPECT_FALSE(is_rendering_remotely_);
   scoped_refptr<RemotingSourceImpl> cdm_remoting_source_impl =
@@ -267,6 +280,9 @@
   remoting_renderer_controller_->OnRemotePlaybackDisabled(false);
   RunUntilIdle();
   EXPECT_FALSE(is_rendering_remotely_);
+  remoting_renderer_controller_->OnPlaying();
+  RunUntilIdle();
+  EXPECT_FALSE(is_rendering_remotely_);
 
   scoped_refptr<RemotingSourceImpl> cdm_remoting_source_impl =
       CreateRemotingSourceImpl(true);
@@ -297,6 +313,9 @@
   remoting_renderer_controller_->OnRemotePlaybackDisabled(false);
   RunUntilIdle();
   EXPECT_FALSE(is_rendering_remotely_);
+  remoting_renderer_controller_->OnPlaying();
+  RunUntilIdle();
+  EXPECT_FALSE(is_rendering_remotely_);
 
   scoped_refptr<RemotingSourceImpl> cdm_remoting_source_impl =
       CreateRemotingSourceImpl(false);
diff --git a/net/test/url_request/url_request_mock_http_job.cc b/net/test/url_request/url_request_mock_http_job.cc
index 5317b84..7fdcfaaf 100644
--- a/net/test/url_request/url_request_mock_http_job.cc
+++ b/net/test/url_request/url_request_mock_http_job.cc
@@ -184,6 +184,7 @@
   // ParseRawHeaders expects \0 to end each header line.
   base::ReplaceSubstringsAfterOffset(
       &raw_headers_, 0, "\n", base::StringPiece("\0", 1));
+  total_received_bytes_ += raw_headers_.size();
   URLRequestFileJob::Start();
 }
 
diff --git a/remoting/host/BUILD.gn b/remoting/host/BUILD.gn
index d066858..6a09a0c 100644
--- a/remoting/host/BUILD.gn
+++ b/remoting/host/BUILD.gn
@@ -200,8 +200,6 @@
     "ipc_mouse_cursor_monitor.h",
     "ipc_screen_controls.cc",
     "ipc_screen_controls.h",
-    "ipc_util.h",
-    "ipc_util_win.cc",
     "ipc_video_frame_capturer.cc",
     "ipc_video_frame_capturer.h",
     "it2me_desktop_environment.cc",
diff --git a/remoting/host/desktop_session_agent.cc b/remoting/host/desktop_session_agent.cc
index 43862d1..94af3be 100644
--- a/remoting/host/desktop_session_agent.cc
+++ b/remoting/host/desktop_session_agent.cc
@@ -22,7 +22,6 @@
 #include "remoting/host/chromoting_messages.h"
 #include "remoting/host/desktop_environment.h"
 #include "remoting/host/input_injector.h"
-#include "remoting/host/ipc_util.h"
 #include "remoting/host/remote_input_filter.h"
 #include "remoting/host/screen_controls.h"
 #include "remoting/host/screen_resolution.h"
diff --git a/remoting/host/ipc_util.h b/remoting/host/ipc_util.h
deleted file mode 100644
index 17b7c71..0000000
--- a/remoting/host/ipc_util.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef REMOTING_HOST_IPC_UTIL_H_
-#define REMOTING_HOST_IPC_UTIL_H_
-
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "build/build_config.h"
-
-#if defined(OS_WIN)
-#include "base/win/scoped_handle.h"
-#endif  // defined(OS_WIN)
-
-namespace remoting {
-
-#if defined(OS_WIN)
-
-// Creates the server end of the IPC channel and applies the security
-// descriptor |pipe_security_descriptor| to it.
-bool CreateIpcChannel(
-    const std::string& channel_name,
-    const std::string& pipe_security_descriptor,
-    base::win::ScopedHandle* pipe_out);
-
-#endif  // defined(OS_WIN)
-
-} // namespace remoting
-
-#endif  // REMOTING_HOST_IPC_UTIL_H_
diff --git a/remoting/host/ipc_util_win.cc b/remoting/host/ipc_util_win.cc
deleted file mode 100644
index a70b528..0000000
--- a/remoting/host/ipc_util_win.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "remoting/host/ipc_util.h"
-
-#include <utility>
-
-#include "base/logging.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/win/scoped_handle.h"
-#include "base/win/win_util.h"
-#include "ipc/ipc_channel.h"
-#include "remoting/host/win/security_descriptor.h"
-
-namespace remoting {
-
-// Pipe name prefix used by Chrome IPC channels to convert a channel name into
-// a pipe name.
-const char kChromePipeNamePrefix[] = "\\\\.\\pipe\\chrome.";
-
-bool CreateIpcChannel(
-    const std::string& channel_name,
-    const std::string& pipe_security_descriptor,
-    base::win::ScopedHandle* pipe_out) {
-  // Create security descriptor for the channel.
-  ScopedSd sd = ConvertSddlToSd(pipe_security_descriptor);
-  if (!sd) {
-    PLOG(ERROR) << "Failed to create a security descriptor for the Chromoting "
-                   "IPC channel";
-    return false;
-  }
-
-  SECURITY_ATTRIBUTES security_attributes = {0};
-  security_attributes.nLength = sizeof(security_attributes);
-  security_attributes.lpSecurityDescriptor = sd.get();
-  security_attributes.bInheritHandle = FALSE;
-
-  // Convert the channel name to the pipe name.
-  std::string pipe_name(kChromePipeNamePrefix);
-  pipe_name.append(channel_name);
-
-  // Create the server end of the pipe. This code should match the code in
-  // IPC::Channel with exception of passing a non-default security descriptor.
-  base::win::ScopedHandle pipe;
-  pipe.Set(CreateNamedPipe(
-      base::UTF8ToUTF16(pipe_name).c_str(),
-      PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE,
-      PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
-      1,
-      IPC::Channel::kReadBufferSize,
-      IPC::Channel::kReadBufferSize,
-      5000,
-      &security_attributes));
-  if (!pipe.IsValid()) {
-    PLOG(ERROR)
-        << "Failed to create the server end of the Chromoting IPC channel";
-    return false;
-  }
-
-  *pipe_out = std::move(pipe);
-  return true;
-}
-
-} // namespace remoting
diff --git a/remoting/host/security_key/security_key_auth_handler_win.cc b/remoting/host/security_key/security_key_auth_handler_win.cc
index e8b93b0..55d72fe 100644
--- a/remoting/host/security_key/security_key_auth_handler_win.cc
+++ b/remoting/host/security_key/security_key_auth_handler_win.cc
@@ -27,7 +27,6 @@
 #include "remoting/base/logging.h"
 #include "remoting/host/chromoting_messages.h"
 #include "remoting/host/client_session_details.h"
-#include "remoting/host/ipc_util.h"
 #include "remoting/host/security_key/security_key_ipc_constants.h"
 #include "remoting/host/security_key/security_key_ipc_server.h"
 
diff --git a/remoting/host/security_key/security_key_ipc_server_impl.cc b/remoting/host/security_key/security_key_ipc_server_impl.cc
index e051a26..b412991 100644
--- a/remoting/host/security_key/security_key_ipc_server_impl.cc
+++ b/remoting/host/security_key/security_key_ipc_server_impl.cc
@@ -29,7 +29,6 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/win/win_util.h"
-#include "remoting/host/ipc_util.h"
 #endif  // defined(OS_WIN)
 
 namespace {
diff --git a/services/ui/public/cpp/BUILD.gn b/services/ui/public/cpp/BUILD.gn
index bb3e590a..0830bc8a 100644
--- a/services/ui/public/cpp/BUILD.gn
+++ b/services/ui/public/cpp/BUILD.gn
@@ -8,7 +8,6 @@
 # implementation (and private haders) are in 'internal'.
 source_set("cpp") {
   sources = [
-    "context_provider.h",
     "input_event_handler.h",
     "property_type_converters.h",
     "raster_thread_helper.h",
@@ -31,11 +30,7 @@
     "//cc",
     "//cc/surfaces",
     "//cc/surfaces:surface_id",
-    "//gpu/command_buffer/client",
-    "//gpu/command_buffer/client:gles2_implementation",
-    "//gpu/command_buffer/common",
     "//mojo/public/cpp/bindings",
-    "//mojo/public/cpp/system",
     "//services/service_manager/public/interfaces",
     "//services/ui/common:mus_common",
     "//services/ui/public/cpp/gpu",
@@ -93,9 +88,6 @@
   ]
 
   sources = [
-    "context_provider.cc",
-    "gles2_context.cc",
-    "gles2_context.h",
     "in_flight_change.cc",
     "in_flight_change.h",
     "property_type_converters.cc",
@@ -117,14 +109,7 @@
     "//cc",
     "//cc/surfaces",
     "//cc/surfaces:surface_id",
-    "//gpu/command_buffer/client",
-    "//gpu/command_buffer/client:gles2_cmd_helper",
-    "//gpu/command_buffer/client:gles2_implementation",
-    "//gpu/command_buffer/client:gles2_interface",
-    "//gpu/command_buffer/common",
-    "//gpu/ipc/client",
     "//mojo/public/cpp/bindings",
-    "//mojo/public/cpp/system",
     "//services/service_manager/public/cpp",
     "//services/service_manager/public/interfaces",
     "//services/ui/common:mus_common",
diff --git a/services/ui/public/cpp/context_provider.cc b/services/ui/public/cpp/context_provider.cc
deleted file mode 100644
index 29908d8..0000000
--- a/services/ui/public/cpp/context_provider.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "services/ui/public/cpp/context_provider.h"
-
-#include <stdint.h>
-
-#include "base/logging.h"
-#include "cc/output/context_cache_controller.h"
-#include "gpu/ipc/client/gpu_channel_host.h"
-#include "services/ui/public/cpp/gles2_context.h"
-
-namespace ui {
-
-ContextProvider::ContextProvider(
-    scoped_refptr<gpu::GpuChannelHost> gpu_channel_host)
-    : gpu_channel_host_(std::move(gpu_channel_host)) {}
-
-bool ContextProvider::BindToCurrentThread() {
-  context_ = GLES2Context::CreateOffscreenContext(
-      gpu_channel_host_, base::ThreadTaskRunnerHandle::Get());
-  if (context_) {
-    cache_controller_.reset(new cc::ContextCacheController(
-        context_->context_support(), base::ThreadTaskRunnerHandle::Get()));
-  }
-  return !!context_;
-}
-
-gpu::gles2::GLES2Interface* ContextProvider::ContextGL() {
-  return context_->interface();
-}
-
-gpu::ContextSupport* ContextProvider::ContextSupport() {
-  if (!context_)
-    return NULL;
-  return context_->context_support();
-}
-
-class GrContext* ContextProvider::GrContext() {
-  return NULL;
-}
-
-cc::ContextCacheController* ContextProvider::CacheController() {
-  return cache_controller_.get();
-}
-
-void ContextProvider::InvalidateGrContext(uint32_t state) {}
-
-gpu::Capabilities ContextProvider::ContextCapabilities() {
-  return gpu::Capabilities();
-}
-
-base::Lock* ContextProvider::GetLock() {
-  // This context provider is not used on multiple threads.
-  NOTREACHED();
-  return nullptr;
-}
-
-ContextProvider::~ContextProvider() {
-}
-
-}  // namespace ui
diff --git a/services/ui/public/cpp/context_provider.h b/services/ui/public/cpp/context_provider.h
deleted file mode 100644
index 348d7cd..0000000
--- a/services/ui/public/cpp/context_provider.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SERVICES_UI_PUBLIC_CPP_CONTEXT_PROVIDER_H_
-#define SERVICES_UI_PUBLIC_CPP_CONTEXT_PROVIDER_H_
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/macros.h"
-#include "cc/output/context_provider.h"
-#include "mojo/public/cpp/system/core.h"
-
-namespace gpu {
-class GpuChannelHost;
-}
-
-namespace ui {
-
-class GLES2Context;
-
-class ContextProvider : public cc::ContextProvider {
- public:
-  explicit ContextProvider(scoped_refptr<gpu::GpuChannelHost> gpu_channel_host);
-
-  // cc::ContextProvider implementation.
-  bool BindToCurrentThread() override;
-  gpu::gles2::GLES2Interface* ContextGL() override;
-  gpu::ContextSupport* ContextSupport() override;
-  class GrContext* GrContext() override;
-  cc::ContextCacheController* CacheController() override;
-  void InvalidateGrContext(uint32_t state) override;
-  base::Lock* GetLock() override;
-  gpu::Capabilities ContextCapabilities() override;
-  void SetLostContextCallback(
-      const LostContextCallback& lost_context_callback) override {}
-
- protected:
-  friend class base::RefCountedThreadSafe<ContextProvider>;
-  ~ContextProvider() override;
-
- private:
-  std::unique_ptr<GLES2Context> context_;
-  std::unique_ptr<cc::ContextCacheController> cache_controller_;
-  scoped_refptr<gpu::GpuChannelHost> gpu_channel_host_;
-
-  DISALLOW_COPY_AND_ASSIGN(ContextProvider);
-};
-
-}  // namespace ui
-
-#endif  // SERVICES_UI_PUBLIC_CPP_CONTEXT_PROVIDER_H_
diff --git a/services/ui/public/cpp/gles2_context.cc b/services/ui/public/cpp/gles2_context.cc
deleted file mode 100644
index 9ff0477..0000000
--- a/services/ui/public/cpp/gles2_context.cc
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "services/ui/public/cpp/gles2_context.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <utility>
-
-#include "gpu/command_buffer/client/gles2_cmd_helper.h"
-#include "gpu/command_buffer/client/shared_memory_limits.h"
-#include "gpu/command_buffer/client/transfer_buffer.h"
-#include "gpu/ipc/client/command_buffer_proxy_impl.h"
-#include "gpu/ipc/client/gpu_channel_host.h"
-#include "mojo/public/cpp/system/core.h"
-#include "url/gurl.h"
-
-namespace ui {
-
-GLES2Context::GLES2Context() {}
-
-GLES2Context::~GLES2Context() {}
-
-bool GLES2Context::Initialize(
-    scoped_refptr<gpu::GpuChannelHost> gpu_channel_host,
-    scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
-  DCHECK(gpu_channel_host);
-  gpu::SurfaceHandle surface_handle = gfx::kNullAcceleratedWidget;
-  // TODO(penghuang): support shared group.
-  gpu::CommandBufferProxyImpl* shared_command_buffer = nullptr;
-  gpu::GpuStreamId stream_id = gpu::GpuStreamId::GPU_STREAM_DEFAULT;
-  gpu::GpuStreamPriority stream_priority = gpu::GpuStreamPriority::NORMAL;
-  gpu::gles2::ContextCreationAttribHelper attributes;
-  // TODO(penghuang): figure a useful active_url.
-  GURL active_url;
-  command_buffer_proxy_impl_ = gpu::CommandBufferProxyImpl::Create(
-      std::move(gpu_channel_host), surface_handle, shared_command_buffer,
-      stream_id, stream_priority, attributes, active_url,
-      std::move(task_runner));
-  if (!command_buffer_proxy_impl_)
-    return false;
-  gpu::CommandBuffer* command_buffer = command_buffer_proxy_impl_.get();
-  gpu::GpuControl* gpu_control = command_buffer_proxy_impl_.get();
-
-  constexpr gpu::SharedMemoryLimits default_limits;
-  gles2_helper_.reset(new gpu::gles2::GLES2CmdHelper(command_buffer));
-  if (!gles2_helper_->Initialize(default_limits.command_buffer_size))
-    return false;
-  gles2_helper_->SetAutomaticFlushes(false);
-  transfer_buffer_.reset(new gpu::TransferBuffer(gles2_helper_.get()));
-  gpu::Capabilities capabilities = gpu_control->GetCapabilities();
-  bool bind_generates_resource =
-      !!capabilities.bind_generates_resource_chromium;
-  // TODO(piman): Some contexts (such as compositor) want this to be true, so
-  // this needs to be a public parameter.
-  bool lose_context_when_out_of_memory = false;
-  bool support_client_side_arrays = false;
-  implementation_.reset(new gpu::gles2::GLES2Implementation(
-      gles2_helper_.get(), NULL, transfer_buffer_.get(),
-      bind_generates_resource, lose_context_when_out_of_memory,
-      support_client_side_arrays, gpu_control));
-  if (!implementation_->Initialize(default_limits.start_transfer_buffer_size,
-                                   default_limits.min_transfer_buffer_size,
-                                   default_limits.max_transfer_buffer_size,
-                                   default_limits.mapped_memory_reclaim_limit))
-    return false;
-  return true;
-}
-
-// static
-std::unique_ptr<GLES2Context> GLES2Context::CreateOffscreenContext(
-    scoped_refptr<gpu::GpuChannelHost> gpu_channel_host,
-    scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
-  if (!gpu_channel_host)
-    return nullptr;
-
-  // Return the GLES2Context only if it is successfully initialized. If
-  // initialization fails, then return null.
-  std::unique_ptr<GLES2Context> gles2_context(new GLES2Context);
-  if (!gles2_context->Initialize(std::move(gpu_channel_host),
-                                 std::move(task_runner)))
-    gles2_context.reset();
-  return gles2_context;
-}
-
-}  // namespace ui
diff --git a/services/ui/public/cpp/gles2_context.h b/services/ui/public/cpp/gles2_context.h
deleted file mode 100644
index ba0c2c25..0000000
--- a/services/ui/public/cpp/gles2_context.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SERVICES_UI_PUBLIC_CPP_GLES2_CONTEXT_H_
-#define SERVICES_UI_PUBLIC_CPP_GLES2_CONTEXT_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/single_thread_task_runner.h"
-#include "gpu/command_buffer/client/gles2_implementation.h"
-
-namespace gpu {
-
-class CommandBufferProxyImpl;
-class GpuChannelHost;
-class TransferBuffer;
-
-namespace gles2 {
-class GLES2CmdHelper;
-}
-
-}  // namespace gpu
-
-namespace ui {
-
-class GLES2Context {
- public:
-  ~GLES2Context();
-  gpu::gles2::GLES2Interface* interface() const {
-    return implementation_.get();
-  }
-  gpu::ContextSupport* context_support() const { return implementation_.get(); }
-
-  static std::unique_ptr<GLES2Context> CreateOffscreenContext(
-      scoped_refptr<gpu::GpuChannelHost> gpu_channel_host,
-      scoped_refptr<base::SingleThreadTaskRunner> task_runner);
-
- private:
-  GLES2Context();
-  bool Initialize(scoped_refptr<gpu::GpuChannelHost> gpu_channel_host,
-                  scoped_refptr<base::SingleThreadTaskRunner> task_runner);
-
-  std::unique_ptr<gpu::CommandBufferProxyImpl> command_buffer_proxy_impl_;
-  std::unique_ptr<gpu::gles2::GLES2CmdHelper> gles2_helper_;
-  std::unique_ptr<gpu::TransferBuffer> transfer_buffer_;
-  std::unique_ptr<gpu::gles2::GLES2Implementation> implementation_;
-
-  DISALLOW_COPY_AND_ASSIGN(GLES2Context);
-};
-
-}  // namespace ui
-
-#endif  // SERVICES_UI_PUBLIC_CPP_GLES2_CONTEXT_H_
diff --git a/services/ui/public/cpp/gpu/command_buffer_metrics.cc b/services/ui/public/cpp/gpu/command_buffer_metrics.cc
index 2d3505b9..6f9e91d9 100644
--- a/services/ui/public/cpp/gpu/command_buffer_metrics.cc
+++ b/services/ui/public/cpp/gpu/command_buffer_metrics.cc
@@ -120,9 +120,15 @@
     case BLIMP_RENDER_COMPOSITOR_CONTEXT:
       UMA_HISTOGRAM_ENUMERATION("GPU.ContextLost.BlimpRenderCompositor", reason,
                                 CONTEXT_LOST_REASON_MAX_ENUM);
+      break;
     case BLIMP_RENDER_WORKER_CONTEXT:
       UMA_HISTOGRAM_ENUMERATION("GPU.ContextLost.BlimpRenderWorker", reason,
                                 CONTEXT_LOST_REASON_MAX_ENUM);
+      break;
+    case MUS_CLIENT_CONTEXT:
+      UMA_HISTOGRAM_ENUMERATION("GPU.ContextLost.MusClient", reason,
+                                CONTEXT_LOST_REASON_MAX_ENUM);
+      break;
     case CONTEXT_TYPE_UNKNOWN:
       UMA_HISTOGRAM_ENUMERATION("GPU.ContextLost.Unknown", reason,
                                 CONTEXT_LOST_REASON_MAX_ENUM);
@@ -160,6 +166,8 @@
       return "BlimpRenderCompositor";
     case BLIMP_RENDER_WORKER_CONTEXT:
       return "BlimpRenderWorker";
+    case MUS_CLIENT_CONTEXT:
+      return "MusClientContext";
     default:
       NOTREACHED();
       return "unknown";
diff --git a/services/ui/public/cpp/gpu/command_buffer_metrics.h b/services/ui/public/cpp/gpu/command_buffer_metrics.h
index 79ef6053..b11f1b5 100644
--- a/services/ui/public/cpp/gpu/command_buffer_metrics.h
+++ b/services/ui/public/cpp/gpu/command_buffer_metrics.h
@@ -26,6 +26,7 @@
   MEDIA_CONTEXT,
   BLIMP_RENDER_COMPOSITOR_CONTEXT,
   BLIMP_RENDER_WORKER_CONTEXT,
+  MUS_CLIENT_CONTEXT,
   OFFSCREEN_CONTEXT_FOR_TESTING = CONTEXT_TYPE_UNKNOWN,
 };
 
diff --git a/services/ui/public/cpp/gpu/gpu.cc b/services/ui/public/cpp/gpu/gpu.cc
index 4cd0d57..93639cd 100644
--- a/services/ui/public/cpp/gpu/gpu.cc
+++ b/services/ui/public/cpp/gpu/gpu.cc
@@ -10,6 +10,7 @@
 #include "mojo/public/cpp/system/platform_handle.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/ui/public/cpp/gpu/client_gpu_memory_buffer_manager.h"
+#include "services/ui/public/cpp/gpu/context_provider_command_buffer.h"
 #include "services/ui/public/interfaces/constants.mojom.h"
 #include "services/ui/public/interfaces/gpu.mojom.h"
 
@@ -64,6 +65,27 @@
   return base::WrapUnique(new Gpu(nullptr, provider, std::move(task_runner)));
 }
 
+scoped_refptr<cc::ContextProvider> Gpu::CreateContextProvider(
+    scoped_refptr<gpu::GpuChannelHost> gpu_channel) {
+  constexpr bool automatic_flushes = false;
+  constexpr bool support_locking = false;
+  gpu::gles2::ContextCreationAttribHelper attributes;
+  attributes.alpha_size = -1;
+  attributes.depth_size = 0;
+  attributes.stencil_size = 0;
+  attributes.samples = 0;
+  attributes.sample_buffers = 0;
+  attributes.bind_generates_resource = false;
+  attributes.lose_context_when_out_of_memory = true;
+  constexpr ui::ContextProviderCommandBuffer* shared_context_provider = nullptr;
+  return make_scoped_refptr(new ui::ContextProviderCommandBuffer(
+      std::move(gpu_channel), gpu::GPU_STREAM_DEFAULT,
+      gpu::GpuStreamPriority::NORMAL, gpu::kNullSurfaceHandle,
+      GURL("chrome://gpu/MusContextFactory"), automatic_flushes,
+      support_locking, gpu::SharedMemoryLimits(), attributes,
+      shared_context_provider, ui::command_buffer_metrics::MUS_CLIENT_CONTEXT));
+}
+
 void Gpu::EstablishGpuChannel(
     const gpu::GpuChannelEstablishedCallback& callback) {
   DCHECK(IsMainThread());
diff --git a/services/ui/public/cpp/gpu/gpu.h b/services/ui/public/cpp/gpu/gpu.h
index c838668..f99250a 100644
--- a/services/ui/public/cpp/gpu/gpu.h
+++ b/services/ui/public/cpp/gpu/gpu.h
@@ -13,6 +13,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread.h"
+#include "cc/output/context_provider.h"
 #include "gpu/ipc/client/gpu_channel_host.h"
 #include "services/ui/public/cpp/gpu/client_gpu_memory_buffer_manager.h"
 #include "services/ui/public/interfaces/gpu.mojom.h"
@@ -43,6 +44,9 @@
       service_manager::InterfaceProvider*,
       scoped_refptr<base::SingleThreadTaskRunner> task_runner = nullptr);
 
+  scoped_refptr<cc::ContextProvider> CreateContextProvider(
+      scoped_refptr<gpu::GpuChannelHost> gpu_channel);
+
   // gpu::GpuChannelEstablishFactory:
   void EstablishGpuChannel(
       const gpu::GpuChannelEstablishedCallback& callback) override;
@@ -57,7 +61,6 @@
       scoped_refptr<base::SingleThreadTaskRunner> task_runner);
 
   scoped_refptr<gpu::GpuChannelHost> GetGpuChannel();
-  void EstablishGpuChannelOnMainThreadSyncLocked();
   void OnEstablishedGpuChannel(int client_id,
                                mojo::ScopedMessagePipeHandle channel_handle,
                                const gpu::GPUInfo& gpu_info);
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index f8a70dbc..a24375ee 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1934,10 +1934,6 @@
 crbug.com/659917 virtual/mojo-loading/http/tests/xmlhttprequest/workers/xmlhttprequest-response-type-blob-sync.html [ Pass Timeout ]
 crbug.com/659917 virtual/mojo-loading/http/tests/xmlhttprequest/workers/shared-worker-response-type-blob-sync.html [ Pass Timeout ]
 
-crbug.com/669357 virtual/mojo-loading/http/tests/inspector-protocol/network-data-length.html [ Failure ]
-crbug.com/669357 virtual/mojo-loading/http/tests/inspector/network/network-datareceived.html [ Failure ]
-crbug.com/669357 virtual/mojo-loading/http/tests/inspector/tracing/timeline-receive-response-event.html [ Failure ]
-crbug.com/669357 virtual/mojo-loading/http/tests/inspector/tracing/timeline-network-received-data.html [ Failure ]
 crbug.com/669357 virtual/mojo-loading/http/tests/local/formdata/upload-events.html [ Failure ]
 
 crbug.com/664873 http/tests/xmlhttprequest/small-chunks-response-text.html [ Failure Pass ]
@@ -1951,6 +1947,16 @@
 crbug.com/673109 [ Linux Win ] virtual/scalefactor150/fast/hidpi/static/popup-menu-with-scrollbar-appearance.html [ NeedsRebaseline ]
 crbug.com/673109 [ Linux Win Mac ] virtual/scalefactor200/fast/hidpi/static/popup-menu-with-scrollbar-appearance.html [ NeedsRebaseline ]
 crbug.com/673109 [ Linux Win ] virtual/scalefactor200withzoom/fast/hidpi/static/popup-menu-with-scrollbar-appearance.html [ NeedsRebaseline ]
+crbug.com/674663 [ Win ] virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance.html [ NeedsRebaseline ]
+crbug.com/674663 [ Win ] virtual/scalefactor150/fast/hidpi/static/data-suggestion-picker-appearance.html [ NeedsRebaseline ]
+crbug.com/674663 [ Win ] virtual/scalefactor150/fast/hidpi/static/popup-menu-appearance.html [ NeedsRebaseline ]
+crbug.com/674663 [ Win ] virtual/scalefactor200/fast/hidpi/static/calendar-picker-appearance.html [ NeedsRebaseline ]
+crbug.com/674663 [ Win ] virtual/scalefactor200/fast/hidpi/static/data-suggestion-picker-appearance.html [ NeedsRebaseline ]
+crbug.com/674663 [ Win ] virtual/scalefactor200/fast/hidpi/static/popup-menu-appearance.html [ NeedsRebaseline ]
+crbug.com/674663 [ Win ] virtual/scalefactor200withzoom/fast/hidpi/static/calendar-picker-appearance.html [ NeedsRebaseline ]
+crbug.com/674663 [ Win ] virtual/scalefactor200withzoom/fast/hidpi/static/data-suggestion-picker-appearance.html [ NeedsRebaseline ]
+crbug.com/674663 [ Win ] virtual/scalefactor200withzoom/fast/hidpi/static/popup-menu-appearance.html [ NeedsRebaseline ]
+
 
 # Due to a temporal revert these tests are failing:
 crbug.com/666688 fast/css-grid-layout/grid-change-intrinsic-size-with-auto-repeat-tracks.html [ Failure ]
@@ -2235,7 +2241,6 @@
 # Added 2016-12-16
 crbug.com/674858 [ Linux ] virtual/threaded/printing/offscreencanvas-2d-printing.html [ Pass Failure Crash ]
 crbug.com/674858 [ Linux ] virtual/threaded/printing/offscreencanvas-webgl-printing.html [ Pass Failure Crash ]
-crbug.com/675055 [ Trusty Debug ] virtual/android/fullscreen/full-screen-stacking-context.html [ Failure ]
 
 # for Skia DEPS roll
 crbug.com/674509   compositing/overlap-blending/reflection-opacity-huge.html [ NeedsRebaseline ]
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/context_click_select_misspelling.html b/third_party/WebKit/LayoutTests/editing/spelling/context_click_select_misspelling.html
index c1f0486..199edbf 100644
--- a/third_party/WebKit/LayoutTests/editing/spelling/context_click_select_misspelling.html
+++ b/third_party/WebKit/LayoutTests/editing/spelling/context_click_select_misspelling.html
@@ -20,6 +20,7 @@
 add_result_callback(testObj => {
   if (!testObj.properties.blockHeldTest)
     return;
+  testObj.properties.sample.remove();
   if (++heldTest.properties.finishCount === kNumTests)
     heldTest.done();
 });
@@ -85,7 +86,7 @@
             'Context clicking "home" does not select the correctly spelled word');
       },
       'Context clicking misspelled word in INPUT selects the word.',
-      {blockHeldTest: true})
+      {sample: sample, blockHeldTest: true})
     });
 
 spellcheck_test(
@@ -114,7 +115,7 @@
             '');
       },
       'Context clicking misspelled word in editable DIV selects the word.',
-      {blockHeldTest: true})
+      {sample: sample, blockHeldTest: true})
     });
 
 spellcheck_test(
@@ -130,7 +131,7 @@
             'Context clicking "wordl" selects the misspelled word.');
       },
       'Context clicking the second misspelled word "wordl" in editable DIV selects the word.',
-      {blockHeldTest: true})
+      {sample: sample, blockHeldTest: true})
     });
 
 spellcheck_test(
@@ -147,6 +148,6 @@
             'uppercase');
       },
       'Context clicking multi-word misspelling "upper case" in editable DIV selects the words.',
-      {blockHeldTest: true})
+      {sample: sample, blockHeldTest: true})
     });
 </script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/network/network-columns-visible.html b/third_party/WebKit/LayoutTests/http/tests/inspector/network/network-columns-visible.html
index 5012aa2..86cde8e 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/network/network-columns-visible.html
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/network/network-columns-visible.html
@@ -17,6 +17,8 @@
 
     function onNodeInserted(node)
     {
+        if (node.dataGrid !== UI.panels.network._networkLogView._dataGrid)
+            return;
         if (node.request().name() !== "empty.html?xhr")
             return;
         xhrNode = node;
@@ -45,7 +47,7 @@
 
     InspectorTest.recordNetwork();
     InspectorTest.networkManager.addEventListener(SDK.NetworkManager.Events.RequestFinished, onRequestFinished);
-    InspectorTest.addSniffer(UI.panels.network._networkLogView._dataGrid, "insertChild", onNodeInserted, true);
+    InspectorTest.addSniffer(UI.SortableDataGridNode.prototype, "insertChild", onNodeInserted, true);
     InspectorTest.NetworkAgent.setCacheDisabled(true, InspectorTest.evaluateInPage.bind(null, "sendXHRRequest()"));
 }
 </script>
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
index 4e79ca3..11a0ec7e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/data-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/data-suggestion-picker-appearance-expected.png
index c3df0d8..549ea6b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/data-suggestion-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/data-suggestion-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/popup-menu-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/popup-menu-appearance-expected.png
index 92f4ed67..3fe82909 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/popup-menu-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/popup-menu-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200/fast/hidpi/static/calendar-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200/fast/hidpi/static/calendar-picker-appearance-expected.png
index 2a65773d..1547bd8a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200/fast/hidpi/static/calendar-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200/fast/hidpi/static/calendar-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200/fast/hidpi/static/data-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200/fast/hidpi/static/data-suggestion-picker-appearance-expected.png
index 9d67f89..01d151ed 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200/fast/hidpi/static/data-suggestion-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200/fast/hidpi/static/data-suggestion-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200/fast/hidpi/static/popup-menu-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200/fast/hidpi/static/popup-menu-appearance-expected.png
index 2beb2c4..49d0e29 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200/fast/hidpi/static/popup-menu-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200/fast/hidpi/static/popup-menu-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/calendar-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/calendar-picker-appearance-expected.png
index 2a65773d..1547bd8a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/calendar-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/calendar-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/data-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/data-suggestion-picker-appearance-expected.png
index 9d67f89..01d151ed 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/data-suggestion-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/data-suggestion-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/popup-menu-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/popup-menu-appearance-expected.png
index 2beb2c4..49d0e29 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/popup-menu-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/popup-menu-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/Source/bindings/scripts/code_generator_web_module.py b/third_party/WebKit/Source/bindings/scripts/code_generator_web_module.py
index 4128751..7953d0fc 100644
--- a/third_party/WebKit/Source/bindings/scripts/code_generator_web_module.py
+++ b/third_party/WebKit/Source/bindings/scripts/code_generator_web_module.py
@@ -29,10 +29,10 @@
 MODULE_PYNAME = os.path.splitext(os.path.basename(__file__))[0] + '.py'
 
 WEB_MODULE_IDL_ATTRIBUTE = 'WebModuleAPI'
-
+STRING_INCLUDE_PATH = 'wtf/text/WTFString.h'
 
 def interface_context(idl_interface):
-    builder = InterfaceContextBuilder(MODULE_PYNAME)
+    builder = InterfaceContextBuilder(MODULE_PYNAME, TypeResolver())
     builder.set_class_name(idl_interface.name)
     builder.set_inheritance(idl_interface.parent)
 
@@ -45,9 +45,40 @@
     return builder.build()
 
 
+class TypeResolver(object):
+    """Resolves Web IDL types into corresponding C++ types and include paths
+       to the generated and existing files."""
+
+    def includes_from_interface(self, base_type):
+        # TODO(dglazkov): Are there any exceptional conditions here?
+        return set([base_type])
+
+    def _includes_from_type(self, idl_type):
+        if idl_type.is_void:
+            return set()
+        if idl_type.is_primitive_type:
+            return set()
+        if idl_type.is_string_type:
+            return set([STRING_INCLUDE_PATH])
+
+        # TODO(dglazkov): Handle complex/weird types.
+        # TODO(dglazkov): Make these proper paths to generated and non-generated
+        # files.
+        return set([idl_type.base_type])
+
+    def includes_from_definition(self, idl_definition):
+        return self._includes_from_type(idl_definition.idl_type)
+
+    def type_from_definition(self, idl_definition):
+        # TODO(dglazkov): The output of this method must be a reasonable C++
+        # type that can be used directly in the jinja2 template.
+        return idl_definition.idl_type.base_type
+
+
 class InterfaceContextBuilder(object):
-    def __init__(self, code_generator):
+    def __init__(self, code_generator, type_resolver):
         self.result = {'code_generator': code_generator}
+        self.type_resolver = type_resolver
 
     def set_class_name(self, class_name):
         self.result['class_name'] = class_name
@@ -57,7 +88,7 @@
             return
         self.result['inherits_expression'] = ' : public %s' % base_interface
         self._ensure_set('cpp_includes').update(
-            self._includes_for_type(base_interface))
+            self.type_resolver.includes_from_interface(base_interface))
 
     def _ensure_set(self, name):
         return self.result.setdefault(name, set())
@@ -65,19 +96,11 @@
     def _ensure_list(self, name):
         return self.result.setdefault(name, [])
 
-    def _includes_for_type(self, idl_type):
-        # TODO(dglazkov): Make this actually work.
-        name = idl_type
-        return set([name])
-
-    def _get_return_type(self, idl_definition):
-        return idl_definition.idl_type.preprocessed_type.base_type
-
     def add_attribute(self, idl_attribute):
         self._ensure_list('attributes').append(
             self.create_attribute(idl_attribute))
         self._ensure_set('cpp_includes').update(
-            self._includes_for_type(self._get_return_type(idl_attribute)))
+            self.type_resolver.includes_from_definition(idl_attribute))
 
     def add_operation(self, idl_operation):
         if not idl_operation.name:
@@ -85,11 +108,11 @@
         self._ensure_list('methods').append(
             self.create_method(idl_operation))
         self._ensure_set('cpp_includes').update(
-            self._includes_for_type(self._get_return_type(idl_operation)))
+            self.type_resolver.includes_from_definition(idl_operation))
 
     def create_method(self, idl_operation):
         name = idl_operation.name
-        return_type = idl_operation.idl_type.preprocessed_type.base_type
+        return_type = self.type_resolver.type_from_definition(idl_operation)
         return {
             'name': name,
             'return_type': return_type
@@ -97,7 +120,7 @@
 
     def create_attribute(self, idl_attribute):
         name = idl_attribute.name
-        return_type = idl_attribute.idl_type.preprocessed_type.base_type
+        return_type = self.type_resolver.type_from_definition(idl_attribute)
         return {
             'name': name,
             'return_type': return_type
diff --git a/third_party/WebKit/Source/bindings/scripts/code_generator_web_module_test.py b/third_party/WebKit/Source/bindings/scripts/code_generator_web_module_test.py
index 5254244..b3fcc42 100644
--- a/third_party/WebKit/Source/bindings/scripts/code_generator_web_module_test.py
+++ b/third_party/WebKit/Source/bindings/scripts/code_generator_web_module_test.py
@@ -2,16 +2,20 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-# pylint: disable=import-error,print-statement,relative-import
+# pylint: disable=import-error,print-statement,relative-import,protected-access
 
 """Unit tests for code_generator_web_module.py."""
 
 import unittest
 
 from code_generator_web_module import InterfaceContextBuilder
+from code_generator_web_module import TypeResolver
+from code_generator_web_module import STRING_INCLUDE_PATH
 from idl_definitions import IdlAttribute
 from idl_definitions import IdlOperation
 from idl_types import IdlType
+from idl_types import PRIMITIVE_TYPES
+from idl_types import STRING_TYPES
 
 
 # TODO(dglazkov): Convert to use actual objects, not stubs.
@@ -32,16 +36,46 @@
         idl_operation_stub.idl_type = IdlType(return_type)
         return idl_operation_stub
 
+    def make_stub_idl_type(self, base_type):
+        return IdlType(base_type)
+
+
+class TypeResolverTest(unittest.TestCase):
+
+    def test_includes_from_type_should_filter_primitive_types(self):
+        type_resolver = TypeResolver()
+        helper = IdlTestingHelper()
+        for primitive_type in PRIMITIVE_TYPES:
+            idl_type = helper.make_stub_idl_type(primitive_type)
+            self.assertEqual(
+                type_resolver._includes_from_type(idl_type), set())
+
+    def test_includes_from_type_should_filter_void(self):
+        type_resolver = TypeResolver()
+        helper = IdlTestingHelper()
+        idl_type = helper.make_stub_idl_type('void')
+        self.assertEqual(
+            type_resolver._includes_from_type(idl_type), set())
+
+    def test_includes_from_type_should_handle_string(self):
+        type_resolver = TypeResolver()
+        helper = IdlTestingHelper()
+        for string_type in STRING_TYPES:
+            idl_type = helper.make_stub_idl_type(string_type)
+            self.assertEqual(
+                type_resolver._includes_from_type(idl_type),
+                set([STRING_INCLUDE_PATH]))
+
 
 class InterfaceContextBuilderTest(unittest.TestCase):
 
     def test_empty(self):
-        builder = InterfaceContextBuilder('test')
+        builder = InterfaceContextBuilder('test', TypeResolver())
 
         self.assertEqual({'code_generator': 'test'}, builder.build())
 
     def test_set_name(self):
-        builder = InterfaceContextBuilder('test')
+        builder = InterfaceContextBuilder('test', TypeResolver())
 
         builder.set_class_name('foo')
         self.assertEqual({
@@ -50,7 +84,7 @@
         }, builder.build())
 
     def test_set_inheritance(self):
-        builder = InterfaceContextBuilder('test')
+        builder = InterfaceContextBuilder('test', TypeResolver())
         builder.set_inheritance('foo')
         self.assertEqual({
             'code_generator': 'test',
@@ -58,14 +92,14 @@
             'cpp_includes': set(['foo']),
         }, builder.build())
 
-        builder = InterfaceContextBuilder('test')
+        builder = InterfaceContextBuilder('test', TypeResolver())
         builder.set_inheritance(None)
         self.assertEqual({'code_generator': 'test'}, builder.build())
 
 
     def test_add_attribute(self):
         helper = IdlTestingHelper()
-        builder = InterfaceContextBuilder('test')
+        builder = InterfaceContextBuilder('test', TypeResolver())
 
         attribute = helper.make_stub_idl_attribute('foo', 'bar')
         builder.add_attribute(attribute)
@@ -77,7 +111,7 @@
 
     def test_add_method(self):
         helper = IdlTestingHelper()
-        builder = InterfaceContextBuilder('test')
+        builder = InterfaceContextBuilder('test', TypeResolver())
 
         operation = helper.make_stub_idl_operation('foo', 'bar')
         builder.add_operation(operation)
diff --git a/third_party/WebKit/Source/bindings/scripts/idl_types.py b/third_party/WebKit/Source/bindings/scripts/idl_types.py
index 3224a5d..7447b56 100644
--- a/third_party/WebKit/Source/bindings/scripts/idl_types.py
+++ b/third_party/WebKit/Source/bindings/scripts/idl_types.py
@@ -208,6 +208,10 @@
         return self.base_type in INTEGER_TYPES
 
     @property
+    def is_void(self):
+        return self.base_type == 'void'
+
+    @property
     def is_numeric_type(self):
         return self.base_type in NUMERIC_TYPES
 
diff --git a/third_party/WebKit/Source/bindings/scripts/idl_types_test.py b/third_party/WebKit/Source/bindings/scripts/idl_types_test.py
new file mode 100644
index 0000000..b21f00b7
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/scripts/idl_types_test.py
@@ -0,0 +1,20 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# pylint: disable=import-error,print-statement,relative-import
+
+"""Unit tests for idl_types.py."""
+
+import unittest
+
+from idl_types import IdlType
+
+
+class IdlTypeTest(unittest.TestCase):
+
+    def test_is_void(self):
+        idl_type = IdlType('void')
+        self.assertTrue(idl_type.is_void)
+        idl_type = IdlType('somethingElse')
+        self.assertFalse(idl_type.is_void)
diff --git a/third_party/WebKit/Source/bindings/templates/web_module_interface.cpp.tmpl b/third_party/WebKit/Source/bindings/templates/web_module_interface.cpp.tmpl
index 3bd1329..b918325 100644
--- a/third_party/WebKit/Source/bindings/templates/web_module_interface.cpp.tmpl
+++ b/third_party/WebKit/Source/bindings/templates/web_module_interface.cpp.tmpl
@@ -2,11 +2,11 @@
 
 {% include 'copyright_block.txt' %}
 
-#include "Web{{class_name}}.h"
+#include "{{class_name}}.h"
 
 // TODO(dglazkov): Implement generating includes.
 {% for filename in cpp_includes %}
-#include "Web{{filename}}.h"
+#include "{{filename}}.h"
 {% endfor %}
 
 namespace blink {
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/WebTestInterface3.cpp b/third_party/WebKit/Source/bindings/tests/results/core/WebTestInterface3.cpp
index 225fbc57..7bfce64 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/WebTestInterface3.cpp
+++ b/third_party/WebKit/Source/bindings/tests/results/core/WebTestInterface3.cpp
@@ -10,12 +10,11 @@
 
 // clang-format off
 
-#include "WebTestInterface3.h"
+#include "TestInterface3.h"
 
 // TODO(dglazkov): Implement generating includes.
-#include "Webvoid.h"
-#include "WebIterator.h"
-#include "WebDOMString.h"
+#include "wtf/text/WTFString.h.h"
+#include "Iterator.h"
 
 namespace blink {
 namespace api {
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn
index 42412dc..1947213 100644
--- a/third_party/WebKit/Source/core/BUILD.gn
+++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -1265,7 +1265,9 @@
     "paint/PaintLayerScrollableAreaTest.cpp",
     "paint/PaintLayerTest.cpp",
     "paint/PaintPropertyTreeBuilderTest.cpp",
+    "paint/PaintPropertyTreeBuilderTest.h",
     "paint/PaintPropertyTreePrinterTest.cpp",
+    "paint/PaintPropertyTreeUpdateTests.cpp",
     "paint/PrePaintTreeWalkTest.cpp",
     "paint/SVGInlineTextBoxPainterTest.cpp",
     "paint/StubChromeClientForSPv2.h",
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index bdb4126..2a0fec7 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -492,7 +492,8 @@
       m_parserSyncPolicy(AllowAsynchronousParsing),
       m_nodeCount(0),
       m_wouldLoadReason(Created),
-      m_passwordCount(0) {
+      m_passwordCount(0),
+      m_engagementLevel(mojom::blink::EngagementLevel::NONE) {
   if (m_frame) {
     DCHECK(m_frame->page());
     provideContextFeaturesToDocumentFrom(*this, *m_frame->page());
diff --git a/third_party/WebKit/Source/core/dom/Document.h b/third_party/WebKit/Source/core/dom/Document.h
index 4a8a171f..3fc2855 100644
--- a/third_party/WebKit/Source/core/dom/Document.h
+++ b/third_party/WebKit/Source/core/dom/Document.h
@@ -63,6 +63,7 @@
 #include "platform/weborigin/ReferrerPolicy.h"
 #include "public/platform/WebFocusType.h"
 #include "public/platform/WebInsecureRequestPolicy.h"
+#include "public/platform/site_engagement.mojom-blink.h"
 #include "wtf/Compiler.h"
 #include "wtf/HashSet.h"
 #include "wtf/PassRefPtr.h"
@@ -1194,6 +1195,13 @@
   Document& ensureTemplateDocument();
   Document* templateDocumentHost() { return m_templateDocumentHost; }
 
+  mojom::blink::EngagementLevel getEngagementLevel() const {
+    return m_engagementLevel;
+  }
+  void setEngagementLevel(mojom::blink::EngagementLevel level) {
+    m_engagementLevel = level;
+  }
+
   // TODO(thestig): Rename these and related functions, since we can call them
   // for controls outside of forms as well.
   void didAssociateFormControl(Element*);
@@ -1662,6 +1670,8 @@
   unsigned m_passwordCount;
 
   TaskHandle m_sensitiveInputVisibilityTask;
+
+  mojom::EngagementLevel m_engagementLevel;
 };
 
 extern template class CORE_EXTERN_TEMPLATE_EXPORT Supplement<Document>;
diff --git a/third_party/WebKit/Source/core/frame/ImageBitmapTest.cpp b/third_party/WebKit/Source/core/frame/ImageBitmapTest.cpp
index c9a206a..a4a56df9 100644
--- a/third_party/WebKit/Source/core/frame/ImageBitmapTest.cpp
+++ b/third_party/WebKit/Source/core/frame/ImageBitmapTest.cpp
@@ -33,6 +33,7 @@
 #include "SkPixelRef.h"  // FIXME: qualify this skia header file.
 #include "core/dom/Document.h"
 #include "core/fetch/MemoryCache.h"
+#include "core/frame/FrameView.h"
 #include "core/html/HTMLCanvasElement.h"
 #include "core/html/HTMLImageElement.h"
 #include "core/html/HTMLVideoElement.h"
@@ -65,7 +66,10 @@
     m_globalMemoryCache = replaceMemoryCacheForTesting(MemoryCache::create());
 
     // Save the state of experimental canvas features and color correct
-    // rendering flags to restore them on teardown.
+    // rendering flags to restore them on teardown. Each test that changes the
+    // flags must restore them to prevent affecting other ImageBitmap tests.
+    // This is an extra safety precaution to prevent such an error to leak from
+    // this test suite.
     experimentalCanvasFeatures =
         RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled();
     colorCorrectRendering =
@@ -214,10 +218,7 @@
   LAST = LINEAR_RGB
 };
 
-static ImageBitmap* createImageBitmapWithColorSpaceConversion(
-    HTMLImageElement* image,
-    Optional<IntRect>& cropRect,
-    Document* document,
+static ImageBitmapOptions prepareBitmapOptionsAndSetRuntimeFlags(
     const ColorSpaceConversion& colorSpaceConversion) {
   // Set the color space conversion in ImageBitmapOptions
   ImageBitmapOptions options;
@@ -233,11 +234,10 @@
   RuntimeEnabledFeatures::setColorCorrectRenderingEnabled(flag);
   RuntimeEnabledFeatures::setColorCorrectRenderingDefaultModeEnabled(!flag);
 
-  // Create and return the ImageBitmap
-  return ImageBitmap::create(image, cropRect, &(image->document()), options);
+  return options;
 }
 
-TEST_F(ImageBitmapTest, ImageBitmapColorSpaceConversion) {
+TEST_F(ImageBitmapTest, ImageBitmapColorSpaceConversionHTMLImageElement) {
   HTMLImageElement* imageElement =
       HTMLImageElement::create(*Document::create());
 
@@ -247,15 +247,15 @@
       SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
 
   SkImageInfo rasterImageInfo =
-      SkImageInfo::MakeN32Premul(100, 100, srcRGBColorSpace);
+      SkImageInfo::MakeN32Premul(10, 10, srcRGBColorSpace);
   sk_sp<SkSurface> surface(SkSurface::MakeRaster(rasterImageInfo));
-  surface->getCanvas()->drawCircle(50, 50, 50, p);
+  surface->getCanvas()->drawCircle(5, 5, 5, p);
   sk_sp<SkImage> image = surface->makeImageSnapshot();
 
   std::unique_ptr<uint8_t[]> srcPixel(
       new uint8_t[rasterImageInfo.bytesPerPixel()]());
   image->readPixels(rasterImageInfo.makeWH(1, 1), srcPixel.get(),
-                    image->width() * rasterImageInfo.bytesPerPixel(), 50, 50);
+                    image->width() * rasterImageInfo.bytesPerPixel(), 5, 5);
 
   ImageResourceContent* originalImageResource =
       ImageResourceContent::create(StaticBitmapImage::create(image).get());
@@ -281,9 +281,15 @@
        i <= static_cast<uint8_t>(ColorSpaceConversion::LAST); i++) {
     ColorSpaceConversion colorSpaceConversion =
         static_cast<ColorSpaceConversion>(i);
-    ImageBitmap* imageBitmap = createImageBitmapWithColorSpaceConversion(
-        imageElement, cropRect, &(imageElement->document()),
-        colorSpaceConversion);
+    ImageBitmapOptions options =
+        prepareBitmapOptionsAndSetRuntimeFlags(colorSpaceConversion);
+    ImageBitmap* imageBitmap = ImageBitmap::create(
+        imageElement, cropRect, &(imageElement->document()), options);
+
+    // ColorBehavior::ignore() is used instead of
+    // ColorBehavior::transformToTargetForTesting() to avoid color conversion to
+    // display color profile, as we want to solely rely on the color correction
+    // that happens in ImageBitmap create method.
     SkImage* convertedImage =
         imageBitmap->bitmapImage()
             ->imageForCurrentFrame(ColorBehavior::ignore())
@@ -320,7 +326,110 @@
         new uint8_t[imageInfo.bytesPerPixel()]());
     convertedImage->readPixels(
         imageInfo, convertedPixel.get(),
-        convertedImage->width() * imageInfo.bytesPerPixel(), 50, 50);
+        convertedImage->width() * imageInfo.bytesPerPixel(), 5, 5);
+
+    // Transform the source pixel and check if the image bitmap color conversion
+    // is done correctly.
+    std::unique_ptr<SkColorSpaceXform> colorSpaceXform =
+        SkColorSpaceXform::New(srcRGBColorSpace.get(), colorSpace.get());
+    std::unique_ptr<uint8_t[]> transformedPixel(
+        new uint8_t[imageInfo.bytesPerPixel()]());
+    colorSpaceXform->apply(colorFormat, transformedPixel.get(), colorFormat32,
+                           srcPixel.get(), 1, SkAlphaType::kPremul_SkAlphaType);
+
+    int compare = std::memcmp(convertedPixel.get(), transformedPixel.get(),
+                              imageInfo.bytesPerPixel());
+    ASSERT_EQ(compare, 0);
+  }
+}
+
+TEST_F(ImageBitmapTest, ImageBitmapColorSpaceConversionImageBitmap) {
+  HTMLImageElement* imageElement =
+      HTMLImageElement::create(*Document::create());
+
+  SkPaint p;
+  p.setColor(SK_ColorRED);
+  sk_sp<SkColorSpace> srcRGBColorSpace =
+      SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
+
+  SkImageInfo rasterImageInfo =
+      SkImageInfo::MakeN32Premul(10, 10, srcRGBColorSpace);
+  sk_sp<SkSurface> surface(SkSurface::MakeRaster(rasterImageInfo));
+  surface->getCanvas()->drawCircle(5, 5, 5, p);
+  sk_sp<SkImage> image = surface->makeImageSnapshot();
+
+  std::unique_ptr<uint8_t[]> srcPixel(
+      new uint8_t[rasterImageInfo.bytesPerPixel()]());
+  image->readPixels(rasterImageInfo.makeWH(1, 1), srcPixel.get(),
+                    image->width() * rasterImageInfo.bytesPerPixel(), 5, 5);
+
+  ImageResourceContent* sourceImageResource =
+      ImageResourceContent::create(StaticBitmapImage::create(image).get());
+  imageElement->setImageResource(sourceImageResource);
+
+  Optional<IntRect> cropRect = IntRect(0, 0, image->width(), image->height());
+  ImageBitmapOptions options =
+      prepareBitmapOptionsAndSetRuntimeFlags(ColorSpaceConversion::SRGB);
+  ImageBitmap* sourceImageBitmap = ImageBitmap::create(
+      imageElement, cropRect, &(imageElement->document()), options);
+
+  sk_sp<SkColorSpace> colorSpace = nullptr;
+  SkColorType colorType = SkColorType::kN32_SkColorType;
+  SkColorSpaceXform::ColorFormat colorFormat32 =
+      (colorType == kBGRA_8888_SkColorType)
+          ? SkColorSpaceXform::ColorFormat::kBGRA_8888_ColorFormat
+          : SkColorSpaceXform::ColorFormat::kRGBA_8888_ColorFormat;
+  SkColorSpaceXform::ColorFormat colorFormat = colorFormat32;
+
+  for (uint8_t i = static_cast<uint8_t>(
+           ColorSpaceConversion::DEFAULT_NOT_COLOR_CORRECTED);
+       i <= static_cast<uint8_t>(ColorSpaceConversion::LAST); i++) {
+    ColorSpaceConversion colorSpaceConversion =
+        static_cast<ColorSpaceConversion>(i);
+    options = prepareBitmapOptionsAndSetRuntimeFlags(colorSpaceConversion);
+    ImageBitmap* imageBitmap =
+        ImageBitmap::create(sourceImageBitmap, cropRect, options);
+    // ColorBehavior::ignore() is used instead of
+    // ColorBehavior::transformToTargetForTesting() to avoid color conversion to
+    // display color profile, as we want to solely rely on the color correction
+    // that happens in ImageBitmap create method.
+    SkImage* convertedImage =
+        imageBitmap->bitmapImage()
+            ->imageForCurrentFrame(ColorBehavior::ignore())
+            .get();
+
+    switch (colorSpaceConversion) {
+      case ColorSpaceConversion::NONE:
+        NOTREACHED();
+        break;
+      case ColorSpaceConversion::DEFAULT_NOT_COLOR_CORRECTED:
+        // TODO(zakerinasab): Replace sRGB with a call to
+        // ImageDecoder::globalTargetColorSpace() when the crash problem on Mac
+        // is fixed. crbug.com/668546.
+        colorSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
+        colorFormat = colorFormat32;
+        break;
+      case ColorSpaceConversion::DEFAULT_COLOR_CORRECTED:
+      case ColorSpaceConversion::SRGB:
+        colorSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
+        colorFormat = colorFormat32;
+        break;
+      case ColorSpaceConversion::LINEAR_RGB:
+        colorSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGBLinear_Named);
+        colorType = SkColorType::kRGBA_F16_SkColorType;
+        colorFormat = SkColorSpaceXform::ColorFormat::kRGBA_F16_ColorFormat;
+        break;
+      default:
+        NOTREACHED();
+    }
+
+    SkImageInfo imageInfo = SkImageInfo::Make(
+        1, 1, colorType, SkAlphaType::kPremul_SkAlphaType, colorSpace);
+    std::unique_ptr<uint8_t[]> convertedPixel(
+        new uint8_t[imageInfo.bytesPerPixel()]());
+    convertedImage->readPixels(
+        imageInfo, convertedPixel.get(),
+        convertedImage->width() * imageInfo.bytesPerPixel(), 5, 5);
 
     // Transform the source pixel and check if the image bitmap color conversion
     // is done correctly.
diff --git a/third_party/WebKit/Source/core/html/CollectionItemsCache.h b/third_party/WebKit/Source/core/html/CollectionItemsCache.h
index 2b88dce..4ab7209 100644
--- a/third_party/WebKit/Source/core/html/CollectionItemsCache.h
+++ b/third_party/WebKit/Source/core/html/CollectionItemsCache.h
@@ -86,7 +86,7 @@
   NodeType* currentNode = collection.traverseToFirst();
   unsigned currentIndex = 0;
   while (currentNode) {
-    m_cachedList.append(currentNode);
+    m_cachedList.push_back(currentNode);
     currentNode = collection.traverseForwardToOffset(
         currentIndex + 1, *currentNode, currentIndex);
   }
diff --git a/third_party/WebKit/Source/core/html/FormData.cpp b/third_party/WebKit/Source/core/html/FormData.cpp
index da16236..2051fed9 100644
--- a/third_party/WebKit/Source/core/html/FormData.cpp
+++ b/third_party/WebKit/Source/core/html/FormData.cpp
@@ -96,7 +96,7 @@
 }
 
 void FormData::append(const String& name, const String& value) {
-  m_entries.append(
+  m_entries.push_back(
       new Entry(encodeAndNormalize(name), encodeAndNormalize(value)));
 }
 
@@ -163,7 +163,7 @@
       DCHECK(entry->isFile());
       value.setFile(entry->file());
     }
-    results.append(value);
+    results.push_back(value);
   }
   return results;
 }
@@ -202,7 +202,7 @@
     }
   }
   if (!found)
-    m_entries.append(entry);
+    m_entries.push_back(entry);
 }
 
 void FormData::append(const String& name, int value) {
@@ -210,7 +210,7 @@
 }
 
 void FormData::append(const String& name, Blob* blob, const String& filename) {
-  m_entries.append(new Entry(encodeAndNormalize(name), blob, filename));
+  m_entries.push_back(new Entry(encodeAndNormalize(name), blob, filename));
 }
 
 CString FormData::encodeAndNormalize(const String& string) const {
diff --git a/third_party/WebKit/Source/core/html/HTMLCollection.cpp b/third_party/WebKit/Source/core/html/HTMLCollection.cpp
index 74f3b7f..33a3c2f 100644
--- a/third_party/WebKit/Source/core/html/HTMLCollection.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLCollection.cpp
@@ -457,7 +457,7 @@
       HashSet<AtomicString>::AddResult addResult =
           existingNames.add(idAttribute);
       if (addResult.isNewEntry)
-        names.append(idAttribute);
+        names.push_back(idAttribute);
     }
     if (!element->isHTMLElement())
       continue;
@@ -468,7 +468,7 @@
       HashSet<AtomicString>::AddResult addResult =
           existingNames.add(nameAttribute);
       if (addResult.isNewEntry)
-        names.append(nameAttribute);
+        names.push_back(nameAttribute);
     }
   }
 }
@@ -513,12 +513,12 @@
   const NamedItemCache& cache = namedItemCache();
   if (HeapVector<Member<Element>>* idResults = cache.getElementsById(name)) {
     for (const auto& element : *idResults)
-      result.append(element);
+      result.push_back(element);
   }
   if (HeapVector<Member<Element>>* nameResults =
           cache.getElementsByName(name)) {
     for (const auto& element : *nameResults)
-      result.append(element);
+      result.push_back(element);
   }
 }
 
diff --git a/third_party/WebKit/Source/core/html/HTMLCollection.h b/third_party/WebKit/Source/core/html/HTMLCollection.h
index 94a81ef3a..3834d387 100644
--- a/third_party/WebKit/Source/core/html/HTMLCollection.h
+++ b/third_party/WebKit/Source/core/html/HTMLCollection.h
@@ -152,7 +152,7 @@
           map.add(key.impl(), nullptr).storedValue->value;
       if (!vector)
         vector = new HeapVector<Member<Element>>;
-      vector->append(element);
+      vector->push_back(element);
     }
 
     StringToElementsMap m_idCache;
diff --git a/third_party/WebKit/Source/core/html/HTMLDimension.cpp b/third_party/WebKit/Source/core/html/HTMLDimension.cpp
index 21cf532b..9109a5a 100644
--- a/third_party/WebKit/Source/core/html/HTMLDimension.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLDimension.cpp
@@ -75,7 +75,7 @@
              (isASCIIDigit(characters[position]) ||
               isASCIISpace(characters[position]))) {
         if (isASCIIDigit(characters[position]))
-          fractionNumbers.append(characters[position]);
+          fractionNumbers.push_back(characters[position]);
         ++position;
       }
 
@@ -138,12 +138,12 @@
     if (nextComma == kNotFound)
       break;
 
-    parsedDimensions.append(
+    parsedDimensions.push_back(
         parseDimension(trimmedString, lastParsedIndex, nextComma));
     lastParsedIndex = nextComma + 1;
   }
 
-  parsedDimensions.append(
+  parsedDimensions.push_back(
       parseDimension(trimmedString, lastParsedIndex, trimmedString.length()));
   return parsedDimensions;
 }
diff --git a/third_party/WebKit/Source/core/html/HTMLElement.cpp b/third_party/WebKit/Source/core/html/HTMLElement.cpp
index f0992219..30bc4d8 100644
--- a/third_party/WebKit/Source/core/html/HTMLElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLElement.cpp
@@ -948,17 +948,17 @@
   // "characters" in the String.
   for (; i < colorString.length() && digitBuffer.size() < maxColorLength; i++) {
     if (!isASCIIHexDigit(colorString[i]))
-      digitBuffer.append('0');
+      digitBuffer.push_back('0');
     else
-      digitBuffer.append(colorString[i]);
+      digitBuffer.push_back(colorString[i]);
   }
 
   if (!digitBuffer.size())
     return Color::black;
 
   // Pad the buffer out to at least the next multiple of three in size.
-  digitBuffer.append('0');
-  digitBuffer.append('0');
+  digitBuffer.push_back('0');
+  digitBuffer.push_back('0');
 
   if (digitBuffer.size() < 6)
     return makeRGB(toASCIIHexValue(digitBuffer[0]),
diff --git a/third_party/WebKit/Source/core/html/HTMLEmbedElement.cpp b/third_party/WebKit/Source/core/html/HTMLEmbedElement.cpp
index 481c7d01..5450793 100644
--- a/third_party/WebKit/Source/core/html/HTMLEmbedElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLEmbedElement.cpp
@@ -135,8 +135,8 @@
                                            Vector<String>& paramValues) {
   AttributeCollection attributes = this->attributes();
   for (const Attribute& attribute : attributes) {
-    paramNames.append(attribute.localName().getString());
-    paramValues.append(attribute.value().getString());
+    paramNames.push_back(attribute.localName().getString());
+    paramValues.push_back(attribute.value().getString());
   }
 }
 
diff --git a/third_party/WebKit/Source/core/html/HTMLFormControlElement.cpp b/third_party/WebKit/Source/core/html/HTMLFormControlElement.cpp
index 9e5926a..a3a0d1d4 100644
--- a/third_party/WebKit/Source/core/html/HTMLFormControlElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLFormControlElement.cpp
@@ -515,7 +515,7 @@
   if (dispatchResult == DispatchEventResult::NotCanceled &&
       unhandledInvalidControls && isConnected() &&
       originalDocument == document())
-    unhandledInvalidControls->append(this);
+    unhandledInvalidControls->push_back(this);
   return false;
 }
 
diff --git a/third_party/WebKit/Source/core/html/HTMLFormControlsCollection.cpp b/third_party/WebKit/Source/core/html/HTMLFormControlsCollection.cpp
index 6801399..8810a78 100644
--- a/third_party/WebKit/Source/core/html/HTMLFormControlsCollection.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLFormControlsCollection.cpp
@@ -207,14 +207,14 @@
       HashSet<AtomicString>::AddResult addResult =
           existingNames.add(idAttribute);
       if (addResult.isNewEntry)
-        names.append(idAttribute);
+        names.push_back(idAttribute);
     }
     const AtomicString& nameAttribute = element->getNameAttribute();
     if (!nameAttribute.isEmpty()) {
       HashSet<AtomicString>::AddResult addResult =
           existingNames.add(nameAttribute);
       if (addResult.isNewEntry)
-        names.append(nameAttribute);
+        names.push_back(nameAttribute);
     }
   }
 }
diff --git a/third_party/WebKit/Source/core/html/HTMLFormElement.cpp b/third_party/WebKit/Source/core/html/HTMLFormElement.cpp
index fcfa50f..94552349 100644
--- a/third_party/WebKit/Source/core/html/HTMLFormElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLFormElement.cpp
@@ -562,7 +562,7 @@
     else
       continue;
     if (listedElement->form() == this)
-      elements.append(listedElement);
+      elements.push_back(listedElement);
   }
 }
 
@@ -590,7 +590,7 @@
   for (HTMLImageElement& image :
        Traversal<HTMLImageElement>::startsAfter(root)) {
     if (image.formOwner() == this)
-      elements.append(&image);
+      elements.push_back(&image);
   }
 }
 
@@ -658,7 +658,7 @@
   HeapVector<Member<ListedElement>> elements;
   elements.reserveCapacity(listedElements.size());
   for (const auto& element : listedElements)
-    elements.append(element);
+    elements.push_back(element);
   int invalidControlsCount = 0;
   for (const auto& element : elements) {
     if (element->form() == this && element->isFormControlElement()) {
@@ -732,7 +732,7 @@
   if (namedItems.size() && namedItems.front() != elementFromPast) {
     addToPastNamesMap(namedItems.front().get(), name);
   } else if (elementFromPast && namedItems.isEmpty()) {
-    namedItems.append(elementFromPast);
+    namedItems.push_back(elementFromPast);
     UseCounter::count(document(), UseCounter::FormNameAccessForPastNamesMap);
   }
 }
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElementPermissions.cpp b/third_party/WebKit/Source/core/html/HTMLIFrameElementPermissions.cpp
index 0fe5e9f..8e22e8b4 100644
--- a/third_party/WebKit/Source/core/html/HTMLIFrameElementPermissions.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLIFrameElementPermissions.cpp
@@ -60,7 +60,7 @@
   for (size_t i = 0; i < tokens.size(); ++i) {
     WebPermissionType type;
     if (getPermissionType(tokens[i], &type)) {
-      permissions.append(type);
+      permissions.push_back(type);
     } else {
       if (numTokenErrors)
         tokenErrors.append(", '");
diff --git a/third_party/WebKit/Source/core/html/HTMLInputElement.cpp b/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
index f721e09e..4c405b3 100644
--- a/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
@@ -1363,7 +1363,7 @@
       continue;
     if (!predicate(trimmedType))
       continue;
-    types.append(trimmedType.lower());
+    types.push_back(trimmedType.lower());
   }
 
   return types;
@@ -1600,7 +1600,7 @@
     // TODO(tkent): Should allow invalid strings. crbug.com/607097.
     if (!isValidValue(option->value()))
       continue;
-    filtered.append(option);
+    filtered.push_back(option);
   }
   return filtered;
 }
@@ -1832,7 +1832,7 @@
       suggestion.localizedValue = localizeValue(option->value());
       suggestion.label =
           option->value() == option->label() ? String() : option->label();
-      parameters.suggestions.append(suggestion);
+      parameters.suggestions.push_back(suggestion);
     }
   }
   return true;
diff --git a/third_party/WebKit/Source/core/html/HTMLKeygenElement.cpp b/third_party/WebKit/Source/core/html/HTMLKeygenElement.cpp
index 81996b2..17d92d2 100644
--- a/third_party/WebKit/Source/core/html/HTMLKeygenElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLKeygenElement.cpp
@@ -74,9 +74,9 @@
 
   Vector<String> keys;
   keys.reserveCapacity(2);
-  keys.append(
+  keys.push_back(
       locale().queryString(WebLocalizedString::KeygenMenuHighGradeKeySize));
-  keys.append(
+  keys.push_back(
       locale().queryString(WebLocalizedString::KeygenMenuMediumGradeKeySize));
 
   // Create a select element with one option element for each key size.
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
index 1ddf9ba..3d20d30 100644
--- a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
@@ -886,7 +886,7 @@
     for (unsigned i = 0; i < m_textTracks->length(); ++i) {
       TextTrack* track = m_textTracks->anonymousIndexedGetter(i);
       if (track->mode() != TextTrack::disabledKeyword())
-        m_textTracksWhenResourceSelectionBegan.append(track);
+        m_textTracksWhenResourceSelectionBegan.push_back(track);
     }
   }
 
@@ -2167,7 +2167,7 @@
   // remove the Promise if ::play() failed.
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
   ScriptPromise promise = resolver->promise();
-  m_playPromiseResolvers.append(resolver);
+  m_playPromiseResolvers.push_back(resolver);
 
   Nullable<ExceptionCode> code = play();
   if (!code.isNull()) {
@@ -2537,7 +2537,7 @@
   for (unsigned i = 0; i < audioTracks().length(); ++i) {
     AudioTrack* track = audioTracks().anonymousIndexedGetter(i);
     if (track->enabled())
-      enabledTrackIds.append(track->id());
+      enabledTrackIds.push_back(track->id());
   }
 
   webMediaPlayer()->enabledAudioTracksChanged(enabledTrackIds);
diff --git a/third_party/WebKit/Source/core/html/HTMLMetaElement.cpp b/third_party/WebKit/Source/core/html/HTMLMetaElement.cpp
index 9a84945..d1e83844 100644
--- a/third_party/WebKit/Source/core/html/HTMLMetaElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLMetaElement.cpp
@@ -503,7 +503,7 @@
 WTF::TextEncoding HTMLMetaElement::computeEncoding() const {
   HTMLAttributeList attributeList;
   for (const Attribute& attr : attributes())
-    attributeList.append(
+    attributeList.push_back(
         std::make_pair(attr.name().localName(), attr.value().getString()));
   return encodingFromMetaAttributes(attributeList);
 }
diff --git a/third_party/WebKit/Source/core/html/HTMLObjectElement.cpp b/third_party/WebKit/Source/core/html/HTMLObjectElement.cpp
index 9b3667d..f52ece6 100644
--- a/third_party/WebKit/Source/core/html/HTMLObjectElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLObjectElement.cpp
@@ -140,8 +140,8 @@
   }
 
   if (srcIndex == -1 && dataIndex != -1) {
-    paramNames->append("src");
-    paramValues->append((*paramValues)[dataIndex]);
+    paramNames->push_back("src");
+    paramValues->push_back((*paramValues)[dataIndex]);
   }
 }
 
@@ -163,8 +163,8 @@
       continue;
 
     uniqueParamNames.add(name.impl());
-    paramNames.append(p->name());
-    paramValues.append(p->value());
+    paramNames.push_back(p->name());
+    paramValues.push_back(p->value());
 
     // TODO(schenney): crbug.com/572908 url adjustment does not belong in this
     // function.
@@ -201,8 +201,8 @@
   for (const Attribute& attribute : attributes) {
     const AtomicString& name = attribute.name().localName();
     if (!uniqueParamNames.contains(name.impl())) {
-      paramNames.append(name.getString());
-      paramValues.append(attribute.value().getString());
+      paramNames.push_back(name.getString());
+      paramValues.push_back(attribute.value().getString());
     }
   }
 
diff --git a/third_party/WebKit/Source/core/html/HTMLOptionsCollection.cpp b/third_party/WebKit/Source/core/html/HTMLOptionsCollection.cpp
index 6779f72d..5445526 100644
--- a/third_party/WebKit/Source/core/html/HTMLOptionsCollection.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLOptionsCollection.cpp
@@ -55,14 +55,14 @@
       HashSet<AtomicString>::AddResult addResult =
           existingNames.add(idAttribute);
       if (addResult.isNewEntry)
-        names.append(idAttribute);
+        names.push_back(idAttribute);
     }
     const AtomicString& nameAttribute = element->getNameAttribute();
     if (!nameAttribute.isEmpty()) {
       HashSet<AtomicString>::AddResult addResult =
           existingNames.add(nameAttribute);
       if (addResult.isNewEntry)
-        names.append(nameAttribute);
+        names.push_back(nameAttribute);
     }
   }
 }
diff --git a/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp b/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp
index 60960f26..5718ac82 100644
--- a/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp
@@ -244,8 +244,8 @@
   Vector<String> paramNames;
   Vector<String> paramValues;
 
-  paramNames.append("type");
-  paramValues.append(m_serviceType);
+  paramNames.push_back("type");
+  paramValues.push_back(m_serviceType);
 
   bool useFallback = false;
   loadPlugin(url, m_serviceType, paramNames, paramValues, useFallback, false);
diff --git a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
index dcd06dbf..0808d59 100644
--- a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
@@ -446,7 +446,7 @@
     for (const auto& option : optionList()) {
       if (optionIndex++ >= newLen) {
         DCHECK(option->parentNode());
-        itemsToRemove.append(option);
+        itemsToRemove.push_back(option);
       }
     }
 
@@ -579,8 +579,8 @@
 
   m_lastOnChangeSelection.clear();
   for (auto& element : listItems())
-    m_lastOnChangeSelection.append(isHTMLOptionElement(*element) &&
-                                   toHTMLOptionElement(element)->selected());
+    m_lastOnChangeSelection.push_back(isHTMLOptionElement(*element) &&
+                                      toHTMLOptionElement(element)->selected());
 }
 
 void HTMLSelectElement::setActiveSelectionAnchor(HTMLOptionElement* option) {
@@ -602,7 +602,7 @@
   //   updateListBoxSelection needs to clear selection of the fifth OPTION.
   m_cachedStateForActiveSelection.resize(0);
   for (const auto& option : optionList()) {
-    m_cachedStateForActiveSelection.append(option->selected());
+    m_cachedStateForActiveSelection.push_back(option->selected());
   }
 }
 
@@ -772,7 +772,7 @@
         currentElement = ElementTraversal::nextSkippingChildren(current, this);
         continue;
       }
-      m_listItems.append(&current);
+      m_listItems.push_back(&current);
       if (Element* nextElement = ElementTraversal::firstWithin(current)) {
         currentElement = nextElement;
         continue;
@@ -780,10 +780,10 @@
     }
 
     if (isHTMLOptionElement(current))
-      m_listItems.append(&current);
+      m_listItems.push_back(&current);
 
     if (isHTMLHRElement(current))
-      m_listItems.append(&current);
+      m_listItems.push_back(&current);
 
     // In conforming HTML code, only <optgroup> and <option> will be found
     // within a <select>. We call NodeTraversal::nextSkippingChildren so
@@ -2013,10 +2013,10 @@
   Vector<String> filter;
   filter.reserveCapacity(4);
   // Observe only attributes which affect popup content.
-  filter.append(String("disabled"));
-  filter.append(String("label"));
-  filter.append(String("selected"));
-  filter.append(String("value"));
+  filter.push_back(String("disabled"));
+  filter.push_back(String("label"));
+  filter.push_back(String("selected"));
+  filter.push_back(String("value"));
   MutationObserverInit init;
   init.setAttributeOldValue(true);
   init.setAttributes(true);
diff --git a/third_party/WebKit/Source/core/html/HTMLSlotElement.cpp b/third_party/WebKit/Source/core/html/HTMLSlotElement.cpp
index e2b48feb..d298d7a 100644
--- a/third_party/WebKit/Source/core/html/HTMLSlotElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLSlotElement.cpp
@@ -91,7 +91,7 @@
     if (isHTMLSlotElement(child)) {
       child = NodeTraversal::next(*child, this);
     } else {
-      distributedNodes.append(child);
+      distributedNodes.push_back(child);
       child = NodeTraversal::nextSkippingChildren(*child, this);
     }
   }
@@ -106,7 +106,7 @@
 
 void HTMLSlotElement::appendAssignedNode(Node& hostChild) {
   DCHECK(hostChild.isSlotable());
-  m_assignedNodes.append(&hostChild);
+  m_assignedNodes.push_back(&hostChild);
 }
 
 void HTMLSlotElement::resolveDistributedNodes() {
@@ -124,7 +124,7 @@
 
 void HTMLSlotElement::appendDistributedNode(Node& node) {
   size_t size = m_distributedNodes.size();
-  m_distributedNodes.append(&node);
+  m_distributedNodes.push_back(&node);
   m_distributedIndices.set(&node, size);
 }
 
diff --git a/third_party/WebKit/Source/core/html/HTMLTextAreaElement.cpp b/third_party/WebKit/Source/core/html/HTMLTextAreaElement.cpp
index 93f9bd0..b47ce43 100644
--- a/third_party/WebKit/Source/core/html/HTMLTextAreaElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLTextAreaElement.cpp
@@ -471,7 +471,7 @@
   HeapVector<Member<Node>> textNodes;
   for (Node* n = firstChild(); n; n = n->nextSibling()) {
     if (n->isTextNode())
-      textNodes.append(n);
+      textNodes.push_back(n);
   }
   for (const auto& text : textNodes)
     removeChild(text.get(), IGNORE_EXCEPTION);
diff --git a/third_party/WebKit/Source/core/html/MediaFragmentURIParser.cpp b/third_party/WebKit/Source/core/html/MediaFragmentURIParser.cpp
index 3db9fae..6a487d6e 100644
--- a/third_party/WebKit/Source/core/html/MediaFragmentURIParser.cpp
+++ b/third_party/WebKit/Source/core/html/MediaFragmentURIParser.cpp
@@ -136,7 +136,7 @@
     }
 
     if (validUTF8)
-      m_fragments.append(std::make_pair(name, value));
+      m_fragments.push_back(std::make_pair(name, value));
 
     offset = parameterEnd + 1;
   }
diff --git a/third_party/WebKit/Source/core/html/PublicURLManager.cpp b/third_party/WebKit/Source/core/html/PublicURLManager.cpp
index 4695a7a9..baa29ee 100644
--- a/third_party/WebKit/Source/core/html/PublicURLManager.cpp
+++ b/third_party/WebKit/Source/core/html/PublicURLManager.cpp
@@ -84,7 +84,7 @@
         KURL url(ParsedURLString, registeredUrl.key);
         getExecutionContext()->removeURLFromMemoryCache(url);
         registry->unregisterURL(url);
-        urlsToRemove.append(registeredUrl.key);
+        urlsToRemove.push_back(registeredUrl.key);
       }
     }
     for (const auto& url : urlsToRemove)
diff --git a/third_party/WebKit/Source/core/html/TextControlElement.cpp b/third_party/WebKit/Source/core/html/TextControlElement.cpp
index 1b1bf9d..b4ad1c4 100644
--- a/third_party/WebKit/Source/core/html/TextControlElement.cpp
+++ b/third_party/WebKit/Source/core/html/TextControlElement.cpp
@@ -960,8 +960,8 @@
       const unsigned length = end - start;
 
       concatTexts.append(text->data(), start, length);
-      lengthList.append(length);
-      textList.append(text);
+      lengthList.push_back(length);
+      textList.push_back(text);
     }
 
     if (isEndNode)
diff --git a/third_party/WebKit/Source/core/html/forms/ColorInputType.cpp b/third_party/WebKit/Source/core/html/forms/ColorInputType.cpp
index 0f3b9e24..d9d3e79 100644
--- a/third_party/WebKit/Source/core/html/forms/ColorInputType.cpp
+++ b/third_party/WebKit/Source/core/html/forms/ColorInputType.cpp
@@ -252,7 +252,7 @@
         continue;
       ColorSuggestion suggestion(
           color, option->label().left(maxSuggestionLabelLength));
-      suggestions.append(suggestion);
+      suggestions.push_back(suggestion);
       if (suggestions.size() >= maxSuggestions)
         break;
     }
diff --git a/third_party/WebKit/Source/core/html/forms/FileInputType.cpp b/third_party/WebKit/Source/core/html/forms/FileInputType.cpp
index e350501..ed6d99e 100644
--- a/third_party/WebKit/Source/core/html/forms/FileInputType.cpp
+++ b/third_party/WebKit/Source/core/html/forms/FileInputType.cpp
@@ -73,9 +73,9 @@
   Vector<FileChooserFileInfo> files;
   for (size_t i = 0; i < state.valueSize(); i += 2) {
     if (!state[i + 1].isEmpty())
-      files.append(FileChooserFileInfo(state[i], state[i + 1]));
+      files.push_back(FileChooserFileInfo(state[i], state[i + 1]));
     else
-      files.append(FileChooserFileInfo(state[i]));
+      files.push_back(FileChooserFileInfo(state[i]));
   }
   return files;
 }
@@ -332,7 +332,7 @@
     HTMLInputElement& input = element();
     settings.allowsDirectoryUpload = true;
     settings.allowsMultipleFiles = true;
-    settings.selectedFiles.append(path);
+    settings.selectedFiles.push_back(path);
     settings.acceptMIMETypes = input.acceptMIMETypes();
     settings.acceptFileExtensions = input.acceptFileExtensions();
     chromeClient->enumerateChosenDirectory(newFileChooser(settings));
@@ -351,13 +351,13 @@
 
   Vector<FileChooserFileInfo> files;
   for (const auto& path : paths)
-    files.append(FileChooserFileInfo(path));
+    files.push_back(FileChooserFileInfo(path));
 
   if (input.fastHasAttribute(multipleAttr)) {
     filesChosen(files);
   } else {
     Vector<FileChooserFileInfo> firstFileOnly;
-    firstFileOnly.append(files[0]);
+    firstFileOnly.push_back(files[0]);
     filesChosen(firstFileOnly);
   }
 }
diff --git a/third_party/WebKit/Source/core/html/forms/FileInputTypeTest.cpp b/third_party/WebKit/Source/core/html/forms/FileInputTypeTest.cpp
index 3e8f3b8..aba6482b 100644
--- a/third_party/WebKit/Source/core/html/forms/FileInputTypeTest.cpp
+++ b/third_party/WebKit/Source/core/html/forms/FileInputTypeTest.cpp
@@ -19,7 +19,8 @@
   Vector<FileChooserFileInfo> files;
 
   // Native file.
-  files.append(FileChooserFileInfo("/native/path/native-file", "display-name"));
+  files.push_back(
+      FileChooserFileInfo("/native/path/native-file", "display-name"));
 
   // Non-native file.
   KURL url(ParsedURLStringTag(),
@@ -27,7 +28,7 @@
   FileMetadata metadata;
   metadata.length = 64;
   metadata.modificationTime = 1.0 * msPerDay + 3;
-  files.append(FileChooserFileInfo(url, metadata));
+  files.push_back(FileChooserFileInfo(url, metadata));
 
   FileList* list = FileInputType::createFileList(files, false);
   ASSERT_TRUE(list);
@@ -81,16 +82,16 @@
   HTMLInputElement* input = HTMLInputElement::create(*document, false);
   InputType* fileInput = FileInputType::create(*input);
   Vector<String> paths;
-  paths.append("/native/path");
-  paths.append("/native/path2");
+  paths.push_back("/native/path");
+  paths.push_back("/native/path2");
   fileInput->setFilesFromPaths(paths);
   ASSERT_EQ(1u, fileInput->files()->length());
   EXPECT_EQ(String("/native/path"), fileInput->files()->item(0)->path());
 
   // Try to upload multiple files without multipleAttr
   paths.clear();
-  paths.append("/native/path1");
-  paths.append("/native/path2");
+  paths.push_back("/native/path1");
+  paths.push_back("/native/path2");
   fileInput->setFilesFromPaths(paths);
   ASSERT_EQ(1u, fileInput->files()->length());
   EXPECT_EQ(String("/native/path1"), fileInput->files()->item(0)->path());
@@ -98,8 +99,8 @@
   // Try to upload multiple files with multipleAttr
   input->setBooleanAttribute(HTMLNames::multipleAttr, true);
   paths.clear();
-  paths.append("/native/real/path1");
-  paths.append("/native/real/path2");
+  paths.push_back("/native/real/path1");
+  paths.push_back("/native/real/path2");
   fileInput->setFilesFromPaths(paths);
   ASSERT_EQ(2u, fileInput->files()->length());
   EXPECT_EQ(String("/native/real/path1"), fileInput->files()->item(0)->path());
diff --git a/third_party/WebKit/Source/core/html/forms/FormController.cpp b/third_party/WebKit/Source/core/html/forms/FormController.cpp
index 42eaad3..975daedb 100644
--- a/third_party/WebKit/Source/core/html/forms/FormController.cpp
+++ b/third_party/WebKit/Source/core/html/forms/FormController.cpp
@@ -59,9 +59,9 @@
 
 void FormControlState::serializeTo(Vector<String>& stateVector) const {
   DCHECK(!isFailure());
-  stateVector.append(String::number(m_values.size()));
+  stateVector.push_back(String::number(m_values.size()));
   for (const auto& value : m_values)
-    stateVector.append(value.isNull() ? emptyString() : value);
+    stateVector.push_back(value.isNull() ? emptyString() : value);
 }
 
 FormControlState FormControlState::deserialize(
@@ -241,13 +241,13 @@
 }
 
 void SavedFormState::serializeTo(Vector<String>& stateVector) const {
-  stateVector.append(String::number(m_controlStateCount));
+  stateVector.push_back(String::number(m_controlStateCount));
   for (const auto& formControl : m_stateForNewFormElements) {
     const FormElementKey& key = formControl.key;
     const Deque<FormControlState>& queue = formControl.value;
     for (const FormControlState& formControlState : queue) {
-      stateVector.append(key.name());
-      stateVector.append(key.type());
+      stateVector.push_back(key.name());
+      stateVector.push_back(key.type());
       formControlState.serializeTo(stateVector);
     }
   }
@@ -296,7 +296,7 @@
           HTMLInputElement::filesFromFileInputFormControlState(
               formControlState);
       for (const auto& file : selectedFiles)
-        toReturn.append(file.path);
+        toReturn.push_back(file.path);
     }
   }
   return toReturn;
@@ -441,9 +441,9 @@
 
   Vector<String> stateVector;
   stateVector.reserveInitialCapacity(m_formControls.size() * 4);
-  stateVector.append(formStateSignature());
+  stateVector.push_back(formStateSignature());
   for (const auto& savedFormState : *stateMap) {
-    stateVector.append(savedFormState.key);
+    stateVector.push_back(savedFormState.key);
     savedFormState.value->serializeTo(stateVector);
   }
   bool hasOnlySignature = stateVector.size() == 1;
diff --git a/third_party/WebKit/Source/core/html/forms/FormController.h b/third_party/WebKit/Source/core/html/forms/FormController.h
index 6aadcfa5..871cd17 100644
--- a/third_party/WebKit/Source/core/html/forms/FormController.h
+++ b/third_party/WebKit/Source/core/html/forms/FormController.h
@@ -44,7 +44,7 @@
  public:
   FormControlState() : m_type(TypeSkip) {}
   explicit FormControlState(const String& value) : m_type(TypeRestore) {
-    m_values.append(value);
+    m_values.push_back(value);
   }
   static FormControlState deserialize(const Vector<String>& stateVector,
                                       size_t& index);
@@ -75,7 +75,7 @@
 
 inline void FormControlState::append(const String& value) {
   m_type = TypeRestore;
-  m_values.append(value);
+  m_values.push_back(value);
 }
 
 using SavedFormStateMap =
diff --git a/third_party/WebKit/Source/core/html/forms/RangeInputType.cpp b/third_party/WebKit/Source/core/html/forms/RangeInputType.cpp
index 926f555..190e8821 100644
--- a/third_party/WebKit/Source/core/html/forms/RangeInputType.cpp
+++ b/third_party/WebKit/Source/core/html/forms/RangeInputType.cpp
@@ -363,7 +363,7 @@
     String optionValue = optionElement->value();
     if (!this->element().isValidValue(optionValue))
       continue;
-    m_tickMarkValues.append(parseToNumber(optionValue, Decimal::nan()));
+    m_tickMarkValues.push_back(parseToNumber(optionValue, Decimal::nan()));
   }
   m_tickMarkValues.shrinkToFit();
   nonCopyingSort(m_tickMarkValues.begin(), m_tickMarkValues.end(),
diff --git a/third_party/WebKit/Source/core/html/imports/HTMLImport.cpp b/third_party/WebKit/Source/core/html/imports/HTMLImport.cpp
index 213dcea..77cd44a 100644
--- a/third_party/WebKit/Source/core/html/imports/HTMLImport.cpp
+++ b/third_party/WebKit/Source/core/html/imports/HTMLImport.cpp
@@ -103,7 +103,7 @@
     // Once the state reaches Ready, it shouldn't go back.
     DCHECK(!oldState.isReady() || oldState <= newState);
     if (newState != oldState)
-      updated.append(i);
+      updated.push_back(i);
   }
 
   for (const auto& import : updated)
diff --git a/third_party/WebKit/Source/core/html/imports/HTMLImportLoader.cpp b/third_party/WebKit/Source/core/html/imports/HTMLImportLoader.cpp
index 1b85900..84686bb 100644
--- a/third_party/WebKit/Source/core/html/imports/HTMLImportLoader.cpp
+++ b/third_party/WebKit/Source/core/html/imports/HTMLImportLoader.cpp
@@ -189,7 +189,7 @@
 void HTMLImportLoader::addImport(HTMLImportChild* import) {
   DCHECK_EQ(kNotFound, m_imports.find(import));
 
-  m_imports.append(import);
+  m_imports.push_back(import);
   import->normalize();
   if (isDone())
     import->didFinishLoading();
diff --git a/third_party/WebKit/Source/core/html/imports/HTMLImportTreeRoot.cpp b/third_party/WebKit/Source/core/html/imports/HTMLImportTreeRoot.cpp
index 47e1329..1a9c741 100644
--- a/third_party/WebKit/Source/core/html/imports/HTMLImportTreeRoot.cpp
+++ b/third_party/WebKit/Source/core/html/imports/HTMLImportTreeRoot.cpp
@@ -62,7 +62,7 @@
 }
 
 HTMLImportChild* HTMLImportTreeRoot::add(HTMLImportChild* child) {
-  m_imports.append(child);
+  m_imports.push_back(child);
   return m_imports.back().get();
 }
 
diff --git a/third_party/WebKit/Source/core/html/imports/HTMLImportsController.cpp b/third_party/WebKit/Source/core/html/imports/HTMLImportsController.cpp
index b5f43eb..ec9374d 100644
--- a/third_party/WebKit/Source/core/html/imports/HTMLImportsController.cpp
+++ b/third_party/WebKit/Source/core/html/imports/HTMLImportsController.cpp
@@ -133,7 +133,7 @@
 }
 
 HTMLImportLoader* HTMLImportsController::createLoader() {
-  m_loaders.append(HTMLImportLoader::create(this));
+  m_loaders.push_back(HTMLImportLoader::create(this));
   return m_loaders.back().get();
 }
 
diff --git a/third_party/WebKit/Source/core/html/parser/AtomicHTMLToken.h b/third_party/WebKit/Source/core/html/parser/AtomicHTMLToken.h
index c777839..4b0db8d 100644
--- a/third_party/WebKit/Source/core/html/parser/AtomicHTMLToken.h
+++ b/third_party/WebKit/Source/core/html/parser/AtomicHTMLToken.h
@@ -157,7 +157,7 @@
                              nullAtom);
           // FIXME: This is N^2 for the number of attributes.
           if (!findAttributeInVector(m_attributes, name))
-            m_attributes.append(
+            m_attributes.push_back(
                 Attribute(name, AtomicString(attribute.value())));
         }
       // Fall through!
@@ -233,7 +233,7 @@
     const QualifiedName& name = nameForAttribute(attribute);
     // FIXME: This is N^2 for the number of attributes.
     if (!findAttributeInVector(m_attributes, name))
-      m_attributes.append(Attribute(name, value));
+      m_attributes.push_back(Attribute(name, value));
   }
 }
 
diff --git a/third_party/WebKit/Source/core/html/parser/BackgroundHTMLInputStream.cpp b/third_party/WebKit/Source/core/html/parser/BackgroundHTMLInputStream.cpp
index dfcc058..a5e6a25f 100644
--- a/third_party/WebKit/Source/core/html/parser/BackgroundHTMLInputStream.cpp
+++ b/third_party/WebKit/Source/core/html/parser/BackgroundHTMLInputStream.cpp
@@ -34,7 +34,7 @@
 
 void BackgroundHTMLInputStream::append(const String& input) {
   m_current.append(SegmentedString(input));
-  m_segments.append(input);
+  m_segments.push_back(input);
 }
 
 void BackgroundHTMLInputStream::close() {
@@ -44,8 +44,8 @@
 HTMLInputCheckpoint BackgroundHTMLInputStream::createCheckpoint(
     size_t tokensExtractedSincePreviousCheckpoint) {
   HTMLInputCheckpoint checkpoint = m_checkpoints.size();
-  m_checkpoints.append(Checkpoint(m_current, m_segments.size(),
-                                  tokensExtractedSincePreviousCheckpoint));
+  m_checkpoints.push_back(Checkpoint(m_current, m_segments.size(),
+                                     tokensExtractedSincePreviousCheckpoint));
   m_totalCheckpointTokenCount += tokensExtractedSincePreviousCheckpoint;
   return checkpoint;
 }
diff --git a/third_party/WebKit/Source/core/html/parser/BackgroundHTMLParser.cpp b/third_party/WebKit/Source/core/html/parser/BackgroundHTMLParser.cpp
index f3e5bb14..df8fcc3 100644
--- a/third_party/WebKit/Source/core/html/parser/BackgroundHTMLParser.cpp
+++ b/third_party/WebKit/Source/core/html/parser/BackgroundHTMLParser.cpp
@@ -256,7 +256,7 @@
               FilterTokenRequest(*m_token, m_sourceTracker,
                                  m_tokenizer->shouldAllowCDATA()))) {
         xssInfo->m_textPosition = position;
-        m_pendingXSSInfos.append(std::move(xssInfo));
+        m_pendingXSSInfos.push_back(std::move(xssInfo));
       }
 
       CompactHTMLToken token(m_token.get(), position);
@@ -278,12 +278,13 @@
         m_startingScript = true;
       }
 
-      m_pendingTokens->append(token);
+      m_pendingTokens->push_back(token);
       if (isCSPMetaTag) {
         m_pendingCSPMetaTokenIndex = m_pendingTokens->size() - 1;
       }
       if (shouldEvaluateForDocumentWrite) {
-        m_likelyDocumentWriteScriptIndices.append(m_pendingTokens->size() - 1);
+        m_likelyDocumentWriteScriptIndices.push_back(m_pendingTokens->size() -
+                                                     1);
       }
     }
 
diff --git a/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.cpp b/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.cpp
index 3a5f00a1..7f6f76d 100644
--- a/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.cpp
+++ b/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.cpp
@@ -238,7 +238,7 @@
         Resource::CSSStyleSheet, m_referrerPolicy);
     if (request) {
       // FIXME: Should this be including the charset in the preload request?
-      m_requests->append(std::move(request));
+      m_requests->push_back(std::move(request));
     }
     m_state = Initial;
   } else if (equalIgnoringCase(m_rule, "charset"))
diff --git a/third_party/WebKit/Source/core/html/parser/CSSPreloadScannerTest.cpp b/third_party/WebKit/Source/core/html/parser/CSSPreloadScannerTest.cpp
index 17a87f9..e9ad6f5 100644
--- a/third_party/WebKit/Source/core/html/parser/CSSPreloadScannerTest.cpp
+++ b/third_party/WebKit/Source/core/html/parser/CSSPreloadScannerTest.cpp
@@ -41,7 +41,7 @@
 
   void fetchPreloads(PreloadRequestStream& preloads) override {
     for (const auto& it : preloads)
-      m_preloadUrls.append(it->resourceURL());
+      m_preloadUrls.push_back(it->resourceURL());
     CSSPreloaderResourceClient::fetchPreloads(preloads);
   }
 
diff --git a/third_party/WebKit/Source/core/html/parser/CompactHTMLToken.cpp b/third_party/WebKit/Source/core/html/parser/CompactHTMLToken.cpp
index c920a7b..a797db4e 100644
--- a/third_party/WebKit/Source/core/html/parser/CompactHTMLToken.cpp
+++ b/third_party/WebKit/Source/core/html/parser/CompactHTMLToken.cpp
@@ -55,7 +55,7 @@
 
       // There is only 1 DOCTYPE token per document, so to avoid increasing the
       // size of CompactHTMLToken, we just use the m_attributes vector.
-      m_attributes.append(Attribute(
+      m_attributes.push_back(Attribute(
           attemptStaticStringCreation(token->publicIdentifier(), Likely8Bit),
           String(token->systemIdentifier())));
       m_doctypeForcesQuirks = token->forceQuirks();
@@ -66,7 +66,7 @@
     case HTMLToken::StartTag:
       m_attributes.reserveInitialCapacity(token->attributes().size());
       for (const HTMLToken::Attribute& attribute : token->attributes())
-        m_attributes.append(
+        m_attributes.push_back(
             Attribute(attribute.nameAttemptStaticStringCreation(),
                       attribute.value8BitIfNecessary()));
     // Fall through!
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.cpp b/third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.cpp
index 499703e0..bb6717f 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.cpp
@@ -277,7 +277,7 @@
 void HTMLConstructionSite::queueTask(const HTMLConstructionSiteTask& task) {
   flushPendingText(FlushAlways);
   ASSERT(m_pendingText.isEmpty());
-  m_taskQueue.append(task);
+  m_taskQueue.push_back(task);
 }
 
 void HTMLConstructionSite::attachLater(ContainerNode* parent,
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp b/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp
index 6f29385a..d2e0a7e 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp
@@ -347,14 +347,14 @@
         // Link rel preloads don't need to wait for AppCache but they
         // should probably wait for CSP.
         if (!m_pendingCSPMetaToken && request->isLinkRelPreload())
-          linkRelPreloads.append(std::move(request));
+          linkRelPreloads.push_back(std::move(request));
         else
-          m_queuedPreloads.append(std::move(request));
+          m_queuedPreloads.push_back(std::move(request));
       }
       for (auto& index : chunk->likelyDocumentWriteScriptIndices) {
         const CompactHTMLToken& token = chunk->tokens->at(index);
         ASSERT(token.type() == HTMLToken::TokenType::Character);
-        m_queuedDocumentWriteScripts.append(token.data());
+        m_queuedDocumentWriteScripts.push_back(token.data());
       }
     }
     m_preloader->takeAndPreload(linkRelPreloads);
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLEntityParser.cpp b/third_party/WebKit/Source/core/html/parser/HTMLEntityParser.cpp
index c9c59b5..e14d0d08 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLEntityParser.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLEntityParser.cpp
@@ -110,7 +110,7 @@
     entitySearch.advance(cc);
     if (!entitySearch.isEntityPrefix())
       break;
-    consumedCharacters.append(cc);
+    consumedCharacters.push_back(cc);
     source.advanceAndASSERT(cc);
   }
   notEnoughCharacters = source.isEmpty();
@@ -136,7 +136,7 @@
     for (int i = 0; i < length; ++i) {
       cc = source.currentChar();
       DCHECK_EQ(cc, static_cast<UChar>(*reference++));
-      consumedCharacters.append(cc);
+      consumedCharacters.push_back(cc);
       source.advanceAndASSERT(cc);
       ASSERT(!source.isEmpty());
     }
@@ -266,7 +266,7 @@
     if (result > UCHAR_MAX_VALUE)
       result = kInvalidUnicode;
 
-    consumedCharacters.append(cc);
+    consumedCharacters.push_back(cc);
     source.advanceAndASSERT(cc);
   }
   ASSERT(source.isEmpty());
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLFormattingElementList.cpp b/third_party/WebKit/Source/core/html/parser/HTMLFormattingElementList.cpp
index 2fcba8b1..7df9ed04 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLFormattingElementList.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLFormattingElementList.cpp
@@ -92,7 +92,7 @@
 
 void HTMLFormattingElementList::append(HTMLStackItem* item) {
   ensureNoahsArkCondition(item);
-  m_entries.append(item);
+  m_entries.push_back(item);
 }
 
 void HTMLFormattingElementList::remove(Element* element) {
@@ -102,7 +102,7 @@
 }
 
 void HTMLFormattingElementList::appendMarker() {
-  m_entries.append(Entry::MarkerEntry);
+  m_entries.push_back(Entry::MarkerEntry);
 }
 
 void HTMLFormattingElementList::clearToLastMarker() {
@@ -143,7 +143,7 @@
     if (candidate->attributes().size() != newItemAttributeCount)
       continue;
 
-    candidates.append(candidate);
+    candidates.push_back(candidate);
   }
 
   // There's room for the new element in the ark. There's no need to copy out
@@ -178,7 +178,7 @@
           candidate->getAttributeItem(attribute.name());
       if (candidateAttribute &&
           candidateAttribute->value() == attribute.value())
-        remainingCandidates.append(candidate);
+        remainingCandidates.push_back(candidate);
     }
 
     if (remainingCandidates.size() < kNoahsArkCapacity)
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLMetaCharsetParser.cpp b/third_party/WebKit/Source/core/html/parser/HTMLMetaCharsetParser.cpp
index fac2787d..37e6614d 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLMetaCharsetParser.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLMetaCharsetParser.cpp
@@ -52,7 +52,7 @@
   for (const HTMLToken::Attribute& tokenAttribute : tokenAttributes) {
     String attributeName = tokenAttribute.nameAttemptStaticStringCreation();
     String attributeValue = tokenAttribute.value8BitIfNecessary();
-    attributes.append(std::make_pair(attributeName, attributeValue));
+    attributes.push_back(std::make_pair(attributeName, attributeValue));
   }
 
   m_encoding = encodingFromMetaAttributes(attributes);
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLParserIdioms.cpp b/third_party/WebKit/Source/core/html/parser/HTMLParserIdioms.cpp
index 4710b2b9..b9bf250 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLParserIdioms.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLParserIdioms.cpp
@@ -329,7 +329,7 @@
     size_t parsedLength = 0;
     double number = charactersToDouble(
         unparsedNumberStart, position - unparsedNumberStart, parsedLength);
-    numbers.append(checkDoubleValue(number, parsedLength != 0, 0));
+    numbers.push_back(checkDoubleValue(number, parsedLength != 0, 0));
 
     skipWhile<CharacterType, isSpaceOrDelimiter>(position, end);
   }
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp b/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp
index 01f22d7d..b15ceb4 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp
@@ -551,8 +551,8 @@
 
 TokenPreloadScannerCheckpoint TokenPreloadScanner::createCheckpoint() {
   TokenPreloadScannerCheckpoint checkpoint = m_checkpoints.size();
-  m_checkpoints.append(Checkpoint(m_predictedBaseElementURL, m_inStyle,
-                                  m_inScript, m_templateCount));
+  m_checkpoints.push_back(Checkpoint(m_predictedBaseElementURL, m_inStyle,
+                                     m_inScript, m_templateCount));
   return checkpoint;
 }
 
@@ -815,7 +815,7 @@
           m_predictedBaseElementURL, source, m_clientHintsPreferences,
           m_pictureData, m_documentParameters->referrerPolicy);
       if (request)
-        requests.append(std::move(request));
+        requests.push_back(std::move(request));
       return;
     }
     default: { return; }
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLToken.h b/third_party/WebKit/Source/core/html/parser/HTMLToken.h
index 45c2af7..907b1fd3 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLToken.h
+++ b/third_party/WebKit/Source/core/html/parser/HTMLToken.h
@@ -116,14 +116,14 @@
     }
     const Vector<UChar, 32>& nameAsVector() const { return m_name; }
 
-    void appendToName(UChar c) { m_name.append(c); }
+    void appendToName(UChar c) { m_name.push_back(c); }
 
     PassRefPtr<StringImpl> value8BitIfNecessary() const {
       return StringImpl::create8BitIfPossible(m_value);
     }
     String value() const { return String(m_value); }
 
-    void appendToValue(UChar c) { m_value.append(c); }
+    void appendToValue(UChar c) { m_value.push_back(c); }
     void appendToValue(const String& value) { value.appendTo(m_value); }
     void clearValue() { m_value.clear(); }
 
@@ -195,7 +195,7 @@
   void appendToName(UChar character) {
     ASSERT(m_type == StartTag || m_type == EndTag || m_type == DOCTYPE);
     ASSERT(character);
-    m_data.append(character);
+    m_data.push_back(character);
     m_orAllData |= character;
   }
 
@@ -220,7 +220,7 @@
   void beginDOCTYPE(UChar character) {
     ASSERT(character);
     beginDOCTYPE();
-    m_data.append(character);
+    m_data.push_back(character);
     m_orAllData |= character;
   }
 
@@ -252,14 +252,14 @@
     ASSERT(character);
     ASSERT(m_type == DOCTYPE);
     ASSERT(m_doctypeData->m_hasPublicIdentifier);
-    m_doctypeData->m_publicIdentifier.append(character);
+    m_doctypeData->m_publicIdentifier.push_back(character);
   }
 
   void appendToSystemIdentifier(UChar character) {
     ASSERT(character);
     ASSERT(m_type == DOCTYPE);
     ASSERT(m_doctypeData->m_hasSystemIdentifier);
-    m_doctypeData->m_systemIdentifier.append(character);
+    m_doctypeData->m_systemIdentifier.push_back(character);
   }
 
   std::unique_ptr<DoctypeData> releaseDoctypeData() {
@@ -286,7 +286,7 @@
     m_currentAttribute = 0;
     m_attributes.clear();
 
-    m_data.append(character);
+    m_data.push_back(character);
     m_orAllData |= character;
   }
 
@@ -297,7 +297,7 @@
     m_currentAttribute = 0;
     m_attributes.clear();
 
-    m_data.append(character);
+    m_data.push_back(character);
   }
 
   void beginEndTag(const Vector<LChar, 32>& characters) {
@@ -397,12 +397,12 @@
 
   void appendToCharacter(char character) {
     ASSERT(m_type == Character);
-    m_data.append(character);
+    m_data.push_back(character);
   }
 
   void appendToCharacter(UChar character) {
     ASSERT(m_type == Character);
-    m_data.append(character);
+    m_data.push_back(character);
     m_orAllData |= character;
   }
 
@@ -426,7 +426,7 @@
   void appendToComment(UChar character) {
     ASSERT(character);
     ASSERT(m_type == Comment);
-    m_data.append(character);
+    m_data.push_back(character);
     m_orAllData |= character;
   }
 
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLTokenizer.cpp b/third_party/WebKit/Source/core/html/parser/HTMLTokenizer.cpp
index 3c104d5..44f65dd 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLTokenizer.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLTokenizer.cpp
@@ -332,11 +332,11 @@
 
     HTML_BEGIN_STATE(RCDATAEndTagOpenState) {
       if (isASCIIUpper(cc)) {
-        m_temporaryBuffer.append(static_cast<LChar>(cc));
+        m_temporaryBuffer.push_back(static_cast<LChar>(cc));
         addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
         HTML_ADVANCE_TO(RCDATAEndTagNameState);
       } else if (isASCIILower(cc)) {
-        m_temporaryBuffer.append(static_cast<LChar>(cc));
+        m_temporaryBuffer.push_back(static_cast<LChar>(cc));
         addToPossibleEndTag(static_cast<LChar>(cc));
         HTML_ADVANCE_TO(RCDATAEndTagNameState);
       } else {
@@ -349,27 +349,27 @@
 
     HTML_BEGIN_STATE(RCDATAEndTagNameState) {
       if (isASCIIUpper(cc)) {
-        m_temporaryBuffer.append(static_cast<LChar>(cc));
+        m_temporaryBuffer.push_back(static_cast<LChar>(cc));
         addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
         HTML_ADVANCE_TO(RCDATAEndTagNameState);
       } else if (isASCIILower(cc)) {
-        m_temporaryBuffer.append(static_cast<LChar>(cc));
+        m_temporaryBuffer.push_back(static_cast<LChar>(cc));
         addToPossibleEndTag(static_cast<LChar>(cc));
         HTML_ADVANCE_TO(RCDATAEndTagNameState);
       } else {
         if (isTokenizerWhitespace(cc)) {
           if (isAppropriateEndTag()) {
-            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            m_temporaryBuffer.push_back(static_cast<LChar>(cc));
             FLUSH_AND_ADVANCE_TO(BeforeAttributeNameState);
           }
         } else if (cc == '/') {
           if (isAppropriateEndTag()) {
-            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            m_temporaryBuffer.push_back(static_cast<LChar>(cc));
             FLUSH_AND_ADVANCE_TO(SelfClosingStartTagState);
           }
         } else if (cc == '>') {
           if (isAppropriateEndTag()) {
-            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            m_temporaryBuffer.push_back(static_cast<LChar>(cc));
             return flushEmitAndResumeIn(source, HTMLTokenizer::DataState);
           }
         }
@@ -397,11 +397,11 @@
 
     HTML_BEGIN_STATE(RAWTEXTEndTagOpenState) {
       if (isASCIIUpper(cc)) {
-        m_temporaryBuffer.append(static_cast<LChar>(cc));
+        m_temporaryBuffer.push_back(static_cast<LChar>(cc));
         addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
         HTML_ADVANCE_TO(RAWTEXTEndTagNameState);
       } else if (isASCIILower(cc)) {
-        m_temporaryBuffer.append(static_cast<LChar>(cc));
+        m_temporaryBuffer.push_back(static_cast<LChar>(cc));
         addToPossibleEndTag(static_cast<LChar>(cc));
         HTML_ADVANCE_TO(RAWTEXTEndTagNameState);
       } else {
@@ -414,27 +414,27 @@
 
     HTML_BEGIN_STATE(RAWTEXTEndTagNameState) {
       if (isASCIIUpper(cc)) {
-        m_temporaryBuffer.append(static_cast<LChar>(cc));
+        m_temporaryBuffer.push_back(static_cast<LChar>(cc));
         addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
         HTML_ADVANCE_TO(RAWTEXTEndTagNameState);
       } else if (isASCIILower(cc)) {
-        m_temporaryBuffer.append(static_cast<LChar>(cc));
+        m_temporaryBuffer.push_back(static_cast<LChar>(cc));
         addToPossibleEndTag(static_cast<LChar>(cc));
         HTML_ADVANCE_TO(RAWTEXTEndTagNameState);
       } else {
         if (isTokenizerWhitespace(cc)) {
           if (isAppropriateEndTag()) {
-            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            m_temporaryBuffer.push_back(static_cast<LChar>(cc));
             FLUSH_AND_ADVANCE_TO(BeforeAttributeNameState);
           }
         } else if (cc == '/') {
           if (isAppropriateEndTag()) {
-            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            m_temporaryBuffer.push_back(static_cast<LChar>(cc));
             FLUSH_AND_ADVANCE_TO(SelfClosingStartTagState);
           }
         } else if (cc == '>') {
           if (isAppropriateEndTag()) {
-            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            m_temporaryBuffer.push_back(static_cast<LChar>(cc));
             return flushEmitAndResumeIn(source, HTMLTokenizer::DataState);
           }
         }
@@ -466,11 +466,11 @@
 
     HTML_BEGIN_STATE(ScriptDataEndTagOpenState) {
       if (isASCIIUpper(cc)) {
-        m_temporaryBuffer.append(static_cast<LChar>(cc));
+        m_temporaryBuffer.push_back(static_cast<LChar>(cc));
         addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
         HTML_ADVANCE_TO(ScriptDataEndTagNameState);
       } else if (isASCIILower(cc)) {
-        m_temporaryBuffer.append(static_cast<LChar>(cc));
+        m_temporaryBuffer.push_back(static_cast<LChar>(cc));
         addToPossibleEndTag(static_cast<LChar>(cc));
         HTML_ADVANCE_TO(ScriptDataEndTagNameState);
       } else {
@@ -483,27 +483,27 @@
 
     HTML_BEGIN_STATE(ScriptDataEndTagNameState) {
       if (isASCIIUpper(cc)) {
-        m_temporaryBuffer.append(static_cast<LChar>(cc));
+        m_temporaryBuffer.push_back(static_cast<LChar>(cc));
         addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
         HTML_ADVANCE_TO(ScriptDataEndTagNameState);
       } else if (isASCIILower(cc)) {
-        m_temporaryBuffer.append(static_cast<LChar>(cc));
+        m_temporaryBuffer.push_back(static_cast<LChar>(cc));
         addToPossibleEndTag(static_cast<LChar>(cc));
         HTML_ADVANCE_TO(ScriptDataEndTagNameState);
       } else {
         if (isTokenizerWhitespace(cc)) {
           if (isAppropriateEndTag()) {
-            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            m_temporaryBuffer.push_back(static_cast<LChar>(cc));
             FLUSH_AND_ADVANCE_TO(BeforeAttributeNameState);
           }
         } else if (cc == '/') {
           if (isAppropriateEndTag()) {
-            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            m_temporaryBuffer.push_back(static_cast<LChar>(cc));
             FLUSH_AND_ADVANCE_TO(SelfClosingStartTagState);
           }
         } else if (cc == '>') {
           if (isAppropriateEndTag()) {
-            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            m_temporaryBuffer.push_back(static_cast<LChar>(cc));
             return flushEmitAndResumeIn(source, HTMLTokenizer::DataState);
           }
         }
@@ -595,13 +595,13 @@
         bufferCharacter('<');
         bufferCharacter(cc);
         m_temporaryBuffer.clear();
-        m_temporaryBuffer.append(toLowerCase(cc));
+        m_temporaryBuffer.push_back(toLowerCase(cc));
         HTML_ADVANCE_TO(ScriptDataDoubleEscapeStartState);
       } else if (isASCIILower(cc)) {
         bufferCharacter('<');
         bufferCharacter(cc);
         m_temporaryBuffer.clear();
-        m_temporaryBuffer.append(static_cast<LChar>(cc));
+        m_temporaryBuffer.push_back(static_cast<LChar>(cc));
         HTML_ADVANCE_TO(ScriptDataDoubleEscapeStartState);
       } else {
         bufferCharacter('<');
@@ -612,11 +612,11 @@
 
     HTML_BEGIN_STATE(ScriptDataEscapedEndTagOpenState) {
       if (isASCIIUpper(cc)) {
-        m_temporaryBuffer.append(static_cast<LChar>(cc));
+        m_temporaryBuffer.push_back(static_cast<LChar>(cc));
         addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
         HTML_ADVANCE_TO(ScriptDataEscapedEndTagNameState);
       } else if (isASCIILower(cc)) {
-        m_temporaryBuffer.append(static_cast<LChar>(cc));
+        m_temporaryBuffer.push_back(static_cast<LChar>(cc));
         addToPossibleEndTag(static_cast<LChar>(cc));
         HTML_ADVANCE_TO(ScriptDataEscapedEndTagNameState);
       } else {
@@ -629,27 +629,27 @@
 
     HTML_BEGIN_STATE(ScriptDataEscapedEndTagNameState) {
       if (isASCIIUpper(cc)) {
-        m_temporaryBuffer.append(static_cast<LChar>(cc));
+        m_temporaryBuffer.push_back(static_cast<LChar>(cc));
         addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
         HTML_ADVANCE_TO(ScriptDataEscapedEndTagNameState);
       } else if (isASCIILower(cc)) {
-        m_temporaryBuffer.append(static_cast<LChar>(cc));
+        m_temporaryBuffer.push_back(static_cast<LChar>(cc));
         addToPossibleEndTag(static_cast<LChar>(cc));
         HTML_ADVANCE_TO(ScriptDataEscapedEndTagNameState);
       } else {
         if (isTokenizerWhitespace(cc)) {
           if (isAppropriateEndTag()) {
-            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            m_temporaryBuffer.push_back(static_cast<LChar>(cc));
             FLUSH_AND_ADVANCE_TO(BeforeAttributeNameState);
           }
         } else if (cc == '/') {
           if (isAppropriateEndTag()) {
-            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            m_temporaryBuffer.push_back(static_cast<LChar>(cc));
             FLUSH_AND_ADVANCE_TO(SelfClosingStartTagState);
           }
         } else if (cc == '>') {
           if (isAppropriateEndTag()) {
-            m_temporaryBuffer.append(static_cast<LChar>(cc));
+            m_temporaryBuffer.push_back(static_cast<LChar>(cc));
             return flushEmitAndResumeIn(source, HTMLTokenizer::DataState);
           }
         }
@@ -672,11 +672,11 @@
           HTML_ADVANCE_TO(ScriptDataEscapedState);
       } else if (isASCIIUpper(cc)) {
         bufferCharacter(cc);
-        m_temporaryBuffer.append(toLowerCase(cc));
+        m_temporaryBuffer.push_back(toLowerCase(cc));
         HTML_ADVANCE_TO(ScriptDataDoubleEscapeStartState);
       } else if (isASCIILower(cc)) {
         bufferCharacter(cc);
-        m_temporaryBuffer.append(static_cast<LChar>(cc));
+        m_temporaryBuffer.push_back(static_cast<LChar>(cc));
         HTML_ADVANCE_TO(ScriptDataDoubleEscapeStartState);
       } else
         HTML_RECONSUME_IN(ScriptDataEscapedState);
@@ -756,11 +756,11 @@
           HTML_ADVANCE_TO(ScriptDataDoubleEscapedState);
       } else if (isASCIIUpper(cc)) {
         bufferCharacter(cc);
-        m_temporaryBuffer.append(toLowerCase(cc));
+        m_temporaryBuffer.push_back(toLowerCase(cc));
         HTML_ADVANCE_TO(ScriptDataDoubleEscapeEndState);
       } else if (isASCIILower(cc)) {
         bufferCharacter(cc);
-        m_temporaryBuffer.append(static_cast<LChar>(cc));
+        m_temporaryBuffer.push_back(static_cast<LChar>(cc));
         HTML_ADVANCE_TO(ScriptDataDoubleEscapeEndState);
       } else
         HTML_RECONSUME_IN(ScriptDataDoubleEscapedState);
@@ -1566,7 +1566,7 @@
 
 inline void HTMLTokenizer::addToPossibleEndTag(LChar cc) {
   ASSERT(isEndTagBufferingState(m_state));
-  m_bufferedEndTagName.append(cc);
+  m_bufferedEndTagName.push_back(cc);
 }
 
 inline bool HTMLTokenizer::isAppropriateEndTag() {
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilder.cpp b/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilder.cpp
index 9fff25be..151842e 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilder.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilder.cpp
@@ -254,7 +254,7 @@
       fragment, HTMLStackItem::ItemForDocumentFragmentNode));
 
   if (isHTMLTemplateElement(*contextElement))
-    m_templateInsertionModes.append(TemplateContentsMode);
+    m_templateInsertionModes.push_back(TemplateContentsMode);
 
   resetInsertionModeAppropriately();
 }
@@ -851,7 +851,7 @@
   m_tree.activeFormattingElements()->appendMarker();
   m_tree.insertHTMLElement(token);
   m_framesetOk = false;
-  m_templateInsertionModes.append(TemplateContentsMode);
+  m_templateInsertionModes.push_back(TemplateContentsMode);
   setInsertionMode(TemplateContentsMode);
 }
 
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilderSimulator.cpp b/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilderSimulator.cpp
index 17d9757..75b31a8 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilderSimulator.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilderSimulator.cpp
@@ -95,7 +95,7 @@
 HTMLTreeBuilderSimulator::HTMLTreeBuilderSimulator(
     const HTMLParserOptions& options)
     : m_options(options) {
-  m_namespaceStack.append(HTML);
+  m_namespaceStack.push_back(HTML);
 }
 
 HTMLTreeBuilderSimulator::State HTMLTreeBuilderSimulator::stateFor(
@@ -112,7 +112,7 @@
       currentNamespace = MathML;
 
     if (namespaceStack.isEmpty() || namespaceStack.back() != currentNamespace)
-      namespaceStack.append(currentNamespace);
+      namespaceStack.push_back(currentNamespace);
   }
   namespaceStack.reverse();
   return namespaceStack;
@@ -126,14 +126,14 @@
   if (token.type() == HTMLToken::StartTag) {
     const String& tagName = token.data();
     if (threadSafeMatch(tagName, SVGNames::svgTag))
-      m_namespaceStack.append(SVG);
+      m_namespaceStack.push_back(SVG);
     if (threadSafeMatch(tagName, MathMLNames::mathTag))
-      m_namespaceStack.append(MathML);
+      m_namespaceStack.push_back(MathML);
     if (inForeignContent() && tokenExitsForeignContent(token))
       m_namespaceStack.pop_back();
     if ((m_namespaceStack.back() == SVG && tokenExitsSVG(token)) ||
         (m_namespaceStack.back() == MathML && tokenExitsMath(token)))
-      m_namespaceStack.append(HTML);
+      m_namespaceStack.push_back(HTML);
     if (!inForeignContent()) {
       // FIXME: This is just a copy of Tokenizer::updateStateFor which uses
       // threadSafeMatches.
diff --git a/third_party/WebKit/Source/core/html/parser/TextDocumentParser.cpp b/third_party/WebKit/Source/core/html/parser/TextDocumentParser.cpp
index 710add36..f9f95aff 100644
--- a/third_party/WebKit/Source/core/html/parser/TextDocumentParser.cpp
+++ b/third_party/WebKit/Source/core/html/parser/TextDocumentParser.cpp
@@ -52,7 +52,7 @@
   // fake bytes through the front-end of the parser to avoid distrubing the
   // line/column number calculations.
   Vector<Attribute> attributes;
-  attributes.append(
+  attributes.push_back(
       Attribute(styleAttr, "word-wrap: break-word; white-space: pre-wrap;"));
   AtomicHTMLToken fakePre(HTMLToken::StartTag, preTag.localName(), attributes);
   treeBuilder()->constructTree(&fakePre);
diff --git a/third_party/WebKit/Source/core/html/parser/TokenizedChunkQueue.cpp b/third_party/WebKit/Source/core/html/parser/TokenizedChunkQueue.cpp
index f358e85..2efb34c 100644
--- a/third_party/WebKit/Source/core/html/parser/TokenizedChunkQueue.cpp
+++ b/third_party/WebKit/Source/core/html/parser/TokenizedChunkQueue.cpp
@@ -47,7 +47,7 @@
       std::max(m_peakPendingTokenCount, m_pendingTokenCount);
 
   bool wasEmpty = m_pendingChunks.isEmpty();
-  m_pendingChunks.append(std::move(chunk));
+  m_pendingChunks.push_back(std::move(chunk));
   m_peakPendingChunkCount =
       std::max(m_peakPendingChunkCount, m_pendingChunks.size());
 
diff --git a/third_party/WebKit/Source/core/html/shadow/DateTimeEditElement.cpp b/third_party/WebKit/Source/core/html/shadow/DateTimeEditElement.cpp
index 425102b..8505f9b 100644
--- a/third_party/WebKit/Source/core/html/shadow/DateTimeEditElement.cpp
+++ b/third_party/WebKit/Source/core/html/shadow/DateTimeEditElement.cpp
@@ -530,7 +530,7 @@
 void DateTimeEditElement::addField(DateTimeFieldElement* field) {
   if (m_fields.size() >= maximumNumberOfFields)
     return;
-  m_fields.append(field);
+  m_fields.push_back(field);
   fieldsWrapperElement()->appendChild(field);
 }
 
diff --git a/third_party/WebKit/Source/core/html/track/AutomaticTrackSelection.cpp b/third_party/WebKit/Source/core/html/track/AutomaticTrackSelection.cpp
index 651d790..34e4935 100644
--- a/third_party/WebKit/Source/core/html/track/AutomaticTrackSelection.cpp
+++ b/third_party/WebKit/Source/core/html/track/AutomaticTrackSelection.cpp
@@ -78,7 +78,7 @@
   for (const auto& textTrack : group.tracks) {
     if (m_configuration.disableCurrentlyEnabledTracks &&
         textTrack->mode() == TextTrack::showingKeyword())
-      currentlyEnabledTracks.append(textTrack);
+      currentlyEnabledTracks.push_back(textTrack);
 
     int trackScore = textTrackSelectionScore(*textTrack);
 
@@ -197,7 +197,7 @@
 
     if (textTrack->language().length())
       currentGroup->hasSrcLang = true;
-    currentGroup->tracks.append(textTrack);
+    currentGroup->tracks.push_back(textTrack);
   }
 
   if (captionAndSubtitleTracks.tracks.size())
diff --git a/third_party/WebKit/Source/core/html/track/CueTimeline.cpp b/third_party/WebKit/Source/core/html/track/CueTimeline.cpp
index 718106b..c0eb21b2 100644
--- a/third_party/WebKit/Source/core/html/track/CueTimeline.cpp
+++ b/third_party/WebKit/Source/core/html/track/CueTimeline.cpp
@@ -171,7 +171,7 @@
       // Consider cues that may have been missed since the last seek time.
       if (cue.low() > std::max(lastSeekTime, lastTime) &&
           cue.high() < movieTime)
-        missedCues.append(cue);
+        missedCues.push_back(cue);
     }
   }
 
@@ -245,7 +245,7 @@
   for (const auto& missedCue : missedCues) {
     // 9 - For each text track cue in missed cues, prepare an event named enter
     // for the TextTrackCue object with the text track cue start time.
-    eventTasks.append(
+    eventTasks.push_back(
         std::make_pair(missedCue.data()->startTime(), missedCue.data()));
 
     // 10 - For each text track [...] in missed cues, prepare an event
@@ -258,7 +258,7 @@
     // affect sorting events before dispatch either, because the exit
     // event has the same time as the enter event.
     if (missedCue.data()->startTime() < missedCue.data()->endTime()) {
-      eventTasks.append(
+      eventTasks.push_back(
           std::make_pair(missedCue.data()->endTime(), missedCue.data()));
     }
   }
@@ -268,7 +268,7 @@
     // track cue active flag set prepare an event named exit for the
     // TextTrackCue object with the text track cue end time.
     if (!currentCues.contains(previousCue)) {
-      eventTasks.append(
+      eventTasks.push_back(
           std::make_pair(previousCue.data()->endTime(), previousCue.data()));
     }
   }
@@ -278,7 +278,7 @@
     // text track cue active flag set, prepare an event named enter for the
     // TextTrackCue object with the text track cue start time.
     if (!previousCues.contains(currentCue)) {
-      eventTasks.append(
+      eventTasks.push_back(
           std::make_pair(currentCue.data()->startTime(), currentCue.data()));
     }
   }
@@ -289,7 +289,7 @@
 
   for (const auto& task : eventTasks) {
     if (!affectedTracks.contains(task.second->track()))
-      affectedTracks.append(task.second->track());
+      affectedTracks.push_back(task.second->track());
 
     // 13 - Queue each task in events, in list order.
 
diff --git a/third_party/WebKit/Source/core/html/track/TextTrackList.cpp b/third_party/WebKit/Source/core/html/track/TextTrackList.cpp
index 05f5292..5defe1d 100644
--- a/third_party/WebKit/Source/core/html/track/TextTrackList.cpp
+++ b/third_party/WebKit/Source/core/html/track/TextTrackList.cpp
@@ -168,13 +168,13 @@
 
 void TextTrackList::append(TextTrack* track) {
   if (track->trackType() == TextTrack::AddTrack) {
-    m_addTrackTracks.append(TraceWrapperMember<TextTrack>(this, track));
+    m_addTrackTracks.push_back(TraceWrapperMember<TextTrack>(this, track));
   } else if (track->trackType() == TextTrack::TrackElement) {
     // Insert tracks added for <track> element in tree order.
     size_t index = static_cast<LoadableTextTrack*>(track)->trackElementIndex();
     m_elementTracks.insert(index, TraceWrapperMember<TextTrack>(this, track));
   } else if (track->trackType() == TextTrack::InBand) {
-    m_inbandTracks.append(TraceWrapperMember<TextTrack>(this, track));
+    m_inbandTracks.push_back(TraceWrapperMember<TextTrack>(this, track));
   } else {
     NOTREACHED();
   }
diff --git a/third_party/WebKit/Source/core/html/track/TrackListBase.h b/third_party/WebKit/Source/core/html/track/TrackListBase.h
index 05bb6cf..391ec942 100644
--- a/third_party/WebKit/Source/core/html/track/TrackListBase.h
+++ b/third_party/WebKit/Source/core/html/track/TrackListBase.h
@@ -50,7 +50,7 @@
 
   void add(T* track) {
     track->setMediaElement(m_mediaElement);
-    m_tracks.append(TraceWrapperMember<T>(this, track));
+    m_tracks.push_back(TraceWrapperMember<T>(this, track));
     scheduleEvent(TrackEvent::create(EventTypeNames::addtrack, track));
   }
 
diff --git a/third_party/WebKit/Source/core/html/track/vtt/VTTParser.cpp b/third_party/WebKit/Source/core/html/track/vtt/VTTParser.cpp
index 54e1fb8..6d589565 100644
--- a/third_party/WebKit/Source/core/html/track/vtt/VTTParser.cpp
+++ b/third_party/WebKit/Source/core/html/track/vtt/VTTParser.cpp
@@ -378,7 +378,7 @@
   cue->setId(m_currentId);
   cue->parseSettings(m_currentSettings);
 
-  m_cueList.append(cue);
+  m_cueList.push_back(cue);
   if (m_client)
     m_client->newCuesParsed();
 }
@@ -409,7 +409,7 @@
   }
 
   // Step 12.5.11
-  m_regionList.append(region);
+  m_regionList.push_back(region);
 }
 
 bool VTTParser::collectTimeStamp(const String& line, double& timeStamp) {
@@ -522,7 +522,7 @@
         child->setAttribute(VTTElement::voiceAttributeName(),
                             m_token.annotation());
       } else if (nodeType == VTTNodeTypeLanguage) {
-        m_languageStack.append(m_token.annotation());
+        m_languageStack.push_back(m_token.annotation());
         child->setAttribute(VTTElement::langAttributeName(),
                             m_languageStack.back());
       }
diff --git a/third_party/WebKit/Source/core/html/track/vtt/VTTRegionList.cpp b/third_party/WebKit/Source/core/html/track/vtt/VTTRegionList.cpp
index d0671f0..c386e33 100644
--- a/third_party/WebKit/Source/core/html/track/vtt/VTTRegionList.cpp
+++ b/third_party/WebKit/Source/core/html/track/vtt/VTTRegionList.cpp
@@ -53,7 +53,7 @@
 }
 
 void VTTRegionList::add(VTTRegion* region) {
-  m_list.append(region);
+  m_list.push_back(region);
 }
 
 bool VTTRegionList::remove(VTTRegion* region) {
diff --git a/third_party/WebKit/Source/core/layout/LayoutThemeFontProviderWin.cpp b/third_party/WebKit/Source/core/layout/LayoutThemeFontProviderWin.cpp
index 33a5651..d44861c 100644
--- a/third_party/WebKit/Source/core/layout/LayoutThemeFontProviderWin.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutThemeFontProviderWin.cpp
@@ -34,8 +34,8 @@
 
 // Converts |points| to pixels. One point is 1/72 of an inch.
 static float pointsToPixels(float points) {
-  float pixelsPerInch = 96.0f * FontCache::deviceScaleFactor();
-  static const float pointsPerInch = 72.0f;
+  const float pixelsPerInch = 96.0f;
+  const float pointsPerInch = 72.0f;
   return points / pointsPerInch * pixelsPerInch;
 }
 
diff --git a/third_party/WebKit/Source/core/layout/line/InlineTextBox.cpp b/third_party/WebKit/Source/core/layout/line/InlineTextBox.cpp
index 0dbf55c..6d01393 100644
--- a/third_party/WebKit/Source/core/layout/line/InlineTextBox.cpp
+++ b/third_party/WebKit/Source/core/layout/line/InlineTextBox.cpp
@@ -616,6 +616,10 @@
   String string = getLineLayoutItem().text();
   unsigned startPos = start();
   unsigned length = len();
+  // Ensure |this| is in sync with the corresponding LayoutText. Checking here
+  // has less binary size/perf impact than in StringView().
+  RELEASE_ASSERT(startPos <= string.length() &&
+                 length <= string.length() - startPos);
   return constructTextRun(style, StringView(string, startPos, length),
                           getLineLayoutItem().textLength() - startPos,
                           charactersWithHyphen);
diff --git a/third_party/WebKit/Source/core/loader/MixedContentCheckerTest.cpp b/third_party/WebKit/Source/core/loader/MixedContentCheckerTest.cpp
index ffd2687..2d7ba2b6 100644
--- a/third_party/WebKit/Source/core/loader/MixedContentCheckerTest.cpp
+++ b/third_party/WebKit/Source/core/loader/MixedContentCheckerTest.cpp
@@ -38,6 +38,7 @@
       {"https://example.com/foo", "blob:null/foo", false},
       {"https://example.com/foo", "filesystem:https://example.com/foo", false},
       {"https://example.com/foo", "filesystem:http://example.com/foo", false},
+      {"https://example.com/foo", "filesystem:null/foo", false},
 
       {"https://example.com/foo", "http://example.com/foo", true},
       {"https://example.com/foo", "http://google.com/foo", true},
diff --git a/third_party/WebKit/Source/core/offscreencanvas/BUILD.gn b/third_party/WebKit/Source/core/offscreencanvas/BUILD.gn
index 6ac074b..e781026 100644
--- a/third_party/WebKit/Source/core/offscreencanvas/BUILD.gn
+++ b/third_party/WebKit/Source/core/offscreencanvas/BUILD.gn
@@ -11,6 +11,5 @@
   ]
   deps = [
     "//mojo/public/cpp/bindings:bindings",
-    "//third_party/WebKit/public:offscreen_canvas_mojo_bindings_blink",
   ]
 }
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp
index 134b715..92e368d 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp
@@ -2,93 +2,73 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "core/paint/PaintPropertyTreeBuilderTest.h"
+
 #include "core/html/HTMLIFrameElement.h"
-#include "core/layout/LayoutTestHelper.h"
 #include "core/layout/LayoutTreeAsText.h"
-#include "core/layout/api/LayoutViewItem.h"
 #include "core/paint/ObjectPaintProperties.h"
 #include "core/paint/PaintPropertyTreePrinter.h"
 #include "platform/graphics/paint/GeometryMapper.h"
-#include "platform/graphics/paint/ScrollPaintPropertyNode.h"
-#include "platform/graphics/paint/TransformPaintPropertyNode.h"
-#include "platform/testing/RuntimeEnabledFeaturesTestHelpers.h"
-#include "platform/testing/UnitTestHelpers.h"
-#include "platform/text/TextStream.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "wtf/HashMap.h"
-#include "wtf/Vector.h"
 
 namespace blink {
 
-typedef bool TestParamRootLayerScrolling;
-class PaintPropertyTreeBuilderTest
-    : public ::testing::WithParamInterface<TestParamRootLayerScrolling>,
-      private ScopedSlimmingPaintV2ForTest,
-      private ScopedRootLayerScrollingForTest,
-      public RenderingTest {
- public:
-  PaintPropertyTreeBuilderTest()
-      : ScopedSlimmingPaintV2ForTest(true),
-        ScopedRootLayerScrollingForTest(GetParam()),
-        RenderingTest(SingleChildFrameLoaderClient::create()) {}
+void PaintPropertyTreeBuilderTest::loadTestData(const char* fileName) {
+  String fullPath = testing::blinkRootDir();
+  fullPath.append("/Source/core/paint/test_data/");
+  fullPath.append(fileName);
+  RefPtr<SharedBuffer> inputBuffer = testing::readFromFile(fullPath);
+  setBodyInnerHTML(String(inputBuffer->data(), inputBuffer->size()));
+}
 
-  void loadTestData(const char* fileName) {
-    String fullPath = testing::blinkRootDir();
-    fullPath.append("/Source/core/paint/test_data/");
-    fullPath.append(fileName);
-    RefPtr<SharedBuffer> inputBuffer = testing::readFromFile(fullPath);
-    setBodyInnerHTML(String(inputBuffer->data(), inputBuffer->size()));
-  }
+const TransformPaintPropertyNode*
+PaintPropertyTreeBuilderTest::framePreTranslation() {
+  FrameView* frameView = document().view();
+  if (RuntimeEnabledFeatures::rootLayerScrollingEnabled())
+    return frameView->layoutView()->paintProperties()->paintOffsetTranslation();
+  return frameView->preTranslation();
+}
 
-  const TransformPaintPropertyNode* framePreTranslation() {
-    FrameView* frameView = document().view();
-    if (RuntimeEnabledFeatures::rootLayerScrollingEnabled())
-      return frameView->layoutView()
-          ->paintProperties()
-          ->paintOffsetTranslation();
-    return frameView->preTranslation();
-  }
+const TransformPaintPropertyNode*
+PaintPropertyTreeBuilderTest::frameScrollTranslation() {
+  FrameView* frameView = document().view();
+  if (RuntimeEnabledFeatures::rootLayerScrollingEnabled())
+    return frameView->layoutView()->paintProperties()->scrollTranslation();
+  return frameView->scrollTranslation();
+}
 
-  const TransformPaintPropertyNode* frameScrollTranslation() {
-    FrameView* frameView = document().view();
-    if (RuntimeEnabledFeatures::rootLayerScrollingEnabled())
-      return frameView->layoutView()->paintProperties()->scrollTranslation();
-    return frameView->scrollTranslation();
-  }
+const ClipPaintPropertyNode* PaintPropertyTreeBuilderTest::frameContentClip() {
+  FrameView* frameView = document().view();
+  if (RuntimeEnabledFeatures::rootLayerScrollingEnabled())
+    return frameView->layoutView()->paintProperties()->overflowClip();
+  return frameView->contentClip();
+}
 
-  const ClipPaintPropertyNode* frameContentClip() {
-    FrameView* frameView = document().view();
-    if (RuntimeEnabledFeatures::rootLayerScrollingEnabled())
-      return frameView->layoutView()->paintProperties()->overflowClip();
-    return frameView->contentClip();
-  }
+const ScrollPaintPropertyNode* PaintPropertyTreeBuilderTest::frameScroll(
+    FrameView* frameView) {
+  if (!frameView)
+    frameView = document().view();
+  if (RuntimeEnabledFeatures::rootLayerScrollingEnabled())
+    return frameView->layoutView()->paintProperties()->scroll();
+  return frameView->scroll();
+}
 
-  const ScrollPaintPropertyNode* frameScroll(FrameView* frameView = nullptr) {
-    if (!frameView)
-      frameView = document().view();
-    if (RuntimeEnabledFeatures::rootLayerScrollingEnabled())
-      return frameView->layoutView()->paintProperties()->scroll();
-    return frameView->scroll();
-  }
+LayoutPoint PaintPropertyTreeBuilderTest::paintOffset(
+    const LayoutObject* object) {
+  return object->paintProperties()->localBorderBoxProperties()->paintOffset;
+}
 
-  LayoutPoint paintOffset(const LayoutObject* object) {
-    return object->paintProperties()->localBorderBoxProperties()->paintOffset;
-  }
+void PaintPropertyTreeBuilderTest::SetUp() {
+  Settings::setMockScrollbarsEnabled(true);
 
- private:
-  void SetUp() override {
-    Settings::setMockScrollbarsEnabled(true);
+  RenderingTest::SetUp();
+  enableCompositing();
+}
 
-    RenderingTest::SetUp();
-    enableCompositing();
-  }
+void PaintPropertyTreeBuilderTest::TearDown() {
+  RenderingTest::TearDown();
 
-  void TearDown() override {
-    RenderingTest::TearDown();
-
-    Settings::setMockScrollbarsEnabled(false);
-  }
-};
+  Settings::setMockScrollbarsEnabled(false);
+}
 
 #define CHECK_VISUAL_RECT(expected, sourceLayoutObject, ancestorLayoutObject,  \
                           slopFactor)                                          \
@@ -2714,115 +2694,6 @@
       getLayoutObjectByElementId("svg")->paintProperties()->overflowClip());
 }
 
-TEST_P(PaintPropertyTreeBuilderTest,
-       ThreadedScrollingDisabledMainThreadScrollReason) {
-  setBodyInnerHTML(
-      "<style>"
-      "  #overflowA {"
-      "    position: absolute;"
-      "    overflow: scroll;"
-      "    width: 20px;"
-      "    height: 20px;"
-      "  }"
-      "  .forceScroll {"
-      "    height: 4000px;"
-      "  }"
-      "</style>"
-      "<div id='overflowA'>"
-      "  <div class='forceScroll'></div>"
-      "</div>"
-      "<div class='forceScroll'></div>");
-  Element* overflowA = document().getElementById("overflowA");
-  EXPECT_FALSE(frameScroll()->threadedScrollingDisabled());
-  EXPECT_FALSE(overflowA->layoutObject()
-                   ->paintProperties()
-                   ->scroll()
-                   ->threadedScrollingDisabled());
-
-  document().settings()->setThreadedScrollingEnabled(false);
-  // TODO(pdr): The main thread scrolling setting should invalidate properties.
-  document().view()->setNeedsPaintPropertyUpdate();
-  overflowA->layoutObject()->setNeedsPaintPropertyUpdate();
-  document().view()->updateAllLifecyclePhases();
-
-  EXPECT_TRUE(frameScroll()->threadedScrollingDisabled());
-  EXPECT_TRUE(overflowA->layoutObject()
-                  ->paintProperties()
-                  ->scroll()
-                  ->threadedScrollingDisabled());
-}
-
-TEST_P(PaintPropertyTreeBuilderTest,
-       BackgroundAttachmentFixedMainThreadScrollReasonsWithNestedScrollers) {
-  setBodyInnerHTML(
-      "<style>"
-      "  #overflowA {"
-      "    position: absolute;"
-      "    overflow: scroll;"
-      "    width: 20px;"
-      "    height: 20px;"
-      "  }"
-      "  #overflowB {"
-      "    position: absolute;"
-      "    overflow: scroll;"
-      "    width: 5px;"
-      "    height: 3px;"
-      "  }"
-      "  .backgroundAttachmentFixed {"
-      "    background-image: url('foo');"
-      "    background-attachment: fixed;"
-      "  }"
-      "  .forceScroll {"
-      "    height: 4000px;"
-      "  }"
-      "</style>"
-      "<div id='overflowA'>"
-      "  <div id='overflowB' class='backgroundAttachmentFixed'>"
-      "    <div class='forceScroll'></div>"
-      "  </div>"
-      "  <div class='forceScroll'></div>"
-      "</div>"
-      "<div class='forceScroll'></div>");
-  Element* overflowA = document().getElementById("overflowA");
-  Element* overflowB = document().getElementById("overflowB");
-
-  EXPECT_TRUE(frameScroll()->hasBackgroundAttachmentFixedDescendants());
-  EXPECT_TRUE(overflowA->layoutObject()
-                  ->paintProperties()
-                  ->scroll()
-                  ->hasBackgroundAttachmentFixedDescendants());
-  EXPECT_FALSE(overflowB->layoutObject()
-                   ->paintProperties()
-                   ->scroll()
-                   ->hasBackgroundAttachmentFixedDescendants());
-
-  // Removing a main thread scrolling reason should update the entire tree.
-  overflowB->removeAttribute("class");
-  document().view()->updateAllLifecyclePhases();
-  EXPECT_FALSE(frameScroll()->hasBackgroundAttachmentFixedDescendants());
-  EXPECT_FALSE(overflowA->layoutObject()
-                   ->paintProperties()
-                   ->scroll()
-                   ->hasBackgroundAttachmentFixedDescendants());
-  EXPECT_FALSE(overflowB->layoutObject()
-                   ->paintProperties()
-                   ->scroll()
-                   ->hasBackgroundAttachmentFixedDescendants());
-
-  // Adding a main thread scrolling reason should update the entire tree.
-  overflowB->setAttribute(HTMLNames::classAttr, "backgroundAttachmentFixed");
-  document().view()->updateAllLifecyclePhases();
-  EXPECT_TRUE(frameScroll()->hasBackgroundAttachmentFixedDescendants());
-  EXPECT_TRUE(overflowA->layoutObject()
-                  ->paintProperties()
-                  ->scroll()
-                  ->hasBackgroundAttachmentFixedDescendants());
-  EXPECT_FALSE(overflowB->layoutObject()
-                   ->paintProperties()
-                   ->scroll()
-                   ->hasBackgroundAttachmentFixedDescendants());
-}
-
 TEST_P(PaintPropertyTreeBuilderTest, MainThreadScrollReasonsWithoutScrolling) {
   setBodyInnerHTML(
       "<style>"
@@ -2853,74 +2724,6 @@
                   ->hasBackgroundAttachmentFixedDescendants());
 }
 
-TEST_P(PaintPropertyTreeBuilderTest,
-       BackgroundAttachmentFixedMainThreadScrollReasonsWithFixedScroller) {
-  setBodyInnerHTML(
-      "<style>"
-      "  #overflowA {"
-      "    position: absolute;"
-      "    overflow: scroll;"
-      "    width: 20px;"
-      "    height: 20px;"
-      "  }"
-      "  #overflowB {"
-      "    position: fixed;"
-      "    overflow: scroll;"
-      "    width: 5px;"
-      "    height: 3px;"
-      "  }"
-      "  .backgroundAttachmentFixed {"
-      "    background-image: url('foo');"
-      "    background-attachment: fixed;"
-      "  }"
-      "  .forceScroll {"
-      "    height: 4000px;"
-      "  }"
-      "</style>"
-      "<div id='overflowA'>"
-      "  <div id='overflowB' class='backgroundAttachmentFixed'>"
-      "    <div class='forceScroll'></div>"
-      "  </div>"
-      "  <div class='forceScroll'></div>"
-      "</div>"
-      "<div class='forceScroll'></div>");
-  Element* overflowA = document().getElementById("overflowA");
-  Element* overflowB = document().getElementById("overflowB");
-
-  // This should be false. We are not as strict about main thread scrolling
-  // reasons as we could be.
-  EXPECT_TRUE(overflowA->layoutObject()
-                  ->paintProperties()
-                  ->scroll()
-                  ->hasBackgroundAttachmentFixedDescendants());
-  EXPECT_FALSE(overflowB->layoutObject()
-                   ->paintProperties()
-                   ->scroll()
-                   ->hasBackgroundAttachmentFixedDescendants());
-  EXPECT_TRUE(overflowB->layoutObject()
-                  ->paintProperties()
-                  ->scroll()
-                  ->parent()
-                  ->isRoot());
-
-  // Removing a main thread scrolling reason should update the entire tree.
-  overflowB->removeAttribute("class");
-  document().view()->updateAllLifecyclePhases();
-  EXPECT_FALSE(overflowA->layoutObject()
-                   ->paintProperties()
-                   ->scroll()
-                   ->hasBackgroundAttachmentFixedDescendants());
-  EXPECT_FALSE(overflowB->layoutObject()
-                   ->paintProperties()
-                   ->scroll()
-                   ->hasBackgroundAttachmentFixedDescendants());
-  EXPECT_FALSE(overflowB->layoutObject()
-                   ->paintProperties()
-                   ->scroll()
-                   ->parent()
-                   ->hasBackgroundAttachmentFixedDescendants());
-}
-
 TEST_P(PaintPropertyTreeBuilderTest, PaintOffsetsUnderMultiColumn) {
   setBodyInnerHTML(
       "<style>"
@@ -3047,257 +2850,4 @@
   EXPECT_EQ(filterProperties->effect(), childPaintState.effect());
 }
 
-TEST_P(PaintPropertyTreeBuilderTest, DescendantNeedsUpdateAcrossFrames) {
-  setBodyInnerHTML(
-      "<style>body { margin: 0; }</style>"
-      "<div id='divWithTransform' style='transform: translate3d(1px,2px,3px);'>"
-      "  <iframe style='border: 7px solid black'></iframe>"
-      "</div>");
-  setChildFrameHTML(
-      "<style>body { margin: 0; }</style><div id='transform' style='transform: "
-      "translate3d(4px, 5px, 6px); width: 100px; height: 200px'></div>");
-
-  FrameView* frameView = document().view();
-  frameView->updateAllLifecyclePhases();
-
-  LayoutObject* divWithTransform =
-      document().getElementById("divWithTransform")->layoutObject();
-  LayoutObject* childLayoutView = childDocument().layoutView();
-  LayoutObject* innerDivWithTransform =
-      childDocument().getElementById("transform")->layoutObject();
-
-  // Initially, no objects should need a descendant update.
-  EXPECT_FALSE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
-  EXPECT_FALSE(divWithTransform->descendantNeedsPaintPropertyUpdate());
-  EXPECT_FALSE(childLayoutView->descendantNeedsPaintPropertyUpdate());
-  EXPECT_FALSE(innerDivWithTransform->descendantNeedsPaintPropertyUpdate());
-
-  // Marking the child div as needing a paint property update should propagate
-  // up the tree and across frames.
-  innerDivWithTransform->setNeedsPaintPropertyUpdate();
-  EXPECT_TRUE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
-  EXPECT_TRUE(divWithTransform->descendantNeedsPaintPropertyUpdate());
-  EXPECT_TRUE(childLayoutView->descendantNeedsPaintPropertyUpdate());
-  EXPECT_TRUE(innerDivWithTransform->needsPaintPropertyUpdate());
-  EXPECT_FALSE(innerDivWithTransform->descendantNeedsPaintPropertyUpdate());
-
-  // After a lifecycle update, no nodes should need a descendant update.
-  frameView->updateAllLifecyclePhases();
-  EXPECT_FALSE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
-  EXPECT_FALSE(divWithTransform->descendantNeedsPaintPropertyUpdate());
-  EXPECT_FALSE(childLayoutView->descendantNeedsPaintPropertyUpdate());
-  EXPECT_FALSE(innerDivWithTransform->descendantNeedsPaintPropertyUpdate());
-
-  // A child frame marked as needing a paint property update should not be
-  // skipped if the owning layout tree does not need an update.
-  FrameView* childFrameView = childDocument().view();
-  childFrameView->setNeedsPaintPropertyUpdate();
-  EXPECT_TRUE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
-  frameView->updateAllLifecyclePhases();
-  EXPECT_FALSE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
-  EXPECT_FALSE(frameView->needsPaintPropertyUpdate());
-  EXPECT_FALSE(childFrameView->needsPaintPropertyUpdate());
-}
-
-TEST_P(PaintPropertyTreeBuilderTest, UpdatingFrameViewContentClip) {
-  setBodyInnerHTML("hello world.");
-  EXPECT_EQ(FloatRoundedRect(0, 0, 800, 600), frameContentClip()->clipRect());
-  document().view()->resize(800, 599);
-  document().view()->updateAllLifecyclePhases();
-  EXPECT_EQ(FloatRoundedRect(0, 0, 800, 599), frameContentClip()->clipRect());
-  document().view()->resize(800, 600);
-  document().view()->updateAllLifecyclePhases();
-  EXPECT_EQ(FloatRoundedRect(0, 0, 800, 600), frameContentClip()->clipRect());
-  document().view()->resize(5, 5);
-  document().view()->updateAllLifecyclePhases();
-  EXPECT_EQ(FloatRoundedRect(0, 0, 5, 5), frameContentClip()->clipRect());
-}
-
-TEST_P(PaintPropertyTreeBuilderTest, BuildingStopsAtThrottledFrames) {
-  setBodyInnerHTML(
-      "<style>body { margin: 0; }</style>"
-      "<div id='transform' style='transform: translate3d(4px, 5px, 6px);'>"
-      "</div>"
-      "<iframe id='iframe' sandbox></iframe>");
-  setChildFrameHTML(
-      "<style>body { margin: 0; }</style>"
-      "<div id='iframeTransform'"
-      "  style='transform: translate3d(4px, 5px, 6px);'/>");
-
-  // Move the child frame offscreen so it becomes available for throttling.
-  auto* iframe = toHTMLIFrameElement(document().getElementById("iframe"));
-  iframe->setAttribute(HTMLNames::styleAttr, "transform: translateY(5555px)");
-  document().view()->updateAllLifecyclePhases();
-  // Ensure intersection observer notifications get delivered.
-  testing::runPendingTasks();
-  EXPECT_FALSE(document().view()->isHiddenForThrottling());
-  EXPECT_TRUE(childDocument().view()->isHiddenForThrottling());
-
-  auto* transform = document().getElementById("transform")->layoutObject();
-  auto* iframeLayoutView = childDocument().layoutView();
-  auto* iframeTransform =
-      childDocument().getElementById("iframeTransform")->layoutObject();
-
-  // Invalidate properties in the iframe and ensure ancestors are marked.
-  iframeTransform->setNeedsPaintPropertyUpdate();
-  EXPECT_FALSE(document().layoutView()->needsPaintPropertyUpdate());
-  EXPECT_TRUE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
-  EXPECT_FALSE(transform->needsPaintPropertyUpdate());
-  EXPECT_FALSE(transform->descendantNeedsPaintPropertyUpdate());
-  EXPECT_FALSE(iframeLayoutView->needsPaintPropertyUpdate());
-  EXPECT_TRUE(iframeLayoutView->descendantNeedsPaintPropertyUpdate());
-  EXPECT_TRUE(iframeTransform->needsPaintPropertyUpdate());
-  EXPECT_FALSE(iframeTransform->descendantNeedsPaintPropertyUpdate());
-
-  transform->setNeedsPaintPropertyUpdate();
-  EXPECT_TRUE(transform->needsPaintPropertyUpdate());
-  EXPECT_FALSE(transform->descendantNeedsPaintPropertyUpdate());
-
-  {
-    DocumentLifecycle::AllowThrottlingScope throttlingScope(
-        document().lifecycle());
-    EXPECT_FALSE(document().view()->shouldThrottleRendering());
-    EXPECT_TRUE(childDocument().view()->shouldThrottleRendering());
-
-    // A lifecycle update should update all properties except those with
-    // actively throttled descendants.
-    document().view()->updateAllLifecyclePhases();
-    EXPECT_FALSE(document().layoutView()->needsPaintPropertyUpdate());
-    EXPECT_TRUE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
-    EXPECT_FALSE(transform->needsPaintPropertyUpdate());
-    EXPECT_FALSE(transform->descendantNeedsPaintPropertyUpdate());
-    EXPECT_FALSE(iframeLayoutView->needsPaintPropertyUpdate());
-    EXPECT_TRUE(iframeLayoutView->descendantNeedsPaintPropertyUpdate());
-    EXPECT_TRUE(iframeTransform->needsPaintPropertyUpdate());
-    EXPECT_FALSE(iframeTransform->descendantNeedsPaintPropertyUpdate());
-  }
-
-  EXPECT_FALSE(document().view()->shouldThrottleRendering());
-  EXPECT_FALSE(childDocument().view()->shouldThrottleRendering());
-  // Once unthrottled, a lifecycel update should update all properties.
-  document().view()->updateAllLifecyclePhases();
-  EXPECT_FALSE(document().layoutView()->needsPaintPropertyUpdate());
-  EXPECT_FALSE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
-  EXPECT_FALSE(transform->needsPaintPropertyUpdate());
-  EXPECT_FALSE(transform->descendantNeedsPaintPropertyUpdate());
-  EXPECT_FALSE(iframeLayoutView->needsPaintPropertyUpdate());
-  EXPECT_FALSE(iframeLayoutView->descendantNeedsPaintPropertyUpdate());
-  EXPECT_FALSE(iframeTransform->needsPaintPropertyUpdate());
-  EXPECT_FALSE(iframeTransform->descendantNeedsPaintPropertyUpdate());
-}
-
-TEST_P(PaintPropertyTreeBuilderTest, ClipChangesUpdateOverflowClip) {
-  setBodyInnerHTML(
-      "<style>"
-      "  body { margin:0 }"
-      "  #div { overflow:hidden; height:0px; }"
-      "</style>"
-      "<div id='div'></div>");
-  auto* div = document().getElementById("div");
-  div->setAttribute(HTMLNames::styleAttr, "display:inline-block; width:7px;");
-  document().view()->updateAllLifecyclePhases();
-  auto* clipProperties = div->layoutObject()->paintProperties()->overflowClip();
-  EXPECT_EQ(FloatRect(0, 0, 7, 0), clipProperties->clipRect().rect());
-
-  // Width changes should update the overflow clip.
-  div->setAttribute(HTMLNames::styleAttr, "display:inline-block; width:7px;");
-  document().view()->updateAllLifecyclePhases();
-  clipProperties = div->layoutObject()->paintProperties()->overflowClip();
-  EXPECT_EQ(FloatRect(0, 0, 7, 0), clipProperties->clipRect().rect());
-  div->setAttribute(HTMLNames::styleAttr, "display:inline-block; width:9px;");
-  document().view()->updateAllLifecyclePhases();
-  EXPECT_EQ(FloatRect(0, 0, 9, 0), clipProperties->clipRect().rect());
-
-  // An inline block's overflow clip should be updated when padding changes,
-  // even if the border box remains unchanged.
-  div->setAttribute(HTMLNames::styleAttr,
-                    "display:inline-block; width:7px; padding-right:3px;");
-  document().view()->updateAllLifecyclePhases();
-  clipProperties = div->layoutObject()->paintProperties()->overflowClip();
-  EXPECT_EQ(FloatRect(0, 0, 10, 0), clipProperties->clipRect().rect());
-  div->setAttribute(HTMLNames::styleAttr,
-                    "display:inline-block; width:8px; padding-right:2px;");
-  document().view()->updateAllLifecyclePhases();
-  EXPECT_EQ(FloatRect(0, 0, 10, 0), clipProperties->clipRect().rect());
-  div->setAttribute(HTMLNames::styleAttr,
-                    "display:inline-block; width:8px;"
-                    "padding-right:1px; padding-left:1px;");
-  document().view()->updateAllLifecyclePhases();
-  EXPECT_EQ(FloatRect(0, 0, 10, 0), clipProperties->clipRect().rect());
-
-  // An block's overflow clip should be updated when borders change.
-  div->setAttribute(HTMLNames::styleAttr, "border-right:3px solid red;");
-  document().view()->updateAllLifecyclePhases();
-  clipProperties = div->layoutObject()->paintProperties()->overflowClip();
-  EXPECT_EQ(FloatRect(0, 0, 797, 0), clipProperties->clipRect().rect());
-  div->setAttribute(HTMLNames::styleAttr, "border-right:5px solid red;");
-  document().view()->updateAllLifecyclePhases();
-  EXPECT_EQ(FloatRect(0, 0, 795, 0), clipProperties->clipRect().rect());
-
-  // Removing overflow clip should remove the property.
-  div->setAttribute(HTMLNames::styleAttr, "overflow:hidden;");
-  document().view()->updateAllLifecyclePhases();
-  clipProperties = div->layoutObject()->paintProperties()->overflowClip();
-  EXPECT_EQ(FloatRect(0, 0, 800, 0), clipProperties->clipRect().rect());
-  div->setAttribute(HTMLNames::styleAttr, "overflow:visible;");
-  document().view()->updateAllLifecyclePhases();
-  EXPECT_TRUE(!div->layoutObject()->paintProperties() ||
-              !div->layoutObject()->paintProperties()->overflowClip());
-}
-
-TEST_P(PaintPropertyTreeBuilderTest, ContainPaintChangesUpdateOverflowClip) {
-  setBodyInnerHTML(
-      "<style>"
-      "  body { margin:0 }"
-      "  #div { will-change:transform; width:7px; height:6px; }"
-      "</style>"
-      "<div id='div' style='contain:paint;'></div>");
-  document().view()->updateAllLifecyclePhases();
-  auto* div = document().getElementById("div");
-  auto* properties = div->layoutObject()->paintProperties()->overflowClip();
-  EXPECT_EQ(FloatRect(0, 0, 7, 6), properties->clipRect().rect());
-
-  div->setAttribute(HTMLNames::styleAttr, "");
-  document().view()->updateAllLifecyclePhases();
-  EXPECT_TRUE(!div->layoutObject()->paintProperties() ||
-              !div->layoutObject()->paintProperties()->overflowClip());
-}
-
-// A basic sanity check for over-invalidation of paint properties.
-TEST_P(PaintPropertyTreeBuilderTest, NoPaintPropertyUpdateOnBackgroundChange) {
-  setBodyInnerHTML("<div id='div' style='background-color: blue'>DIV</div>");
-  auto* div = document().getElementById("div");
-
-  document().view()->updateAllLifecyclePhases();
-  div->setAttribute(HTMLNames::styleAttr, "background-color: green");
-  document().view()->updateLifecycleToLayoutClean();
-  EXPECT_FALSE(div->layoutObject()->needsPaintPropertyUpdate());
-}
-
-// Disabled due to stale scrollsOverflow values, see: https://crbug.com/675296.
-TEST_P(PaintPropertyTreeBuilderTest,
-       DISABLED_FrameVisibilityChangeUpdatesProperties) {
-  setBodyInnerHTML(
-      "<style>body { margin: 0; }</style>"
-      "<div id='iframeContainer'>"
-      "  <iframe id='iframe' style='width: 100px; height: 100px;'></iframe>"
-      "</div>");
-  setChildFrameHTML(
-      "<style>body { margin: 0; }</style>"
-      "<div id='forceScroll' style='height: 3000px;'></div>");
-
-  FrameView* frameView = document().view();
-  frameView->updateAllLifecyclePhases();
-  EXPECT_EQ(nullptr, frameScroll(frameView));
-  FrameView* childFrameView = childDocument().view();
-  EXPECT_NE(nullptr, frameScroll(childFrameView));
-
-  auto* iframeContainer = document().getElementById("iframeContainer");
-  iframeContainer->setAttribute(HTMLNames::styleAttr, "visibility: hidden;");
-  frameView->updateAllLifecyclePhases();
-
-  EXPECT_EQ(nullptr, frameScroll(frameView));
-  EXPECT_EQ(nullptr, frameScroll(childFrameView));
-}
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.h b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.h
new file mode 100644
index 0000000..1f936e7
--- /dev/null
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.h
@@ -0,0 +1,48 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/layout/LayoutTestHelper.h"
+#include "platform/testing/RuntimeEnabledFeaturesTestHelpers.h"
+#include "platform/testing/UnitTestHelpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+
+class TransformPaintPropertyNode;
+class ClipPaintPropertyNode;
+class ScrollPaintPropertyNode;
+class LayoutPoint;
+
+typedef bool TestParamRootLayerScrolling;
+class PaintPropertyTreeBuilderTest
+    : public ::testing::WithParamInterface<TestParamRootLayerScrolling>,
+      private ScopedSlimmingPaintV2ForTest,
+      private ScopedRootLayerScrollingForTest,
+      public RenderingTest {
+ public:
+  PaintPropertyTreeBuilderTest()
+      : ScopedSlimmingPaintV2ForTest(true),
+        ScopedRootLayerScrollingForTest(GetParam()),
+        RenderingTest(SingleChildFrameLoaderClient::create()) {}
+
+ protected:
+  void loadTestData(const char* fileName);
+
+  // The following helpers return paint property nodes associated with the main
+  // FrameView, accounting for differences from the RootLayerScrolls setting.
+  const TransformPaintPropertyNode* framePreTranslation();
+  const TransformPaintPropertyNode* frameScrollTranslation();
+  const ClipPaintPropertyNode* frameContentClip();
+  const ScrollPaintPropertyNode* frameScroll(FrameView* = nullptr);
+
+  // Return the local border box's paint offset. For more details, see
+  // ObjectPaintProperties::localBorderBoxProperties().
+  LayoutPoint paintOffset(const LayoutObject*);
+
+ private:
+  void SetUp() override;
+  void TearDown() override;
+};
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeUpdateTests.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeUpdateTests.cpp
new file mode 100644
index 0000000..e983490c
--- /dev/null
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeUpdateTests.cpp
@@ -0,0 +1,444 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/html/HTMLIFrameElement.h"
+#include "core/paint/PaintPropertyTreeBuilderTest.h"
+#include "core/paint/PaintPropertyTreePrinter.h"
+
+namespace blink {
+
+// Tests covering incremental updates of paint property trees.
+class PaintPropertyTreeUpdateTest : public PaintPropertyTreeBuilderTest {};
+
+TEST_P(PaintPropertyTreeUpdateTest,
+       ThreadedScrollingDisabledMainThreadScrollReason) {
+  setBodyInnerHTML(
+      "<style>"
+      "  #overflowA {"
+      "    position: absolute;"
+      "    overflow: scroll;"
+      "    width: 20px;"
+      "    height: 20px;"
+      "  }"
+      "  .forceScroll {"
+      "    height: 4000px;"
+      "  }"
+      "</style>"
+      "<div id='overflowA'>"
+      "  <div class='forceScroll'></div>"
+      "</div>"
+      "<div class='forceScroll'></div>");
+  Element* overflowA = document().getElementById("overflowA");
+  EXPECT_FALSE(frameScroll()->threadedScrollingDisabled());
+  EXPECT_FALSE(overflowA->layoutObject()
+                   ->paintProperties()
+                   ->scroll()
+                   ->threadedScrollingDisabled());
+
+  document().settings()->setThreadedScrollingEnabled(false);
+  // TODO(pdr): The main thread scrolling setting should invalidate properties.
+  document().view()->setNeedsPaintPropertyUpdate();
+  overflowA->layoutObject()->setNeedsPaintPropertyUpdate();
+  document().view()->updateAllLifecyclePhases();
+
+  EXPECT_TRUE(frameScroll()->threadedScrollingDisabled());
+  EXPECT_TRUE(overflowA->layoutObject()
+                  ->paintProperties()
+                  ->scroll()
+                  ->threadedScrollingDisabled());
+}
+
+TEST_P(PaintPropertyTreeUpdateTest,
+       BackgroundAttachmentFixedMainThreadScrollReasonsWithNestedScrollers) {
+  setBodyInnerHTML(
+      "<style>"
+      "  #overflowA {"
+      "    position: absolute;"
+      "    overflow: scroll;"
+      "    width: 20px;"
+      "    height: 20px;"
+      "  }"
+      "  #overflowB {"
+      "    position: absolute;"
+      "    overflow: scroll;"
+      "    width: 5px;"
+      "    height: 3px;"
+      "  }"
+      "  .backgroundAttachmentFixed {"
+      "    background-image: url('foo');"
+      "    background-attachment: fixed;"
+      "  }"
+      "  .forceScroll {"
+      "    height: 4000px;"
+      "  }"
+      "</style>"
+      "<div id='overflowA'>"
+      "  <div id='overflowB' class='backgroundAttachmentFixed'>"
+      "    <div class='forceScroll'></div>"
+      "  </div>"
+      "  <div class='forceScroll'></div>"
+      "</div>"
+      "<div class='forceScroll'></div>");
+  Element* overflowA = document().getElementById("overflowA");
+  Element* overflowB = document().getElementById("overflowB");
+
+  EXPECT_TRUE(frameScroll()->hasBackgroundAttachmentFixedDescendants());
+  EXPECT_TRUE(overflowA->layoutObject()
+                  ->paintProperties()
+                  ->scroll()
+                  ->hasBackgroundAttachmentFixedDescendants());
+  EXPECT_FALSE(overflowB->layoutObject()
+                   ->paintProperties()
+                   ->scroll()
+                   ->hasBackgroundAttachmentFixedDescendants());
+
+  // Removing a main thread scrolling reason should update the entire tree.
+  overflowB->removeAttribute("class");
+  document().view()->updateAllLifecyclePhases();
+  EXPECT_FALSE(frameScroll()->hasBackgroundAttachmentFixedDescendants());
+  EXPECT_FALSE(overflowA->layoutObject()
+                   ->paintProperties()
+                   ->scroll()
+                   ->hasBackgroundAttachmentFixedDescendants());
+  EXPECT_FALSE(overflowB->layoutObject()
+                   ->paintProperties()
+                   ->scroll()
+                   ->hasBackgroundAttachmentFixedDescendants());
+
+  // Adding a main thread scrolling reason should update the entire tree.
+  overflowB->setAttribute(HTMLNames::classAttr, "backgroundAttachmentFixed");
+  document().view()->updateAllLifecyclePhases();
+  EXPECT_TRUE(frameScroll()->hasBackgroundAttachmentFixedDescendants());
+  EXPECT_TRUE(overflowA->layoutObject()
+                  ->paintProperties()
+                  ->scroll()
+                  ->hasBackgroundAttachmentFixedDescendants());
+  EXPECT_FALSE(overflowB->layoutObject()
+                   ->paintProperties()
+                   ->scroll()
+                   ->hasBackgroundAttachmentFixedDescendants());
+}
+
+TEST_P(PaintPropertyTreeUpdateTest,
+       BackgroundAttachmentFixedMainThreadScrollReasonsWithFixedScroller) {
+  setBodyInnerHTML(
+      "<style>"
+      "  #overflowA {"
+      "    position: absolute;"
+      "    overflow: scroll;"
+      "    width: 20px;"
+      "    height: 20px;"
+      "  }"
+      "  #overflowB {"
+      "    position: fixed;"
+      "    overflow: scroll;"
+      "    width: 5px;"
+      "    height: 3px;"
+      "  }"
+      "  .backgroundAttachmentFixed {"
+      "    background-image: url('foo');"
+      "    background-attachment: fixed;"
+      "  }"
+      "  .forceScroll {"
+      "    height: 4000px;"
+      "  }"
+      "</style>"
+      "<div id='overflowA'>"
+      "  <div id='overflowB' class='backgroundAttachmentFixed'>"
+      "    <div class='forceScroll'></div>"
+      "  </div>"
+      "  <div class='forceScroll'></div>"
+      "</div>"
+      "<div class='forceScroll'></div>");
+  Element* overflowA = document().getElementById("overflowA");
+  Element* overflowB = document().getElementById("overflowB");
+
+  // This should be false. We are not as strict about main thread scrolling
+  // reasons as we could be.
+  EXPECT_TRUE(overflowA->layoutObject()
+                  ->paintProperties()
+                  ->scroll()
+                  ->hasBackgroundAttachmentFixedDescendants());
+  EXPECT_FALSE(overflowB->layoutObject()
+                   ->paintProperties()
+                   ->scroll()
+                   ->hasBackgroundAttachmentFixedDescendants());
+  EXPECT_TRUE(overflowB->layoutObject()
+                  ->paintProperties()
+                  ->scroll()
+                  ->parent()
+                  ->isRoot());
+
+  // Removing a main thread scrolling reason should update the entire tree.
+  overflowB->removeAttribute("class");
+  document().view()->updateAllLifecyclePhases();
+  EXPECT_FALSE(overflowA->layoutObject()
+                   ->paintProperties()
+                   ->scroll()
+                   ->hasBackgroundAttachmentFixedDescendants());
+  EXPECT_FALSE(overflowB->layoutObject()
+                   ->paintProperties()
+                   ->scroll()
+                   ->hasBackgroundAttachmentFixedDescendants());
+  EXPECT_FALSE(overflowB->layoutObject()
+                   ->paintProperties()
+                   ->scroll()
+                   ->parent()
+                   ->hasBackgroundAttachmentFixedDescendants());
+}
+
+TEST_P(PaintPropertyTreeUpdateTest, DescendantNeedsUpdateAcrossFrames) {
+  setBodyInnerHTML(
+      "<style>body { margin: 0; }</style>"
+      "<div id='divWithTransform' style='transform: translate3d(1px,2px,3px);'>"
+      "  <iframe style='border: 7px solid black'></iframe>"
+      "</div>");
+  setChildFrameHTML(
+      "<style>body { margin: 0; }</style><div id='transform' style='transform: "
+      "translate3d(4px, 5px, 6px); width: 100px; height: 200px'></div>");
+
+  FrameView* frameView = document().view();
+  frameView->updateAllLifecyclePhases();
+
+  LayoutObject* divWithTransform =
+      document().getElementById("divWithTransform")->layoutObject();
+  LayoutObject* childLayoutView = childDocument().layoutView();
+  LayoutObject* innerDivWithTransform =
+      childDocument().getElementById("transform")->layoutObject();
+
+  // Initially, no objects should need a descendant update.
+  EXPECT_FALSE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
+  EXPECT_FALSE(divWithTransform->descendantNeedsPaintPropertyUpdate());
+  EXPECT_FALSE(childLayoutView->descendantNeedsPaintPropertyUpdate());
+  EXPECT_FALSE(innerDivWithTransform->descendantNeedsPaintPropertyUpdate());
+
+  // Marking the child div as needing a paint property update should propagate
+  // up the tree and across frames.
+  innerDivWithTransform->setNeedsPaintPropertyUpdate();
+  EXPECT_TRUE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
+  EXPECT_TRUE(divWithTransform->descendantNeedsPaintPropertyUpdate());
+  EXPECT_TRUE(childLayoutView->descendantNeedsPaintPropertyUpdate());
+  EXPECT_TRUE(innerDivWithTransform->needsPaintPropertyUpdate());
+  EXPECT_FALSE(innerDivWithTransform->descendantNeedsPaintPropertyUpdate());
+
+  // After a lifecycle update, no nodes should need a descendant update.
+  frameView->updateAllLifecyclePhases();
+  EXPECT_FALSE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
+  EXPECT_FALSE(divWithTransform->descendantNeedsPaintPropertyUpdate());
+  EXPECT_FALSE(childLayoutView->descendantNeedsPaintPropertyUpdate());
+  EXPECT_FALSE(innerDivWithTransform->descendantNeedsPaintPropertyUpdate());
+
+  // A child frame marked as needing a paint property update should not be
+  // skipped if the owning layout tree does not need an update.
+  FrameView* childFrameView = childDocument().view();
+  childFrameView->setNeedsPaintPropertyUpdate();
+  EXPECT_TRUE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
+  frameView->updateAllLifecyclePhases();
+  EXPECT_FALSE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
+  EXPECT_FALSE(frameView->needsPaintPropertyUpdate());
+  EXPECT_FALSE(childFrameView->needsPaintPropertyUpdate());
+}
+
+TEST_P(PaintPropertyTreeUpdateTest, UpdatingFrameViewContentClip) {
+  setBodyInnerHTML("hello world.");
+  EXPECT_EQ(FloatRoundedRect(0, 0, 800, 600), frameContentClip()->clipRect());
+  document().view()->resize(800, 599);
+  document().view()->updateAllLifecyclePhases();
+  EXPECT_EQ(FloatRoundedRect(0, 0, 800, 599), frameContentClip()->clipRect());
+  document().view()->resize(800, 600);
+  document().view()->updateAllLifecyclePhases();
+  EXPECT_EQ(FloatRoundedRect(0, 0, 800, 600), frameContentClip()->clipRect());
+  document().view()->resize(5, 5);
+  document().view()->updateAllLifecyclePhases();
+  EXPECT_EQ(FloatRoundedRect(0, 0, 5, 5), frameContentClip()->clipRect());
+}
+
+TEST_P(PaintPropertyTreeUpdateTest, BuildingStopsAtThrottledFrames) {
+  setBodyInnerHTML(
+      "<style>body { margin: 0; }</style>"
+      "<div id='transform' style='transform: translate3d(4px, 5px, 6px);'>"
+      "</div>"
+      "<iframe id='iframe' sandbox></iframe>");
+  setChildFrameHTML(
+      "<style>body { margin: 0; }</style>"
+      "<div id='iframeTransform'"
+      "  style='transform: translate3d(4px, 5px, 6px);'/>");
+
+  // Move the child frame offscreen so it becomes available for throttling.
+  auto* iframe = toHTMLIFrameElement(document().getElementById("iframe"));
+  iframe->setAttribute(HTMLNames::styleAttr, "transform: translateY(5555px)");
+  document().view()->updateAllLifecyclePhases();
+  // Ensure intersection observer notifications get delivered.
+  testing::runPendingTasks();
+  EXPECT_FALSE(document().view()->isHiddenForThrottling());
+  EXPECT_TRUE(childDocument().view()->isHiddenForThrottling());
+
+  auto* transform = document().getElementById("transform")->layoutObject();
+  auto* iframeLayoutView = childDocument().layoutView();
+  auto* iframeTransform =
+      childDocument().getElementById("iframeTransform")->layoutObject();
+
+  // Invalidate properties in the iframe and ensure ancestors are marked.
+  iframeTransform->setNeedsPaintPropertyUpdate();
+  EXPECT_FALSE(document().layoutView()->needsPaintPropertyUpdate());
+  EXPECT_TRUE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
+  EXPECT_FALSE(transform->needsPaintPropertyUpdate());
+  EXPECT_FALSE(transform->descendantNeedsPaintPropertyUpdate());
+  EXPECT_FALSE(iframeLayoutView->needsPaintPropertyUpdate());
+  EXPECT_TRUE(iframeLayoutView->descendantNeedsPaintPropertyUpdate());
+  EXPECT_TRUE(iframeTransform->needsPaintPropertyUpdate());
+  EXPECT_FALSE(iframeTransform->descendantNeedsPaintPropertyUpdate());
+
+  transform->setNeedsPaintPropertyUpdate();
+  EXPECT_TRUE(transform->needsPaintPropertyUpdate());
+  EXPECT_FALSE(transform->descendantNeedsPaintPropertyUpdate());
+
+  {
+    DocumentLifecycle::AllowThrottlingScope throttlingScope(
+        document().lifecycle());
+    EXPECT_FALSE(document().view()->shouldThrottleRendering());
+    EXPECT_TRUE(childDocument().view()->shouldThrottleRendering());
+
+    // A lifecycle update should update all properties except those with
+    // actively throttled descendants.
+    document().view()->updateAllLifecyclePhases();
+    EXPECT_FALSE(document().layoutView()->needsPaintPropertyUpdate());
+    EXPECT_TRUE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
+    EXPECT_FALSE(transform->needsPaintPropertyUpdate());
+    EXPECT_FALSE(transform->descendantNeedsPaintPropertyUpdate());
+    EXPECT_FALSE(iframeLayoutView->needsPaintPropertyUpdate());
+    EXPECT_TRUE(iframeLayoutView->descendantNeedsPaintPropertyUpdate());
+    EXPECT_TRUE(iframeTransform->needsPaintPropertyUpdate());
+    EXPECT_FALSE(iframeTransform->descendantNeedsPaintPropertyUpdate());
+  }
+
+  EXPECT_FALSE(document().view()->shouldThrottleRendering());
+  EXPECT_FALSE(childDocument().view()->shouldThrottleRendering());
+  // Once unthrottled, a lifecycel update should update all properties.
+  document().view()->updateAllLifecyclePhases();
+  EXPECT_FALSE(document().layoutView()->needsPaintPropertyUpdate());
+  EXPECT_FALSE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
+  EXPECT_FALSE(transform->needsPaintPropertyUpdate());
+  EXPECT_FALSE(transform->descendantNeedsPaintPropertyUpdate());
+  EXPECT_FALSE(iframeLayoutView->needsPaintPropertyUpdate());
+  EXPECT_FALSE(iframeLayoutView->descendantNeedsPaintPropertyUpdate());
+  EXPECT_FALSE(iframeTransform->needsPaintPropertyUpdate());
+  EXPECT_FALSE(iframeTransform->descendantNeedsPaintPropertyUpdate());
+}
+
+TEST_P(PaintPropertyTreeUpdateTest, ClipChangesUpdateOverflowClip) {
+  setBodyInnerHTML(
+      "<style>"
+      "  body { margin:0 }"
+      "  #div { overflow:hidden; height:0px; }"
+      "</style>"
+      "<div id='div'></div>");
+  auto* div = document().getElementById("div");
+  div->setAttribute(HTMLNames::styleAttr, "display:inline-block; width:7px;");
+  document().view()->updateAllLifecyclePhases();
+  auto* clipProperties = div->layoutObject()->paintProperties()->overflowClip();
+  EXPECT_EQ(FloatRect(0, 0, 7, 0), clipProperties->clipRect().rect());
+
+  // Width changes should update the overflow clip.
+  div->setAttribute(HTMLNames::styleAttr, "display:inline-block; width:7px;");
+  document().view()->updateAllLifecyclePhases();
+  clipProperties = div->layoutObject()->paintProperties()->overflowClip();
+  EXPECT_EQ(FloatRect(0, 0, 7, 0), clipProperties->clipRect().rect());
+  div->setAttribute(HTMLNames::styleAttr, "display:inline-block; width:9px;");
+  document().view()->updateAllLifecyclePhases();
+  EXPECT_EQ(FloatRect(0, 0, 9, 0), clipProperties->clipRect().rect());
+
+  // An inline block's overflow clip should be updated when padding changes,
+  // even if the border box remains unchanged.
+  div->setAttribute(HTMLNames::styleAttr,
+                    "display:inline-block; width:7px; padding-right:3px;");
+  document().view()->updateAllLifecyclePhases();
+  clipProperties = div->layoutObject()->paintProperties()->overflowClip();
+  EXPECT_EQ(FloatRect(0, 0, 10, 0), clipProperties->clipRect().rect());
+  div->setAttribute(HTMLNames::styleAttr,
+                    "display:inline-block; width:8px; padding-right:2px;");
+  document().view()->updateAllLifecyclePhases();
+  EXPECT_EQ(FloatRect(0, 0, 10, 0), clipProperties->clipRect().rect());
+  div->setAttribute(HTMLNames::styleAttr,
+                    "display:inline-block; width:8px;"
+                    "padding-right:1px; padding-left:1px;");
+  document().view()->updateAllLifecyclePhases();
+  EXPECT_EQ(FloatRect(0, 0, 10, 0), clipProperties->clipRect().rect());
+
+  // An block's overflow clip should be updated when borders change.
+  div->setAttribute(HTMLNames::styleAttr, "border-right:3px solid red;");
+  document().view()->updateAllLifecyclePhases();
+  clipProperties = div->layoutObject()->paintProperties()->overflowClip();
+  EXPECT_EQ(FloatRect(0, 0, 797, 0), clipProperties->clipRect().rect());
+  div->setAttribute(HTMLNames::styleAttr, "border-right:5px solid red;");
+  document().view()->updateAllLifecyclePhases();
+  EXPECT_EQ(FloatRect(0, 0, 795, 0), clipProperties->clipRect().rect());
+
+  // Removing overflow clip should remove the property.
+  div->setAttribute(HTMLNames::styleAttr, "overflow:hidden;");
+  document().view()->updateAllLifecyclePhases();
+  clipProperties = div->layoutObject()->paintProperties()->overflowClip();
+  EXPECT_EQ(FloatRect(0, 0, 800, 0), clipProperties->clipRect().rect());
+  div->setAttribute(HTMLNames::styleAttr, "overflow:visible;");
+  document().view()->updateAllLifecyclePhases();
+  EXPECT_TRUE(!div->layoutObject()->paintProperties() ||
+              !div->layoutObject()->paintProperties()->overflowClip());
+}
+
+TEST_P(PaintPropertyTreeUpdateTest, ContainPaintChangesUpdateOverflowClip) {
+  setBodyInnerHTML(
+      "<style>"
+      "  body { margin:0 }"
+      "  #div { will-change:transform; width:7px; height:6px; }"
+      "</style>"
+      "<div id='div' style='contain:paint;'></div>");
+  document().view()->updateAllLifecyclePhases();
+  auto* div = document().getElementById("div");
+  auto* properties = div->layoutObject()->paintProperties()->overflowClip();
+  EXPECT_EQ(FloatRect(0, 0, 7, 6), properties->clipRect().rect());
+
+  div->setAttribute(HTMLNames::styleAttr, "");
+  document().view()->updateAllLifecyclePhases();
+  EXPECT_TRUE(!div->layoutObject()->paintProperties() ||
+              !div->layoutObject()->paintProperties()->overflowClip());
+}
+
+// A basic sanity check for over-invalidation of paint properties.
+TEST_P(PaintPropertyTreeUpdateTest, NoPaintPropertyUpdateOnBackgroundChange) {
+  setBodyInnerHTML("<div id='div' style='background-color: blue'>DIV</div>");
+  auto* div = document().getElementById("div");
+
+  document().view()->updateAllLifecyclePhases();
+  div->setAttribute(HTMLNames::styleAttr, "background-color: green");
+  document().view()->updateLifecycleToLayoutClean();
+  EXPECT_FALSE(div->layoutObject()->needsPaintPropertyUpdate());
+}
+
+// Disabled due to stale scrollsOverflow values, see: https://crbug.com/675296.
+TEST_P(PaintPropertyTreeUpdateTest,
+       DISABLED_FrameVisibilityChangeUpdatesProperties) {
+  setBodyInnerHTML(
+      "<style>body { margin: 0; }</style>"
+      "<div id='iframeContainer'>"
+      "  <iframe id='iframe' style='width: 100px; height: 100px;'></iframe>"
+      "</div>");
+  setChildFrameHTML(
+      "<style>body { margin: 0; }</style>"
+      "<div id='forceScroll' style='height: 3000px;'></div>");
+
+  FrameView* frameView = document().view();
+  frameView->updateAllLifecyclePhases();
+  EXPECT_EQ(nullptr, frameScroll(frameView));
+  FrameView* childFrameView = childDocument().view();
+  EXPECT_NE(nullptr, frameScroll(childFrameView));
+
+  auto* iframeContainer = document().getElementById("iframeContainer");
+  iframeContainer->setAttribute(HTMLNames::styleAttr, "visibility: hidden;");
+  frameView->updateAllLifecyclePhases();
+
+  EXPECT_EQ(nullptr, frameScroll(frameView));
+  EXPECT_EQ(nullptr, frameScroll(childFrameView));
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/devtools/front_end/main/Main.js b/third_party/WebKit/Source/devtools/front_end/main/Main.js
index b7994b5..eb9fee14 100644
--- a/third_party/WebKit/Source/devtools/front_end/main/Main.js
+++ b/third_party/WebKit/Source/devtools/front_end/main/Main.js
@@ -103,6 +103,7 @@
     Runtime.experiments.register('emptySourceMapAutoStepping', 'Empty sourcemap auto-stepping');
     Runtime.experiments.register('inputEventsOnTimelineOverview', 'Input events on Timeline overview', true);
     Runtime.experiments.register('liveSASS', 'Live SASS');
+    Runtime.experiments.register('networkGroupingRequests', 'Network request groups support', true);
     Runtime.experiments.register('nodeDebugging', 'Node debugging', true);
     Runtime.experiments.register('persistence2', 'Persistence 2.0');
     Runtime.experiments.register('persistenceValidation', 'Validate persistence bindings');
diff --git a/third_party/WebKit/Source/devtools/front_end/main/module.json b/third_party/WebKit/Source/devtools/front_end/main/module.json
index a4ad454..60020383 100644
--- a/third_party/WebKit/Source/devtools/front_end/main/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/main/module.json
@@ -265,9 +265,10 @@
             "settingType": "enum",
             "defaultValue": "default",
             "options": [
-                { "title": "Switch to default theme", "text": "Default", "value": "default" },
+                { "title": "Switch to light theme", "text": "Light", "value": "default" },
                 { "title": "Switch to dark theme", "text": "Dark", "value": "dark" }
-            ]
+            ],
+            "tags": "dark, light"
         },
         {
             "type": "setting",
diff --git a/third_party/WebKit/Source/devtools/front_end/network/NetworkDataGridNode.js b/third_party/WebKit/Source/devtools/front_end/network/NetworkDataGridNode.js
index e62d3fb..57690c4b 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/NetworkDataGridNode.js
+++ b/third_party/WebKit/Source/devtools/front_end/network/NetworkDataGridNode.js
@@ -31,7 +31,33 @@
 /**
  * @unrestricted
  */
-Network.NetworkDataGridNode = class extends UI.SortableDataGridNode {
+Network.NetworkNode = class extends UI.SortableDataGridNode {
+  /**
+   * @return {?SDK.NetworkRequest}
+   */
+  request() {
+    return null;
+  }
+
+  /**
+   * @return {boolean}
+   */
+  isNavigationRequest() {
+    return false;
+  }
+
+  /**
+   * @return {?Network.NetworkRequestNode}
+   */
+  asRequestNode() {
+    return null;
+  }
+};
+
+/**
+ * @unrestricted
+ */
+Network.NetworkRequestNode = class extends Network.NetworkNode {
   /**
    * @param {!Network.NetworkLogView} parentView
    * @param {!SDK.NetworkRequest} request
@@ -45,72 +71,98 @@
   }
 
   /**
-   * @param {!Network.NetworkDataGridNode} a
-   * @param {!Network.NetworkDataGridNode} b
+   * @param {!Network.NetworkNode} a
+   * @param {!Network.NetworkNode} b
    * @return {number}
    */
   static NameComparator(a, b) {
-    var aFileName = a._request.name();
-    var bFileName = b._request.name();
+    // TODO(allada) Handle this properly for group nodes.
+    var aRequest = a.request();
+    var bRequest = b.request();
+    if (!aRequest || !bRequest)
+      return !aRequest ? -1 : 1;
+
+    var aFileName = aRequest.name();
+    var bFileName = bRequest.name();
     if (aFileName > bFileName)
       return 1;
     if (bFileName > aFileName)
       return -1;
-    return a._request.indentityCompare(b._request);
+    return aRequest.indentityCompare(bRequest);
   }
 
   /**
-   * @param {!Network.NetworkDataGridNode} a
-   * @param {!Network.NetworkDataGridNode} b
+   * @param {!Network.NetworkNode} a
+   * @param {!Network.NetworkNode} b
    * @return {number}
    */
   static RemoteAddressComparator(a, b) {
-    var aRemoteAddress = a._request.remoteAddress();
-    var bRemoteAddress = b._request.remoteAddress();
+    // TODO(allada) Handle this properly for group nodes.
+    var aRequest = a.request();
+    var bRequest = b.request();
+    if (!aRequest || !bRequest)
+      return !aRequest ? -1 : 1;
+    var aRemoteAddress = aRequest.remoteAddress();
+    var bRemoteAddress = bRequest.remoteAddress();
     if (aRemoteAddress > bRemoteAddress)
       return 1;
     if (bRemoteAddress > aRemoteAddress)
       return -1;
-    return a._request.indentityCompare(b._request);
+    return aRequest.indentityCompare(bRequest);
   }
 
   /**
-   * @param {!Network.NetworkDataGridNode} a
-   * @param {!Network.NetworkDataGridNode} b
+   * @param {!Network.NetworkNode} a
+   * @param {!Network.NetworkNode} b
    * @return {number}
    */
   static SizeComparator(a, b) {
-    if (b._request.cached() && !a._request.cached())
+    // TODO(allada) Handle this properly for group nodes.
+    var aRequest = a.request();
+    var bRequest = b.request();
+    if (!aRequest || !bRequest)
+      return !aRequest ? -1 : 1;
+    if (bRequest.cached() && !aRequest.cached())
       return 1;
-    if (a._request.cached() && !b._request.cached())
+    if (aRequest.cached() && !bRequest.cached())
       return -1;
-    return (a._request.transferSize - b._request.transferSize) || a._request.indentityCompare(b._request);
+    return (aRequest.transferSize - bRequest.transferSize) || aRequest.indentityCompare(bRequest);
   }
 
   /**
-   * @param {!Network.NetworkDataGridNode} a
-   * @param {!Network.NetworkDataGridNode} b
+   * @param {!Network.NetworkNode} a
+   * @param {!Network.NetworkNode} b
    * @return {number}
    */
   static TypeComparator(a, b) {
-    var aSimpleType = a.displayType();
-    var bSimpleType = b.displayType();
+    // TODO(allada) Handle this properly for group nodes.
+    var aRequest = a.request();
+    var bRequest = b.request();
+    if (!aRequest || !bRequest)
+      return !aRequest ? -1 : 1;
+    var aSimpleType = a.asRequestNode().displayType();
+    var bSimpleType = b.asRequestNode().displayType();
 
     if (aSimpleType > bSimpleType)
       return 1;
     if (bSimpleType > aSimpleType)
       return -1;
-    return a._request.indentityCompare(b._request);
+    return aRequest.indentityCompare(bRequest);
   }
 
   /**
-   * @param {!Network.NetworkDataGridNode} a
-   * @param {!Network.NetworkDataGridNode} b
+   * @param {!Network.NetworkNode} a
+   * @param {!Network.NetworkNode} b
    * @return {number}
    */
   static InitiatorComparator(a, b) {
-    var aInitiator = a._request.initiatorInfo();
-    var bInitiator = b._request.initiatorInfo();
+    // TODO(allada) Handle this properly for group nodes.
+    var aRequest = a.request();
+    var bRequest = b.request();
+    if (!aRequest || !bRequest)
+      return !aRequest ? -1 : 1;
+    var aInitiator = aRequest.initiatorInfo();
+    var bInitiator = bRequest.initiatorInfo();
 
     if (aInitiator.type < bInitiator.type)
       return -1;
@@ -137,110 +189,145 @@
     if (aInitiator.columnNumber > bInitiator.columnNumber)
       return 1;
 
-    return a._request.indentityCompare(b._request);
+    return aRequest.indentityCompare(bRequest);
   }
 
   /**
-   * @param {!Network.NetworkDataGridNode} a
-   * @param {!Network.NetworkDataGridNode} b
+   * @param {!Network.NetworkNode} a
+   * @param {!Network.NetworkNode} b
    * @return {number}
    */
   static RequestCookiesCountComparator(a, b) {
-    var aScore = a._request.requestCookies ? a._request.requestCookies.length : 0;
-    var bScore = b._request.requestCookies ? b._request.requestCookies.length : 0;
-    return (aScore - bScore) || a._request.indentityCompare(b._request);
+    // TODO(allada) Handle this properly for group nodes.
+    var aRequest = a.request();
+    var bRequest = b.request();
+    if (!aRequest || !bRequest)
+      return !aRequest ? -1 : 1;
+    var aScore = aRequest.requestCookies ? aRequest.requestCookies.length : 0;
+    var bScore = bRequest.requestCookies ? bRequest.requestCookies.length : 0;
+    return (aScore - bScore) || aRequest.indentityCompare(bRequest);
   }
 
   /**
-   * @param {!Network.NetworkDataGridNode} a
-   * @param {!Network.NetworkDataGridNode} b
+   * @param {!Network.NetworkNode} a
+   * @param {!Network.NetworkNode} b
    * @return {number}
    */
   static ResponseCookiesCountComparator(a, b) {
-    var aScore = a._request.responseCookies ? a._request.responseCookies.length : 0;
-    var bScore = b._request.responseCookies ? b._request.responseCookies.length : 0;
-    return (aScore - bScore) || a._request.indentityCompare(b._request);
+    // TODO(allada) Handle this properly for group nodes.
+    var aRequest = a.request();
+    var bRequest = b.request();
+    if (!aRequest || !bRequest)
+      return !aRequest ? -1 : 1;
+    var aScore = aRequest.responseCookies ? aRequest.responseCookies.length : 0;
+    var bScore = bRequest.responseCookies ? bRequest.responseCookies.length : 0;
+    return (aScore - bScore) || aRequest.indentityCompare(bRequest);
   }
 
   /**
-   * @param {!Network.NetworkDataGridNode} a
-   * @param {!Network.NetworkDataGridNode} b
+   * @param {!Network.NetworkNode} a
+   * @param {!Network.NetworkNode} b
    * @return {number}
    */
   static InitialPriorityComparator(a, b) {
-    var priorityMap = Network.NetworkDataGridNode._symbolicToNumericPriority;
+    // TODO(allada) Handle this properly for group nodes.
+    var aRequest = a.request();
+    var bRequest = b.request();
+    if (!aRequest || !bRequest)
+      return !aRequest ? -1 : 1;
+    var priorityMap = Network.NetworkRequestNode._symbolicToNumericPriority;
     if (!priorityMap) {
-      Network.NetworkDataGridNode._symbolicToNumericPriority = new Map();
-      priorityMap = Network.NetworkDataGridNode._symbolicToNumericPriority;
+      Network.NetworkRequestNode._symbolicToNumericPriority = new Map();
+      priorityMap = Network.NetworkRequestNode._symbolicToNumericPriority;
       priorityMap.set(Protocol.Network.ResourcePriority.VeryLow, 1);
       priorityMap.set(Protocol.Network.ResourcePriority.Low, 2);
       priorityMap.set(Protocol.Network.ResourcePriority.Medium, 3);
       priorityMap.set(Protocol.Network.ResourcePriority.High, 4);
       priorityMap.set(Protocol.Network.ResourcePriority.VeryHigh, 5);
     }
-    var aScore = priorityMap.get(a._request.initialPriority()) || 0;
-    var bScore = priorityMap.get(b._request.initialPriority()) || 0;
+    var aScore = priorityMap.get(aRequest.initialPriority()) || 0;
+    var bScore = priorityMap.get(bRequest.initialPriority()) || 0;
 
-    return aScore - bScore || a._request.indentityCompare(b._request);
+    return aScore - bScore || aRequest.indentityCompare(bRequest);
   }
 
   /**
    * @param {string} propertyName
-   * @param {!Network.NetworkDataGridNode} a
-   * @param {!Network.NetworkDataGridNode} b
+   * @param {!Network.NetworkNode} a
+   * @param {!Network.NetworkNode} b
    * @return {number}
    */
   static RequestPropertyComparator(propertyName, a, b) {
-    var aValue = a._request[propertyName];
-    var bValue = b._request[propertyName];
+    // TODO(allada) Handle this properly for group nodes.
+    var aRequest = a.request();
+    var bRequest = b.request();
+    if (!aRequest || !bRequest)
+      return !aRequest ? -1 : 1;
+    var aValue = aRequest[propertyName];
+    var bValue = bRequest[propertyName];
     if (aValue === bValue)
-      return a._request.indentityCompare(b._request);
+      return aRequest.indentityCompare(bRequest);
     return aValue > bValue ? 1 : -1;
   }
 
   /**
    * @param {string} propertyName
-   * @param {!Network.NetworkDataGridNode} a
-   * @param {!Network.NetworkDataGridNode} b
+   * @param {!Network.NetworkNode} a
+   * @param {!Network.NetworkNode} b
    * @return {number}
    */
   static ResponseHeaderStringComparator(propertyName, a, b) {
-    var aValue = String(a._request.responseHeaderValue(propertyName) || '');
-    var bValue = String(b._request.responseHeaderValue(propertyName) || '');
-    return aValue.localeCompare(bValue) || a._request.indentityCompare(b._request);
+    // TODO(allada) Handle this properly for group nodes.
+    var aRequest = a.request();
+    var bRequest = b.request();
+    if (!aRequest || !bRequest)
+      return !aRequest ? -1 : 1;
+    var aValue = String(aRequest.responseHeaderValue(propertyName) || '');
+    var bValue = String(bRequest.responseHeaderValue(propertyName) || '');
+    return aValue.localeCompare(bValue) || aRequest.indentityCompare(bRequest);
   }
 
   /**
    * @param {string} propertyName
-   * @param {!Network.NetworkDataGridNode} a
-   * @param {!Network.NetworkDataGridNode} b
+   * @param {!Network.NetworkNode} a
+   * @param {!Network.NetworkNode} b
    * @return {number}
    */
   static ResponseHeaderNumberComparator(propertyName, a, b) {
-    var aValue = (a._request.responseHeaderValue(propertyName) !== undefined) ?
-        parseFloat(a._request.responseHeaderValue(propertyName)) :
+    // TODO(allada) Handle this properly for group nodes.
+    var aRequest = a.request();
+    var bRequest = b.request();
+    if (!aRequest || !bRequest)
+      return !aRequest ? -1 : 1;
+    var aValue = (aRequest.responseHeaderValue(propertyName) !== undefined) ?
+        parseFloat(aRequest.responseHeaderValue(propertyName)) :
         -Infinity;
-    var bValue = (b._request.responseHeaderValue(propertyName) !== undefined) ?
-        parseFloat(b._request.responseHeaderValue(propertyName)) :
+    var bValue = (bRequest.responseHeaderValue(propertyName) !== undefined) ?
+        parseFloat(bRequest.responseHeaderValue(propertyName)) :
         -Infinity;
     if (aValue === bValue)
-      return a._request.indentityCompare(b._request);
+      return aRequest.indentityCompare(bRequest);
     return aValue > bValue ? 1 : -1;
   }
 
   /**
    * @param {string} propertyName
-   * @param {!Network.NetworkDataGridNode} a
-   * @param {!Network.NetworkDataGridNode} b
+   * @param {!Network.NetworkNode} a
+   * @param {!Network.NetworkNode} b
    * @return {number}
    */
   static ResponseHeaderDateComparator(propertyName, a, b) {
-    var aHeader = a._request.responseHeaderValue(propertyName);
-    var bHeader = b._request.responseHeaderValue(propertyName);
+    // TODO(allada) Handle this properly for group nodes.
+    var aRequest = a.request();
+    var bRequest = b.request();
+    if (!aRequest || !bRequest)
+      return !aRequest ? -1 : 1;
+    var aHeader = aRequest.responseHeaderValue(propertyName);
+    var bHeader = bRequest.responseHeaderValue(propertyName);
     var aValue = aHeader ? new Date(aHeader).getTime() : -Infinity;
     var bValue = bHeader ? new Date(bHeader).getTime() : -Infinity;
     if (aValue === bValue)
-      return a._request.indentityCompare(b._request);
+      return aRequest.indentityCompare(bRequest);
     return aValue > bValue ? 1 : -1;
   }
 
@@ -259,6 +346,7 @@
   }
 
   /**
+   * @override
    * @return {!SDK.NetworkRequest}
    */
   request() {
@@ -266,6 +354,15 @@
   }
 
   /**
+   * @override
+   * @return {!Network.NetworkRequestNode}
+   */
+  asRequestNode() {
+    return this;
+  }
+
+  /**
+   * @override
    * @return {boolean}
    */
   isNavigationRequest() {
@@ -602,3 +699,85 @@
     cellElement.appendChild(subtitleElement);
   }
 };
+
+/**
+ * @unrestricted
+ */
+Network.NetworkGroupNode = class extends Network.NetworkNode {
+  /**
+   * @param {!Network.NetworkLogView} parentView
+   * @param {string} name
+   */
+  constructor(parentView, name) {
+    super({});
+    this._parentView = parentView;
+    this._name = name;
+  }
+
+  /**
+   * @override
+   * @return {number}
+   */
+  nodeSelfHeight() {
+    return this._parentView.rowHeight();
+  }
+
+  /**
+   * @param {!Element} element
+   * @param {string} text
+   */
+  _setTextAndTitle(element, text) {
+    element.textContent = text;
+    element.title = text;
+  }
+
+  /**
+   * @override
+   * @param {string} columnIdentifier
+   * @return {!Element}
+   */
+  createCell(columnIdentifier) {
+    var cell = this.createTD(columnIdentifier);
+    if (columnIdentifier === 'name') {
+      cell.classList.add('disclosure');
+      this._setTextAndTitle(cell, this._name);
+    }
+    return cell;
+  }
+
+  /**
+   * @override
+   * @return {null}
+   */
+  request() {
+    return null;
+  }
+
+  /**
+   * @override
+   * @return {boolean}
+   */
+  isNavigationRequest() {
+    return false;
+  }
+
+  /**
+   * @override
+   * @return {null}
+   */
+  asRequestNode() {
+    return null;
+  }
+
+  /**
+   * @override
+   * @param {boolean=} supressSelectedEvent
+   */
+  select(supressSelectedEvent) {
+    if (this.expanded) {
+      this.collapse();
+      return;
+    }
+    this.expand();
+  }
+};
diff --git a/third_party/WebKit/Source/devtools/front_end/network/NetworkLogView.js b/third_party/WebKit/Source/devtools/front_end/network/NetworkLogView.js
index 45e5f03d..72b947b 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/NetworkLogView.js
+++ b/third_party/WebKit/Source/devtools/front_end/network/NetworkLogView.js
@@ -69,8 +69,10 @@
     this._columns = new Network.NetworkLogViewColumns(
         this, this._timeCalculator, this._durationCalculator, networkLogLargeRowsSetting);
 
-    /** @type {!Map.<string, !Network.NetworkDataGridNode>} */
+    /** @type {!Map.<string, !Network.NetworkRequestNode>} */
     this._nodesByRequestId = new Map();
+    /** @type {!Map.<string, !Network.NetworkGroupNode>} */
+    this._nodeGroups = new Map();
     /** @type {!Object.<string, boolean>} */
     this._staleRequestIds = {};
     /** @type {number} */
@@ -84,6 +86,7 @@
     this._filters = [];
     /** @type {?Network.NetworkLogView.Filter} */
     this._timeFilter = null;
+    /** @type {?Network.NetworkNode} */
     this._hoveredNode = null;
 
     this._currentMatchedRequestNode = null;
@@ -519,8 +522,8 @@
    * @param {!Event} event
    */
   _dataGridMouseMove(event) {
-    var node = /** @type {?Network.NetworkDataGridNode} */ (
-        this._dataGrid.dataGridNodeFromNode(/** @type {!Node} */ (event.target)));
+    var node =
+        /** @type {?Network.NetworkNode} */ (this._dataGrid.dataGridNodeFromNode(/** @type {!Node} */ (event.target)));
     var highlightInitiatorChain = event.shiftKey;
     this._setHoveredNode(node, highlightInitiatorChain);
     this._highlightInitiatorChain((highlightInitiatorChain && node) ? node.request() : null);
@@ -532,7 +535,7 @@
   }
 
   /**
-   * @param {?Network.NetworkDataGridNode} node
+   * @param {?Network.NetworkNode} node
    * @param {boolean} highlightInitiatorChain
    */
   setHoveredNode(node, highlightInitiatorChain) {
@@ -541,7 +544,7 @@
   }
 
   /**
-   * @param {?Network.NetworkDataGridNode} node
+   * @param {?Network.NetworkNode} node
    * @param {boolean=} highlightInitiatorChain
    */
   _setHoveredNode(node, highlightInitiatorChain) {
@@ -780,7 +783,7 @@
   }
 
   /**
-   * @return {!Array<!Network.NetworkDataGridNode>}
+   * @return {!Array<!Network.NetworkNode>}
    */
   flatNodesList() {
     return this._dataGrid.rootNode().flatChildren();
@@ -801,11 +804,9 @@
     this._timeCalculator.updateBoundariesForEventTime(this._mainRequestDOMContentLoadedTime);
     this._durationCalculator.updateBoundariesForEventTime(this._mainRequestDOMContentLoadedTime);
 
-    var dataGrid = this._dataGrid;
-    var rootNode = dataGrid.rootNode();
-    /** @type {!Array<!Network.NetworkDataGridNode> } */
+    /** @type {!Array<!Network.NetworkRequestNode> } */
     var nodesToInsert = [];
-    /** @type {!Array<!Network.NetworkDataGridNode> } */
+    /** @type {!Array<!Network.NetworkRequestNode> } */
     var nodesToRefresh = [];
     for (var requestId in this._staleRequestIds) {
       var node = this._nodesByRequestId.get(requestId);
@@ -816,7 +817,7 @@
         this._setHoveredNode(null);
       if (node[Network.NetworkLogView._isFilteredOutSymbol] !== isFilteredOut) {
         if (!node[Network.NetworkLogView._isFilteredOutSymbol])
-          rootNode.removeChild(node);
+          node.parent.removeChild(node);
 
         node[Network.NetworkLogView._isFilteredOutSymbol] = isFilteredOut;
 
@@ -833,8 +834,9 @@
     for (var i = 0; i < nodesToInsert.length; ++i) {
       var node = nodesToInsert[i];
       var request = node.request();
-      dataGrid.insertChild(node);
       node[Network.NetworkLogView._isMatchingSearchQuerySymbol] = this._matchRequest(request);
+      var parent = this._parentNodeForInsert(node);
+      parent.appendChild(node);
     }
 
     for (var node of nodesToRefresh)
@@ -849,6 +851,26 @@
     this._columns.dataChanged();
   }
 
+  /**
+   * @param {!Network.NetworkRequestNode} node
+   * @return {!Network.NetworkNode}
+   */
+  _parentNodeForInsert(node) {
+    if (!Runtime.experiments.isEnabled('networkGroupingRequests'))
+      return /** @type {!Network.NetworkNode} */ (this._dataGrid.rootNode());
+
+    var request = node.request();
+    // TODO(allada) Make this dynamic and allow multiple grouping types.
+    var groupKey = request.domain;
+    var group = this._nodeGroups.get(groupKey);
+    if (group)
+      return group;
+    group = new Network.NetworkGroupNode(this, groupKey);
+    this._nodeGroups.set(groupKey, group);
+    this._dataGrid.rootNode().appendChild(group);
+    return group;
+  }
+
   reset() {
     this._requestWithHighlightedInitiators = null;
     this.dispatchEventToListeners(Network.NetworkLogView.Events.RequestSelected, null);
@@ -867,6 +889,7 @@
     for (var i = 0; i < nodes.length; ++i)
       nodes[i].dispose();
 
+    this._nodeGroups.clear();
     this._nodesByRequestId.clear();
     this._staleRequestIds = {};
     this._resetSuggestionBuilder();
@@ -904,7 +927,7 @@
    * @param {!SDK.NetworkRequest} request
    */
   _appendRequest(request) {
-    var node = new Network.NetworkDataGridNode(this, request);
+    var node = new Network.NetworkRequestNode(this, request);
     node[Network.NetworkLogView._isFilteredOutSymbol] = true;
     node[Network.NetworkLogView._isMatchingSearchQuerySymbol] = false;
 
@@ -1234,7 +1257,7 @@
   _highlightNthMatchedRequestForSearch(n, reveal) {
     this._removeAllHighlights();
 
-    /** @type {!Array.<!Network.NetworkDataGridNode>} */
+    /** @type {!Array.<!Network.NetworkRequestNode>} */
     var nodes = this._dataGrid.rootNode().children;
     var matchCount = 0;
     var node = null;
@@ -1275,7 +1298,7 @@
     this._clearSearchMatchedList();
     this._searchRegex = createPlainTextSearchRegex(query, 'i');
 
-    /** @type {!Array.<!Network.NetworkDataGridNode>} */
+    /** @type {!Array.<!Network.NetworkRequestNode>} */
     var nodes = this._dataGrid.rootNode().children;
     for (var i = 0; i < nodes.length; ++i)
       nodes[i][Network.NetworkLogView._isMatchingSearchQuerySymbol] = this._matchRequest(nodes[i].request());
@@ -1302,11 +1325,11 @@
   }
 
   /**
-   * @param {?Network.NetworkDataGridNode} node
+   * @param {?Network.NetworkRequestNode} node
    * @return {number}
    */
   _updateMatchCountAndFindMatchIndex(node) {
-    /** @type {!Array.<!Network.NetworkDataGridNode>} */
+    /** @type {!Array.<!Network.NetworkRequestNode>} */
     var nodes = this._dataGrid.rootNode().children;
     var matchCount = 0;
     var matchIndex = 0;
@@ -1333,7 +1356,7 @@
   }
 
   /**
-   * @param {!Network.NetworkDataGridNode} node
+   * @param {!Network.NetworkRequestNode} node
    * @return {boolean}
    */
   _applyFilter(node) {
@@ -1536,7 +1559,7 @@
   }
 
   /**
-   * @param {!Network.NetworkDataGridNode} node
+   * @param {!Network.NetworkRequestNode} node
    */
   _highlightNode(node) {
     UI.runCSSAnimationOnce(node.element(), 'highlighted-row');
diff --git a/third_party/WebKit/Source/devtools/front_end/network/NetworkLogViewColumns.js b/third_party/WebKit/Source/devtools/front_end/network/NetworkLogViewColumns.js
index 7e502ba..8b52c9f 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/NetworkLogViewColumns.js
+++ b/third_party/WebKit/Source/devtools/front_end/network/NetworkLogViewColumns.js
@@ -203,7 +203,7 @@
   }
 
   /**
-   * @param {?Network.NetworkDataGridNode} node
+   * @param {?Network.NetworkNode} node
    * @param {boolean} highlightInitiatorChain
    */
   setHoveredNode(node, highlightInitiatorChain) {
@@ -285,7 +285,7 @@
         this._waterfallColumnSortIcon.classList.add('sort-descending');
 
       this._waterfallRequestsAreStale = true;
-      var sortFunction = Network.NetworkDataGridNode.RequestPropertyComparator.bind(null, this._activeWaterfallSortId);
+      var sortFunction = Network.NetworkRequestNode.RequestPropertyComparator.bind(null, this._activeWaterfallSortId);
       this._dataGrid.sortNodes(sortFunction, !this._dataGrid.isSortOrderAscending());
       this._networkLogView.dataGridSorted();
       return;
@@ -500,7 +500,7 @@
           isResponseHeader: true,
           isCustomHeader: true,
           visible: true,
-          sortingFunction: Network.NetworkDataGridNode.ResponseHeaderStringComparator.bind(null, headerId)
+          sortingFunction: Network.NetworkRequestNode.ResponseHeaderStringComparator.bind(null, headerId)
         }));
     this._columns.splice(index, 0, columnConfig);
     if (this._dataGrid)
@@ -626,7 +626,7 @@
  *     sortable: boolean,
  *     align: (?UI.DataGrid.Align|undefined),
  *     isResponseHeader: boolean,
- *     sortingFunction: (!function(!Network.NetworkDataGridNode, !Network.NetworkDataGridNode):number|undefined),
+ *     sortingFunction: (!function(!Network.NetworkRequestNode, !Network.NetworkRequestNode):number|undefined),
  *     isCustomHeader: boolean
  * }}
  */
@@ -666,66 +666,66 @@
     hideable: false,
     nonSelectable: false,
     alwaysVisible: true,
-    sortingFunction: Network.NetworkDataGridNode.NameComparator
+    sortingFunction: Network.NetworkRequestNode.NameComparator
   },
   {
     id: 'method',
     title: Common.UIString('Method'),
-    sortingFunction: Network.NetworkDataGridNode.RequestPropertyComparator.bind(null, 'requestMethod')
+    sortingFunction: Network.NetworkRequestNode.RequestPropertyComparator.bind(null, 'requestMethod')
   },
   {
     id: 'status',
     title: Common.UIString('Status'),
     visible: true,
     subtitle: Common.UIString('Text'),
-    sortingFunction: Network.NetworkDataGridNode.RequestPropertyComparator.bind(null, 'statusCode')
+    sortingFunction: Network.NetworkRequestNode.RequestPropertyComparator.bind(null, 'statusCode')
   },
   {
     id: 'protocol',
     title: Common.UIString('Protocol'),
-    sortingFunction: Network.NetworkDataGridNode.RequestPropertyComparator.bind(null, 'protocol')
+    sortingFunction: Network.NetworkRequestNode.RequestPropertyComparator.bind(null, 'protocol')
   },
   {
     id: 'scheme',
     title: Common.UIString('Scheme'),
-    sortingFunction: Network.NetworkDataGridNode.RequestPropertyComparator.bind(null, 'scheme')
+    sortingFunction: Network.NetworkRequestNode.RequestPropertyComparator.bind(null, 'scheme')
   },
   {
     id: 'domain',
     title: Common.UIString('Domain'),
-    sortingFunction: Network.NetworkDataGridNode.RequestPropertyComparator.bind(null, 'domain')
+    sortingFunction: Network.NetworkRequestNode.RequestPropertyComparator.bind(null, 'domain')
   },
   {
     id: 'remoteaddress',
     title: Common.UIString('Remote Address'),
     weight: 10,
     align: UI.DataGrid.Align.Right,
-    sortingFunction: Network.NetworkDataGridNode.RemoteAddressComparator
+    sortingFunction: Network.NetworkRequestNode.RemoteAddressComparator
   },
   {
     id: 'type',
     title: Common.UIString('Type'),
     visible: true,
-    sortingFunction: Network.NetworkDataGridNode.TypeComparator
+    sortingFunction: Network.NetworkRequestNode.TypeComparator
   },
   {
     id: 'initiator',
     title: Common.UIString('Initiator'),
     visible: true,
     weight: 10,
-    sortingFunction: Network.NetworkDataGridNode.InitiatorComparator
+    sortingFunction: Network.NetworkRequestNode.InitiatorComparator
   },
   {
     id: 'cookies',
     title: Common.UIString('Cookies'),
     align: UI.DataGrid.Align.Right,
-    sortingFunction: Network.NetworkDataGridNode.RequestCookiesCountComparator
+    sortingFunction: Network.NetworkRequestNode.RequestCookiesCountComparator
   },
   {
     id: 'setcookies',
     title: Common.UIString('Set Cookies'),
     align: UI.DataGrid.Align.Right,
-    sortingFunction: Network.NetworkDataGridNode.ResponseCookiesCountComparator
+    sortingFunction: Network.NetworkRequestNode.ResponseCookiesCountComparator
   },
   {
     id: 'size',
@@ -733,7 +733,7 @@
     visible: true,
     subtitle: Common.UIString('Content'),
     align: UI.DataGrid.Align.Right,
-    sortingFunction: Network.NetworkDataGridNode.SizeComparator
+    sortingFunction: Network.NetworkRequestNode.SizeComparator
   },
   {
     id: 'time',
@@ -741,72 +741,72 @@
     visible: true,
     subtitle: Common.UIString('Latency'),
     align: UI.DataGrid.Align.Right,
-    sortingFunction: Network.NetworkDataGridNode.RequestPropertyComparator.bind(null, 'duration')
+    sortingFunction: Network.NetworkRequestNode.RequestPropertyComparator.bind(null, 'duration')
   },
   {
     id: 'priority',
     title: Common.UIString('Priority'),
-    sortingFunction: Network.NetworkDataGridNode.InitialPriorityComparator
+    sortingFunction: Network.NetworkRequestNode.InitialPriorityComparator
   },
   {
     id: 'connectionid',
     title: Common.UIString('Connection ID'),
-    sortingFunction: Network.NetworkDataGridNode.RequestPropertyComparator.bind(null, 'connectionId')
+    sortingFunction: Network.NetworkRequestNode.RequestPropertyComparator.bind(null, 'connectionId')
   },
   {
     id: 'cache-control',
     isResponseHeader: true,
     title: Common.UIString('Cache-Control'),
-    sortingFunction: Network.NetworkDataGridNode.ResponseHeaderStringComparator.bind(null, 'cache-control')
+    sortingFunction: Network.NetworkRequestNode.ResponseHeaderStringComparator.bind(null, 'cache-control')
   },
   {
     id: 'connection',
     isResponseHeader: true,
     title: Common.UIString('Connection'),
-    sortingFunction: Network.NetworkDataGridNode.ResponseHeaderStringComparator.bind(null, 'connection')
+    sortingFunction: Network.NetworkRequestNode.ResponseHeaderStringComparator.bind(null, 'connection')
   },
   {
     id: 'content-encoding',
     isResponseHeader: true,
     title: Common.UIString('Content-Encoding'),
-    sortingFunction: Network.NetworkDataGridNode.ResponseHeaderStringComparator.bind(null, 'content-encoding')
+    sortingFunction: Network.NetworkRequestNode.ResponseHeaderStringComparator.bind(null, 'content-encoding')
   },
   {
     id: 'content-length',
     isResponseHeader: true,
     title: Common.UIString('Content-Length'),
     align: UI.DataGrid.Align.Right,
-    sortingFunction: Network.NetworkDataGridNode.ResponseHeaderNumberComparator.bind(null, 'content-length')
+    sortingFunction: Network.NetworkRequestNode.ResponseHeaderNumberComparator.bind(null, 'content-length')
   },
   {
     id: 'etag',
     isResponseHeader: true,
     title: Common.UIString('ETag'),
-    sortingFunction: Network.NetworkDataGridNode.ResponseHeaderStringComparator.bind(null, 'etag')
+    sortingFunction: Network.NetworkRequestNode.ResponseHeaderStringComparator.bind(null, 'etag')
   },
   {
     id: 'keep-alive',
     isResponseHeader: true,
     title: Common.UIString('Keep-Alive'),
-    sortingFunction: Network.NetworkDataGridNode.ResponseHeaderStringComparator.bind(null, 'keep-alive')
+    sortingFunction: Network.NetworkRequestNode.ResponseHeaderStringComparator.bind(null, 'keep-alive')
   },
   {
     id: 'last-modified',
     isResponseHeader: true,
     title: Common.UIString('Last-Modified'),
-    sortingFunction: Network.NetworkDataGridNode.ResponseHeaderDateComparator.bind(null, 'last-modified')
+    sortingFunction: Network.NetworkRequestNode.ResponseHeaderDateComparator.bind(null, 'last-modified')
   },
   {
     id: 'server',
     isResponseHeader: true,
     title: Common.UIString('Server'),
-    sortingFunction: Network.NetworkDataGridNode.ResponseHeaderStringComparator.bind(null, 'server')
+    sortingFunction: Network.NetworkRequestNode.ResponseHeaderStringComparator.bind(null, 'server')
   },
   {
     id: 'vary',
     isResponseHeader: true,
     title: Common.UIString('Vary'),
-    sortingFunction: Network.NetworkDataGridNode.ResponseHeaderStringComparator.bind(null, 'vary')
+    sortingFunction: Network.NetworkRequestNode.ResponseHeaderStringComparator.bind(null, 'vary')
   },
   // This header is a placeholder to let datagrid know that it can be sorted by this column, but never shown.
   {id: 'waterfall', title: '', visible: false, hideable: false}
diff --git a/third_party/WebKit/Source/devtools/front_end/network/NetworkWaterfallColumn.js b/third_party/WebKit/Source/devtools/front_end/network/NetworkWaterfallColumn.js
index fa0e508..bc1fa4a 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/NetworkWaterfallColumn.js
+++ b/third_party/WebKit/Source/devtools/front_end/network/NetworkWaterfallColumn.js
@@ -34,10 +34,10 @@
     this._popoverHelper.initializeCallbacks(this._getPopoverAnchor.bind(this), this._showPopover.bind(this));
     this._popoverHelper.setTimeout(300, 300);
 
-    /** @type {!Array<!Network.NetworkDataGridNode>} */
+    /** @type {!Array<!Network.NetworkNode>} */
     this._nodes = [];
 
-    /** @type {?Network.NetworkDataGridNode} */
+    /** @type {?Network.NetworkNode} */
     this._hoveredNode = null;
     /** @type {?SDK.NetworkRequest.InitiatorGraph} */
     this._initiatorGraph = null;
@@ -83,12 +83,15 @@
       return;
     var useTimingBars = !Common.moduleSetting('networkColorCodeResourceTypes').get() && !this._calculator.startAtZero;
     if (useTimingBars) {
-      var range = Network.RequestTimingView.calculateRequestTimeRanges(this._hoveredNode.request(), 0)
+      var request = this._hoveredNode.request();
+      if (!request)
+        return;
+      var range = Network.RequestTimingView.calculateRequestTimeRanges(request, 0)
                       .find(data => data.name === Network.RequestTimeRangeNames.Total);
       var start = this._timeToPosition(range.start);
       var end = this._timeToPosition(range.end);
     } else {
-      var range = this._getSimplifiedBarRange(this._hoveredNode, 0);
+      var range = this._getSimplifiedBarRange(this.request(), 0);
       var start = range.start;
       var end = range.end;
     }
@@ -124,18 +127,20 @@
   _showPopover(anchor, popover) {
     if (!this._hoveredNode)
       return;
-    var content =
-        Network.RequestTimingView.createTimingTable(this._hoveredNode.request(), this._calculator.minimumBoundary());
+    var request = this._hoveredNode.request();
+    if (!request)
+      return;
+    var content = Network.RequestTimingView.createTimingTable(request, this._calculator.minimumBoundary());
     popover.showForAnchor(content, anchor);
   }
 
   /**
-   * @param {?Network.NetworkDataGridNode} node
+   * @param {?Network.NetworkNode} node
    * @param {boolean} highlightInitiatorChain
    */
   setHoveredNode(node, highlightInitiatorChain) {
     this._hoveredNode = node;
-    this._initiatorGraph = (highlightInitiatorChain && node) ? node.request().initiatorGraph() : null;
+    this._initiatorGraph = (highlightInitiatorChain && node && node.request()) ? node.request().initiatorGraph() : null;
     this.update();
   }
 
@@ -171,7 +176,7 @@
   /**
    * @param {number} x
    * @param {number} y
-   * @return {?Network.NetworkDataGridNode}
+   * @return {?Network.NetworkNode}
    */
   getNodeFromPoint(x, y) {
     return this._nodes[Math.floor((this._scrollTop + y - this._headerHeight) / this._rowHeight)];
@@ -186,7 +191,7 @@
   /**
    * @param {number=} scrollTop
    * @param {!Map<string, !Array<number>>=} eventDividers
-   * @param {!Array<!Network.NetworkDataGridNode>=} nodes
+   * @param {!Array<!Network.NetworkNode>=} nodes
    */
   update(scrollTop, eventDividers, nodes) {
     if (scrollTop !== undefined)
@@ -353,11 +358,11 @@
   }
 
   /**
-   * @param {!Network.NetworkDataGridNode} node
+   * @param {!SDK.NetworkRequest} request
    * @return {string}
    */
-  _borderColorForResourceType(node) {
-    var resourceType = node.request().resourceType();
+  _borderColorForResourceType(request) {
+    var resourceType = request.resourceType();
     if (this._borderColorsForResourceTypeCache.has(resourceType))
       return this._borderColorsForResourceTypeCache.get(resourceType);
     var colorsForResourceType = Network.NetworkWaterfallColumn._colorsForResourceType;
@@ -373,11 +378,10 @@
 
   /**
    * @param {!CanvasRenderingContext2D} context
-   * @param {!Network.NetworkDataGridNode} node
+   * @param {!SDK.NetworkRequest} request
    * @return {string|!CanvasGradient}
    */
-  _colorForResourceType(context, node) {
-    var request = node.request();
+  _colorForResourceType(context, request) {
     var colorsForResourceType = Network.NetworkWaterfallColumn._colorsForResourceType;
     var resourceType = request.resourceType();
     var color = colorsForResourceType[resourceType] || colorsForResourceType.Other;
@@ -398,13 +402,13 @@
   }
 
   /**
-   * @param {!Network.NetworkDataGridNode} node
+   * @param {!SDK.NetworkRequest} request
    * @param {number} borderOffset
    * @return {!{start: number, mid: number, end: number}}
    */
-  _getSimplifiedBarRange(node, borderOffset) {
+  _getSimplifiedBarRange(request, borderOffset) {
     var drawWidth = this._offsetWidth - this._leftPadding;
-    var percentages = this._calculator.computeBarGraphPercentages(node.request());
+    var percentages = this._calculator.computeBarGraphPercentages(request);
     return {
       start: this._leftPadding + Math.floor((percentages.start / 100) * drawWidth) + borderOffset,
       mid: this._leftPadding + Math.floor((percentages.middle / 100) * drawWidth) + borderOffset,
@@ -414,21 +418,25 @@
 
   /**
    * @param {!CanvasRenderingContext2D} context
-   * @param {!Network.NetworkDataGridNode} node
+   * @param {!Network.NetworkNode} node
    * @param {number} y
    */
   _drawSimplifiedBars(context, node, y) {
+    // TODO(allada) This should draw bars for groupped requests.
+    var request = node.request();
+    if (!request)
+      return;
     const borderWidth = 1;
     var borderOffset = borderWidth % 2 === 0 ? 0 : 0.5;
 
     context.save();
-    var ranges = this._getSimplifiedBarRange(node, borderOffset);
+    var ranges = this._getSimplifiedBarRange(request, borderOffset);
     var height = this._getBarHeight();
     y += Math.floor(this._rowHeight / 2 - height / 2 + borderWidth) - borderWidth / 2;
 
     context.translate(0, y);
-    context.fillStyle = this._colorForResourceType(context, node);
-    context.strokeStyle = this._borderColorForResourceType(node);
+    context.fillStyle = this._colorForResourceType(context, request);
+    context.strokeStyle = this._borderColorForResourceType(request);
     context.lineWidth = borderWidth;
 
     context.beginPath();
@@ -447,13 +455,13 @@
     /** @type {?{left: string, right: string, tooltip: (string|undefined)}} */
     var labels = null;
     if (node === this._hoveredNode) {
-      labels = this._calculator.computeBarGraphLabels(node.request());
+      labels = this._calculator.computeBarGraphLabels(request);
       this._drawSimplifiedBarDetails(
           context, labels.left, labels.right, ranges.start, ranges.mid, ranges.mid + barWidth + borderOffset);
     }
 
     if (!this._calculator.startAtZero) {
-      var queueingRange = Network.RequestTimingView.calculateRequestTimeRanges(node.request(), 0)
+      var queueingRange = Network.RequestTimingView.calculateRequestTimeRanges(request, 0)
                               .find(data => data.name === Network.RequestTimeRangeNames.Total);
       var leftLabelWidth = labels ? context.measureText(labels.left).width : 0;
       var leftTextPlacedInBar = leftLabelWidth < ranges.mid - ranges.start;
@@ -529,12 +537,16 @@
 
   /**
    * @param {!CanvasRenderingContext2D} context
-   * @param {!Network.NetworkDataGridNode} node
+   * @param {!Network.NetworkNode} node
    * @param {number} y
    */
   _drawTimingBars(context, node, y) {
+    // TODO(allada) This should draw bars for groupped requests.
+    var request = node.request();
+    if (!request)
+      return;
     context.save();
-    var ranges = Network.RequestTimingView.calculateRequestTimeRanges(node.request(), 0);
+    var ranges = Network.RequestTimingView.calculateRequestTimeRanges(request, 0);
     for (var range of ranges) {
       if (range.name === Network.RequestTimeRangeNames.Total || range.name === Network.RequestTimeRangeNames.Sending ||
           range.end - range.start === 0)
@@ -567,7 +579,7 @@
 
   /**
    * @param {!CanvasRenderingContext2D} context
-   * @param {!Network.NetworkDataGridNode} node
+   * @param {!Network.NetworkNode} node
    * @param {number} rowNumber
    * @param {number} y
    */
@@ -594,7 +606,7 @@
       var request = node.request();
       if (this._hoveredNode === node)
         return this._rowHoverColor;
-      if (this._initiatorGraph) {
+      if (request && this._initiatorGraph) {
         if (this._initiatorGraph.initiators.has(request))
           return this._parentInitiatorColor;
         if (this._initiatorGraph.initiated.has(request))
diff --git a/third_party/WebKit/Source/platform/weborigin/KURL.cpp b/third_party/WebKit/Source/platform/weborigin/KURL.cpp
index 2c86b43..2f4894f 100644
--- a/third_party/WebKit/Source/platform/weborigin/KURL.cpp
+++ b/third_party/WebKit/Source/platform/weborigin/KURL.cpp
@@ -34,7 +34,6 @@
 #include "wtf/StdLibExtras.h"
 #include "wtf/text/CString.h"
 #include "wtf/text/StringHash.h"
-#include "wtf/text/StringStatics.h"
 #include "wtf/text/StringUTF8Adaptor.h"
 #include "wtf/text/TextEncoding.h"
 #include <algorithm>
@@ -49,7 +48,6 @@
 
 static void assertProtocolIsGood(const char* protocol) {
 #if ENABLE(ASSERT)
-  DCHECK_NE(protocol, "");
   const char* p = protocol;
   while (*p) {
     ASSERT(*p > ' ' && *p < 0x7F && !(*p >= 'A' && *p <= 'Z'));
@@ -243,7 +241,7 @@
       m_protocolIsInHTTPFamily(false),
       m_parsed(parsed),
       m_string(canonicalString) {
-  initProtocolMetadata();
+  initProtocolIsInHTTPFamily();
   initInnerURL();
 }
 
@@ -255,7 +253,6 @@
 KURL::KURL(const KURL& other)
     : m_isValid(other.m_isValid),
       m_protocolIsInHTTPFamily(other.m_protocolIsInHTTPFamily),
-      m_protocol(other.m_protocol),
       m_parsed(other.m_parsed),
       m_string(other.m_string) {
   if (other.m_innerURL.get())
@@ -267,7 +264,6 @@
 KURL& KURL::operator=(const KURL& other) {
   m_isValid = other.m_isValid;
   m_protocolIsInHTTPFamily = other.m_protocolIsInHTTPFamily;
-  m_protocol = other.m_protocol;
   m_parsed = other.m_parsed;
   m_string = other.m_string;
   if (other.m_innerURL)
@@ -281,7 +277,6 @@
   KURL result;
   result.m_isValid = m_isValid;
   result.m_protocolIsInHTTPFamily = m_protocolIsInHTTPFamily;
-  result.m_protocol = m_protocol.isolatedCopy();
   result.m_parsed = m_parsed;
   result.m_string = m_string.isolatedCopy();
   if (m_innerURL)
@@ -317,7 +312,7 @@
 
 String KURL::lastPathComponent() const {
   if (!m_isValid)
-    return stringViewForInvalidComponent().toString();
+    return stringForInvalidComponent();
   ASSERT(!m_string.isNull());
 
   // When the output ends in a slash, WebCore has different expectations than
@@ -341,8 +336,7 @@
 }
 
 String KURL::protocol() const {
-  DCHECK_EQ(componentString(m_parsed.scheme), m_protocol);
-  return m_protocol;
+  return componentString(m_parsed.scheme);
 }
 
 String KURL::host() const {
@@ -371,9 +365,6 @@
   return static_cast<unsigned short>(port);
 }
 
-// TODO(csharrison): Migrate pass() and user() to return a StringView. Most
-// consumers just need to know if the string is empty.
-
 String KURL::pass() const {
   // Bug: https://bugs.webkit.org/show_bug.cgi?id=21015 this function returns
   // a null string when the password is empty, which we duplicate here.
@@ -776,8 +767,9 @@
     m_string = AtomicString::fromUTF8(output.data(), output.length());
   }
 
-  initProtocolMetadata();
+  initProtocolIsInHTTPFamily();
   initInnerURL();
+  DCHECK_EQ(protocol(), protocol().lower());
 }
 
 void KURL::initInnerURL() {
@@ -794,26 +786,50 @@
     m_innerURL.reset();
 }
 
-void KURL::initProtocolMetadata() {
+template <typename CHAR>
+bool internalProtocolIs(const url::Component& scheme,
+                        const CHAR* spec,
+                        const char* protocol) {
+  const CHAR* begin = spec + scheme.begin;
+  const CHAR* end = begin + scheme.len;
+
+  while (begin != end && *protocol) {
+    ASSERT(toASCIILower(*protocol) == *protocol);
+    if (toASCIILower(*begin++) != *protocol++)
+      return false;
+  }
+
+  // Both strings are equal (ignoring case) if and only if all of the characters
+  // were equal, and the end of both has been reached.
+  return begin == end && !*protocol;
+}
+
+template <typename CHAR>
+bool checkIfProtocolIsInHTTPFamily(const url::Component& scheme,
+                                   const CHAR* spec) {
+  if (scheme.len == 4)
+    return internalProtocolIs(scheme, spec, "http");
+  if (scheme.len == 5)
+    return internalProtocolIs(scheme, spec, "https");
+  if (scheme.len == 7)
+    return internalProtocolIs(scheme, spec, "http-so");
+  if (scheme.len == 8)
+    return internalProtocolIs(scheme, spec, "https-so");
+  return false;
+}
+
+void KURL::initProtocolIsInHTTPFamily() {
   if (!m_isValid) {
     m_protocolIsInHTTPFamily = false;
-    m_protocol = componentString(m_parsed.scheme);
     return;
   }
 
-  DCHECK(!m_string.isNull());
-  StringView protocol = componentStringView(m_parsed.scheme);
-  m_protocolIsInHTTPFamily = true;
-  if (protocol == WTF::httpsAtom) {
-    m_protocol = WTF::httpsAtom;
-  } else if (protocol == WTF::httpAtom) {
-    m_protocol = WTF::httpAtom;
-  } else {
-    m_protocol = AtomicString(protocol.toString());
-    m_protocolIsInHTTPFamily =
-        m_protocol == "http-so" || m_protocol == "https-so";
-  }
-  DCHECK_EQ(m_protocol, m_protocol.lower());
+  ASSERT(!m_string.isNull());
+  m_protocolIsInHTTPFamily =
+      m_string.is8Bit() ? checkIfProtocolIsInHTTPFamily(m_parsed.scheme,
+                                                        m_string.characters8())
+                        : checkIfProtocolIsInHTTPFamily(
+                              m_parsed.scheme, m_string.characters16());
 }
 
 bool KURL::protocolIs(const char* protocol) const {
@@ -824,16 +840,26 @@
   // instead.
   // FIXME: Chromium code needs to be fixed for this assert to be enabled.
   // ASSERT(strcmp(protocol, "javascript"));
-  return m_protocol == protocol;
+
+  if (m_string.isNull() || m_parsed.scheme.len <= 0)
+    return *protocol == '\0';
+
+  return m_string.is8Bit()
+             ? internalProtocolIs(m_parsed.scheme, m_string.characters8(),
+                                  protocol)
+             : internalProtocolIs(m_parsed.scheme, m_string.characters16(),
+                                  protocol);
 }
 
-StringView KURL::stringViewForInvalidComponent() const {
-  return m_string.isNull() ? StringView() : StringView("", 0);
+String KURL::stringForInvalidComponent() const {
+  if (m_string.isNull())
+    return String();
+  return emptyString();
 }
 
-StringView KURL::componentStringView(const url::Component& component) const {
+String KURL::componentString(const url::Component& component) const {
   if (!m_isValid || component.len <= 0)
-    return stringViewForInvalidComponent();
+    return stringForInvalidComponent();
   // begin and len are in terms of bytes which do not match
   // if string() is UTF-16 and input contains non-ASCII characters.
   // However, the only part in urlString that can contain non-ASCII
@@ -842,14 +868,7 @@
   // byte) will be longer than what's needed by 'mid'. However, mid
   // truncates len to avoid go past the end of a string so that we can
   // get away without doing anything here.
-
-  int maxLength = getString().length() - component.begin;
-  return StringView(getString(), component.begin,
-                    component.len > maxLength ? maxLength : component.len);
-}
-
-String KURL::componentString(const url::Component& component) const {
-  return componentStringView(component).toString();
+  return getString().substring(component.begin, component.len);
 }
 
 template <typename CHAR>
@@ -863,7 +882,6 @@
 
   m_parsed = newParsed;
   m_string = AtomicString::fromUTF8(output.data(), output.length());
-  initProtocolMetadata();
 }
 
 bool KURL::isSafeToSendToAnotherThread() const {
diff --git a/third_party/WebKit/Source/platform/weborigin/KURL.h b/third_party/WebKit/Source/platform/weborigin/KURL.h
index 91c7851..e441f9e5 100644
--- a/third_party/WebKit/Source/platform/weborigin/KURL.h
+++ b/third_party/WebKit/Source/platform/weborigin/KURL.h
@@ -196,24 +196,17 @@
             const String& relative,
             const WTF::TextEncoding* queryEncoding);
 
-  StringView componentStringView(const url::Component&) const;
   String componentString(const url::Component&) const;
-  StringView stringViewForInvalidComponent() const;
+  String stringForInvalidComponent() const;
 
   template <typename CHAR>
   void replaceComponents(const url::Replacements<CHAR>&);
 
   void initInnerURL();
-  void initProtocolMetadata();
+  void initProtocolIsInHTTPFamily();
 
   bool m_isValid;
   bool m_protocolIsInHTTPFamily;
-
-  // Keep a separate string for the protocol to avoid copious copies for
-  // protocol(). Normally this will be Atomic, except when constructed via
-  // KURL::copy(), which is deep.
-  String m_protocol;
-
   url::Parsed m_parsed;
   String m_string;
   std::unique_ptr<KURL> m_innerURL;
diff --git a/third_party/WebKit/Source/platform/weborigin/KURLTest.cpp b/third_party/WebKit/Source/platform/weborigin/KURLTest.cpp
index 8746f2af..13cdda7e 100644
--- a/third_party/WebKit/Source/platform/weborigin/KURLTest.cpp
+++ b/third_party/WebKit/Source/platform/weborigin/KURLTest.cpp
@@ -367,46 +367,46 @@
   url::AddStandardScheme("http-so", url::SCHEME_WITH_PORT);
   url::AddStandardScheme("https-so", url::SCHEME_WITH_PORT);
 
-  KURL kurl(ParsedURLString, "foo://www.google.com/");
+  KURL kurl;
   EXPECT_TRUE(kurl.setProtocol("http"));
   EXPECT_TRUE(kurl.protocolIs("http"));
-  EXPECT_TRUE(kurl.protocolIsInHTTPFamily());
-  EXPECT_TRUE(kurl.isValid());
+  EXPECT_FALSE(kurl.isValid());
 
   EXPECT_TRUE(kurl.setProtocol("http-so"));
   EXPECT_TRUE(kurl.protocolIs("http-so"));
-  EXPECT_TRUE(kurl.isValid());
+  EXPECT_FALSE(kurl.isValid());
 
   EXPECT_TRUE(kurl.setProtocol("https"));
   EXPECT_TRUE(kurl.protocolIs("https"));
-  EXPECT_TRUE(kurl.isValid());
+  EXPECT_FALSE(kurl.isValid());
 
   EXPECT_TRUE(kurl.setProtocol("https-so"));
   EXPECT_TRUE(kurl.protocolIs("https-so"));
-  EXPECT_TRUE(kurl.isValid());
+  EXPECT_FALSE(kurl.isValid());
 
   EXPECT_TRUE(kurl.setProtocol("ftp"));
   EXPECT_TRUE(kurl.protocolIs("ftp"));
-  EXPECT_TRUE(kurl.isValid());
+  EXPECT_FALSE(kurl.isValid());
 
   kurl = KURL(KURL(), "http://");
-  EXPECT_FALSE(kurl.protocolIs("http"));
-
-  kurl = KURL(KURL(), "http://wide#ιΈ‘");
   EXPECT_TRUE(kurl.protocolIs("http"));
-  EXPECT_EQ(kurl.protocol(), "http");
+  EXPECT_FALSE(kurl.isValid());
 
-  kurl = KURL(KURL(), "http-so://foo");
+  kurl = KURL(KURL(), "http-so://");
   EXPECT_TRUE(kurl.protocolIs("http-so"));
+  EXPECT_FALSE(kurl.isValid());
 
-  kurl = KURL(KURL(), "https://foo");
+  kurl = KURL(KURL(), "https://");
   EXPECT_TRUE(kurl.protocolIs("https"));
+  EXPECT_FALSE(kurl.isValid());
 
-  kurl = KURL(KURL(), "https-so://foo");
+  kurl = KURL(KURL(), "https-so://");
   EXPECT_TRUE(kurl.protocolIs("https-so"));
+  EXPECT_FALSE(kurl.isValid());
 
-  kurl = KURL(KURL(), "ftp://foo");
+  kurl = KURL(KURL(), "ftp://");
   EXPECT_TRUE(kurl.protocolIs("ftp"));
+  EXPECT_FALSE(kurl.isValid());
 
   kurl = KURL(KURL(), "http://host/");
   EXPECT_TRUE(kurl.isValid());
@@ -699,6 +699,7 @@
 
   KURL invalidUTF8(ParsedURLString, "http://a@9%aa%:");
   EXPECT_FALSE(invalidUTF8.protocolIs("http"));
+  EXPECT_TRUE(invalidUTF8.protocolIs(""));
 
   KURL capital(KURL(), "HTTP://www.example.text");
   EXPECT_TRUE(capital.protocolIs("http"));
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
index 606780e9..2f43443 100644
--- a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
+++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
@@ -2291,6 +2291,10 @@
   m_client->saveImageFromDataURL(url);
 }
 
+void WebLocalFrameImpl::setEngagementLevel(mojom::EngagementLevel level) {
+  frame()->document()->setEngagementLevel(level);
+}
+
 WebSandboxFlags WebLocalFrameImpl::effectiveSandboxFlags() const {
   if (!frame())
     return WebSandboxFlags::None;
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.h b/third_party/WebKit/Source/web/WebLocalFrameImpl.h
index 8cdfda6c..cd22c63 100644
--- a/third_party/WebKit/Source/web/WebLocalFrameImpl.h
+++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.h
@@ -290,6 +290,7 @@
   WebFrameWidgetBase* frameWidget() const override;
   void copyImageAt(const WebPoint&) override;
   void saveImageAt(const WebPoint&) override;
+  void setEngagementLevel(mojom::EngagementLevel) override;
   void clearActiveFindMatch() override;
   void usageCountChromeLoadTimes(const WebString& metric) override;
   base::SingleThreadTaskRunner* timerTaskRunner() override;
diff --git a/third_party/WebKit/Source/wtf/text/AtomicString.h b/third_party/WebKit/Source/wtf/text/AtomicString.h
index ea3ee3c4..7d8fb35 100644
--- a/third_party/WebKit/Source/wtf/text/AtomicString.h
+++ b/third_party/WebKit/Source/wtf/text/AtomicString.h
@@ -291,8 +291,6 @@
 WTF_EXPORT extern const AtomicString& xmlAtom;
 WTF_EXPORT extern const AtomicString& xmlnsAtom;
 WTF_EXPORT extern const AtomicString& xlinkAtom;
-WTF_EXPORT extern const AtomicString& httpAtom;
-WTF_EXPORT extern const AtomicString& httpsAtom;
 
 // AtomicStringHash is the default hash for AtomicString
 template <typename T>
diff --git a/third_party/WebKit/Source/wtf/text/StringStatics.cpp b/third_party/WebKit/Source/wtf/text/StringStatics.cpp
index 2bb0dbe..22dd69d 100644
--- a/third_party/WebKit/Source/wtf/text/StringStatics.cpp
+++ b/third_party/WebKit/Source/wtf/text/StringStatics.cpp
@@ -54,8 +54,6 @@
 WTF_EXPORT DEFINE_GLOBAL(AtomicString, xmlAtom);
 WTF_EXPORT DEFINE_GLOBAL(AtomicString, xmlnsAtom);
 WTF_EXPORT DEFINE_GLOBAL(AtomicString, xlinkAtom);
-WTF_EXPORT DEFINE_GLOBAL(AtomicString, httpAtom);
-WTF_EXPORT DEFINE_GLOBAL(AtomicString, httpsAtom);
 
 // This is not an AtomicString because it is unlikely to be used as an
 // event/element/attribute name, so it shouldn't pollute the AtomicString hash
@@ -95,8 +93,6 @@
   new (NotNull, (void*)&xmlnsAtom) AtomicString(addStaticASCIILiteral("xmlns"));
   new (NotNull, (void*)&xlinkAtom) AtomicString(addStaticASCIILiteral("xlink"));
   new (NotNull, (void*)&xmlnsWithColon) String("xmlns:");
-  new (NotNull, (void*)&httpAtom) AtomicString(addStaticASCIILiteral("http"));
-  new (NotNull, (void*)&httpsAtom) AtomicString(addStaticASCIILiteral("https"));
 }
 
 }  // namespace WTF
diff --git a/third_party/WebKit/public/BUILD.gn b/third_party/WebKit/public/BUILD.gn
index 7fb92262e..458e00b5 100644
--- a/third_party/WebKit/public/BUILD.gn
+++ b/third_party/WebKit/public/BUILD.gn
@@ -665,6 +665,7 @@
     "platform/modules/shapedetection/facedetection_provider.mojom",
     "platform/modules/websockets/websocket.mojom",
     "platform/referrer.mojom",
+    "platform/site_engagement.mojom",
     "web/window_features.mojom",
   ]
   public_deps = [
diff --git a/third_party/WebKit/public/platform/site_engagement.mojom b/third_party/WebKit/public/platform/site_engagement.mojom
new file mode 100644
index 0000000..f35f0ce
--- /dev/null
+++ b/third_party/WebKit/public/platform/site_engagement.mojom
@@ -0,0 +1,21 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module blink.mojom;
+
+import "url/mojo/origin.mojom";
+
+enum EngagementLevel {
+  NONE,
+  MINIMAL,
+  LOW,
+  MEDIUM,
+  HIGH,
+  MAX,
+};
+
+interface EngagementClient {
+  // The browser tells the renderer the engagement level of the provided origin.
+  SetEngagementLevel(url.mojom.Origin origin, EngagementLevel level);
+};
diff --git a/third_party/WebKit/public/web/WebLocalFrame.h b/third_party/WebKit/public/web/WebLocalFrame.h
index a6dde3392..d0ea1220 100644
--- a/third_party/WebKit/public/web/WebLocalFrame.h
+++ b/third_party/WebKit/public/web/WebLocalFrame.h
@@ -11,6 +11,7 @@
 #include "WebHistoryItem.h"
 #include "public/platform/WebCachePolicy.h"
 #include "public/platform/WebURLError.h"
+#include "public/platform/site_engagement.mojom-shared.h"
 
 namespace base {
 class SingleThreadTaskRunner;
@@ -437,6 +438,11 @@
   // coordinates.
   virtual void saveImageAt(const WebPoint&) = 0;
 
+  // Site engagement --------------------------------------------------------
+
+  // Sets the site engagement level for this frame's document.
+  virtual void setEngagementLevel(mojom::EngagementLevel) = 0;
+
   // TEMP: Usage count for chrome.loadtimes deprecation.
   // This will be removed following the deprecation.
   virtual void usageCountChromeLoadTimes(const WebString& metric) = 0;
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 3cd7f59..ff4e704 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -8895,8 +8895,8 @@
   <owner>bengr@chromium.org</owner>
   <owner>megjablon@chromium.org</owner>
   <summary>
-    Samples of user interactions with the Lo-Fi snackbar and context menu
-    option. These samples include:
+    User interactions with the Lo-Fi snackbar and context menu option. These
+    include:
 
     Displays and clicks on the &quot;Load images&quot; snackbar. Displays and
     clicks on the &quot;Load image&quot; and &quot;Load images&quot;context menu
@@ -49837,8 +49837,7 @@
   <owner>bengr@chromium.org</owner>
   <owner>megjablon@chromium.org</owner>
   <summary>
-    Samples of user interactions with the Lo-Fi context menu options. These
-    samples include:
+    User interactions with the Lo-Fi context menu options. These include:
 
     Displays and clicks on the &quot;Load image&quot; and &quot;Load
     images&quot; context menu options. Count of pages where the user has clicked
@@ -49895,8 +49894,8 @@
   <owner>bengr@chromium.org</owner>
   <owner>megjablon@chromium.org</owner>
   <summary>
-    Samples of user interactions with the previews LitePage &quot;Saved
-    data&quot; infobar. These samples include:
+    User interactions with the previews LitePage &quot;Saved data&quot; infobar.
+    These include:
 
     Displays of the infobar and clicks on the &quot;Load original&quot; link.
     Whether the infobar was dismissed by navigation or the user clicking on
@@ -49908,8 +49907,8 @@
   <owner>bengr@chromium.org</owner>
   <owner>megjablon@chromium.org</owner>
   <summary>
-    Samples of user interactions with the previews Lo-Fi &quot;Saved data&quot;
-    infobar. These samples include:
+    User interactions with the previews Lo-Fi &quot;Saved data&quot; infobar.
+    These include:
 
     Displays of the infobar and clicks on the &quot;Load original&quot; link.
     Whether the infobar was dismissed by navigation or the user clicking on
@@ -49921,8 +49920,8 @@
   <owner>bengr@chromium.org</owner>
   <owner>megjablon@chromium.org</owner>
   <summary>
-    Samples of user interactions with the previews Offline &quot;Faster page
-    loaded&quot; infobar. These samples include:
+    User interactions with the previews Offline &quot;Faster page loaded&quot;
+    infobar. These include:
 
     Displays of the infobar and clicks on the &quot;Load original&quot; link.
     Whether the infobar was dismissed by navigation or the user clicking on
diff --git a/ui/aura/mus/DEPS b/ui/aura/mus/DEPS
index 1993db3..d5c7f53a 100644
--- a/ui/aura/mus/DEPS
+++ b/ui/aura/mus/DEPS
@@ -10,7 +10,6 @@
   "+mojo/public/cpp/system/buffer.h",
   "+mojo/public/cpp/system/platform_handle.h",
   "+services/ui/common/accelerator_util.h",
-  "+services/ui/public/cpp/context_provider.h",
   "+services/ui/public/cpp/gpu",
   "+services/ui/public/cpp/property_type_converters.h",
   "+services/ui/public/cpp/raster_thread_helper.h",
diff --git a/ui/aura/mus/mus_context_factory.cc b/ui/aura/mus/mus_context_factory.cc
index da0b1263..61dd4d83 100644
--- a/ui/aura/mus/mus_context_factory.cc
+++ b/ui/aura/mus/mus_context_factory.cc
@@ -5,7 +5,6 @@
 #include "ui/aura/mus/mus_context_factory.h"
 
 #include "base/memory/ptr_util.h"
-#include "services/ui/public/cpp/context_provider.h"
 #include "services/ui/public/cpp/gpu/gpu.h"
 #include "ui/aura/mus/window_port_mus.h"
 #include "ui/aura/window_tree_host.h"
@@ -13,24 +12,34 @@
 
 namespace aura {
 
-MusContextFactory::MusContextFactory(ui::Gpu* gpu) : gpu_(gpu) {}
+MusContextFactory::MusContextFactory(ui::Gpu* gpu)
+    : gpu_(gpu), weak_ptr_factory_(this) {}
 
 MusContextFactory::~MusContextFactory() {}
 
-void MusContextFactory::CreateCompositorFrameSink(
-    base::WeakPtr<ui::Compositor> compositor) {
+void MusContextFactory::OnEstablishedGpuChannel(
+    base::WeakPtr<ui::Compositor> compositor,
+    scoped_refptr<gpu::GpuChannelHost> gpu_channel) {
+  if (!compositor)
+    return;
   WindowTreeHost* host =
       WindowTreeHost::GetForAcceleratedWidget(compositor->widget());
   WindowPortMus* window_port = WindowPortMus::Get(host->window());
   DCHECK(window_port);
   auto compositor_frame_sink = window_port->RequestCompositorFrameSink(
       ui::mojom::CompositorFrameSinkType::DEFAULT,
-      make_scoped_refptr(
-          new ui::ContextProvider(gpu_->EstablishGpuChannelSync())),
+      gpu_->CreateContextProvider(std::move(gpu_channel)),
       gpu_->gpu_memory_buffer_manager());
   compositor->SetCompositorFrameSink(std::move(compositor_frame_sink));
 }
 
+void MusContextFactory::CreateCompositorFrameSink(
+    base::WeakPtr<ui::Compositor> compositor) {
+  gpu_->EstablishGpuChannel(
+      base::Bind(&MusContextFactory::OnEstablishedGpuChannel,
+                 weak_ptr_factory_.GetWeakPtr(), compositor));
+}
+
 scoped_refptr<cc::ContextProvider>
 MusContextFactory::SharedMainThreadContextProvider() {
   // NOTIMPLEMENTED();
diff --git a/ui/aura/mus/mus_context_factory.h b/ui/aura/mus/mus_context_factory.h
index d71a51a..babca479 100644
--- a/ui/aura/mus/mus_context_factory.h
+++ b/ui/aura/mus/mus_context_factory.h
@@ -8,12 +8,18 @@
 #include <stdint.h>
 
 #include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
 #include "cc/surfaces/surface_manager.h"
 #include "services/ui/public/cpp/raster_thread_helper.h"
 #include "services/ui/public/interfaces/window_tree.mojom.h"
 #include "ui/aura/aura_export.h"
 #include "ui/compositor/compositor.h"
 
+namespace gpu {
+class GpuChannelHost;
+}
+
 namespace ui {
 class Gpu;
 }
@@ -27,6 +33,10 @@
   ~MusContextFactory() override;
 
  private:
+  // Callback function for Gpu::EstablishGpuChannel().
+  void OnEstablishedGpuChannel(base::WeakPtr<ui::Compositor> compositor,
+                               scoped_refptr<gpu::GpuChannelHost> gpu_channel);
+
   // ContextFactory:
   void CreateCompositorFrameSink(
       base::WeakPtr<ui::Compositor> compositor) override;
@@ -42,6 +52,7 @@
 
   ui::RasterThreadHelper raster_thread_helper_;
   ui::Gpu* gpu_;
+  base::WeakPtrFactory<MusContextFactory> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(MusContextFactory);
 };
diff --git a/ui/file_manager/file_manager/foreground/js/import_controller.js b/ui/file_manager/file_manager/foreground/js/import_controller.js
index 0d129a01..86595729 100644
--- a/ui/file_manager/file_manager/foreground/js/import_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/import_controller.js
@@ -1211,7 +1211,7 @@
 importer.RuntimeControllerEnvironment.prototype.addSelectionChangedListener =
     function(listener) {
   this.selectionHandler_.addEventListener(
-      FileSelectionHandler.EventType.CHANGE,
+      FileSelectionHandler.EventType.CHANGE_THROTTLED,
       listener);
 };
 
diff --git a/ui/views/mus/surface_context_factory.cc b/ui/views/mus/surface_context_factory.cc
index 4b55ac1..9a881ee8 100644
--- a/ui/views/mus/surface_context_factory.cc
+++ b/ui/views/mus/surface_context_factory.cc
@@ -7,7 +7,6 @@
 #include "base/memory/ptr_util.h"
 #include "cc/resources/shared_bitmap_manager.h"
 #include "cc/surfaces/surface_id_allocator.h"
-#include "services/ui/public/cpp/context_provider.h"
 #include "services/ui/public/cpp/gpu/gpu.h"
 #include "services/ui/public/cpp/window.h"
 #include "services/ui/public/cpp/window_compositor_frame_sink.h"
@@ -28,8 +27,8 @@
   ui::mojom::CompositorFrameSinkType compositor_frame_sink_type =
       native_widget->compositor_frame_sink_type();
   auto compositor_frame_sink = window->RequestCompositorFrameSink(
-      compositor_frame_sink_type, make_scoped_refptr(new ui::ContextProvider(
-                                      gpu_->EstablishGpuChannelSync())),
+      compositor_frame_sink_type,
+      gpu_->CreateContextProvider(gpu_->EstablishGpuChannelSync()),
       gpu_->gpu_memory_buffer_manager());
   compositor->SetCompositorFrameSink(std::move(compositor_frame_sink));
 }
diff --git a/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html b/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html
index 748e697..bc0370e8 100644
--- a/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html
+++ b/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html
@@ -17,7 +17,7 @@
 
       h1 {
         -webkit-margin-start: 6px;
-        -webkit-padding-end: 2px;
+        -webkit-padding-end: 12px;
         flex: 1;
         font-size: 123%;
         font-weight: 400;
@@ -27,14 +27,17 @@
       }
 
       #leftContent {
-        -webkit-padding-start: 18px;
-        align-items: center;
-        box-sizing: border-box;
-        display: flex;
-        position: absolute;
+        /* margin-start here must match margin-end on #rightContent. */
+        -webkit-margin-start: 12px;
         transition: opacity 100ms;
       }
 
+      #leftSpacer {
+        -webkit-margin-start: 6px;
+        align-items: center;
+        display: flex;
+      }
+
       #menuButton {
         height: 32px;
         margin-bottom: 6px;
@@ -47,30 +50,10 @@
       #centeredContent {
         display: flex;
         flex: 1 1 0;
-        justify-content: center;
       }
 
-      :host([narrow_]) #centeredContent {
-        -webkit-padding-end: var(--cr-toolbar-field-end-padding, 12px);
-      }
-
-      :host(:not([narrow_])) h1 {
-        @apply(--cr-toolbar-header-wide);
-      }
-
-      :host(:not([narrow_])) #leftContent {
-        /* The amount of space left of the search field:
-           (width of window - width of search field) / 2. */
-        max-width: calc((100% - var(--cr-toolbar-field-width)) / 2);
-        @apply(--cr-toolbar-left-content-wide);
-      }
-
-      :host(:not([narrow_])) #centeredContent {
-        -webkit-margin-start: var(--cr-toolbar-field-margin, 0);
-      }
-
-      :host(:not([narrow_])) #rightContent {
-        @apply(--cr-toolbar-right-content-wide);
+      #rightContent {
+        -webkit-margin-end: 12px;
       }
 
       :host([narrow_]) #centeredContent {
@@ -78,9 +61,19 @@
       }
 
       :host([narrow_][showing-search_]) #leftContent {
+        position: absolute;
         opacity: 0;
       }
 
+      :host(:not([narrow_])) #leftContent {
+        flex: 1 1 var(--cr-toolbar-field-margin, 0);
+      }
+
+      :host(:not([narrow_])) #rightContent {
+        flex: 1 1 0;
+        text-align: end;
+      }
+
       #menuPromo {
         -webkit-padding-end: 12px;
         -webkit-padding-start: 8px;
@@ -103,7 +96,7 @@
       #menuPromo::before {
         background: inherit;
         /* Up arrow. 105% in Y coordinates fixes glitch at 110/125% zoom. */
-        clip-path: polygon(0 105%, 100% 105%, 50% 0);  
+        clip-path: polygon(0 105%, 100% 105%, 50% 0);
         content: '';
         display: block;
         left: 10px;
@@ -131,21 +124,23 @@
       }
     </style>
     <div id="leftContent">
-      <!-- Note: showing #menuPromo relies on this dom-if being [restamp]. -->
-      <template is="dom-if" if="[[showMenu]]" restamp>
-        <paper-icon-button id="menuButton" icon="cr:menu" on-tap="onMenuTap_"
-            title="[[titleIfNotShowMenuPromo_(menuLabel, showMenuPromo)]]"
-            aria-label$="[[menuLabel]]">
-        </paper-icon-button>
-        <template is="dom-if" if="[[showMenuPromo]]">
-          <div id="menuPromo" role="tooltip">
-            [[menuPromo]]
-            <button id="closePromo" on-tap="onClosePromoTap_"
-                aria-label$="[[closeMenuPromo]]">&#x2715;</button>
-          </paper-tooltip>
+      <div id="leftSpacer">
+        <!-- Note: showing #menuPromo relies on this dom-if being [restamp]. -->
+        <template is="dom-if" if="[[showMenu]]" restamp>
+          <paper-icon-button id="menuButton" icon="cr:menu" on-tap="onMenuTap_"
+              title="[[titleIfNotShowMenuPromo_(menuLabel, showMenuPromo)]]"
+              aria-label$="[[menuLabel]]">
+          </paper-icon-button>
+          <template is="dom-if" if="[[showMenuPromo]]">
+            <div id="menuPromo" role="tooltip">
+              [[menuPromo]]
+              <button id="closePromo" on-tap="onClosePromoTap_"
+                  aria-label$="[[closeMenuPromo]]">&#x2715;</button>
+            </paper-tooltip>
+          </template>
         </template>
-      </template>
-      <h1>[[pageName]]</h1>
+        <h1>[[pageName]]</h1>
+      </div>
     </div>
 
     <div id="centeredContent">