diff --git a/DEPS b/DEPS
index 06ec3327..0d74b94a 100644
--- a/DEPS
+++ b/DEPS
@@ -105,11 +105,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '8e9750d3c5bd2695d436659ceac83fac463ffaf3',
+  'skia_revision': 'f7828d0e447e259a87ac947f288c1c00148c656f',
   # 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': '7456952ea796b7ac82bcd7b7fa7da2b212f2eb76',
+  'v8_revision': '668b404640ee55f3f700640e7b6ff533e49c6af0',
   # 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.
@@ -117,7 +117,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '3f21fcb9bd26d469996d59d2f70c711799c227e3',
+  'angle_revision': '120b13f89467dcd72c0f4bf06f33a9419522f835',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -213,7 +213,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'spv_tools_revision': '03cbf33a695ec84d41a68333920864876fca18d9',
+  'spv_tools_revision': 'd3f88b08418962ee9926e3058b0de889d31e72a4',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -761,7 +761,7 @@
     Var('chromium_git') + '/chromium/deps/hunspell_dictionaries.git' + '@' + 'a9bac57ce6c9d390a52ebaad3259f5fdb871210e',
 
   'src/third_party/icu':
-    Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'c52a2a250d6c5f5cbdd015dff36af7c5d0ae1150',
+    Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'ccad4472126e35ccd1d19bea38b6675802d40472',
 
   'src/third_party/icu4j': {
       'packages': [
@@ -1106,7 +1106,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '6d2f3f4cb8bac1f7c4a945c73d07a33df74f22f9',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'b674cd103847da8639a58b60aba4df093314ae8c',
+    Var('webrtc_git') + '/src.git' + '@' + '040f87f934f5e1d2ecd12436b984479e3c2dac71',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1137,7 +1137,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@2a03a8b29373b834c3b70db32297d6019c5ab032',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@ccd9030b9fc319aa5f1040bd2573eceff72accc9',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/util/BoundaryInterfaceReflectionUtil.java b/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/util/BoundaryInterfaceReflectionUtil.java
index 44c90cba..dcf3b56 100644
--- a/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/util/BoundaryInterfaceReflectionUtil.java
+++ b/android_webview/support_library/boundary_interfaces/src/org/chromium/support_lib_boundary/util/BoundaryInterfaceReflectionUtil.java
@@ -16,12 +16,34 @@
  */
 public class BoundaryInterfaceReflectionUtil {
     /**
+     * Check if an object is an instance of {@code className}, resolving {@code className} in
+     * the object's own ClassLoader. This is useful when {@code obj} may have been created in a
+     * ClassLoader other than the current one (in which case {@code obj instanceof Foo} would fail
+     * but {@code instanceOfInOwnClassLoader(obj, "Foo")} may succeed).
+     */
+    public static boolean instanceOfInOwnClassLoader(Object obj, String className) {
+        try {
+            ClassLoader loader = obj.getClass().getClassLoader();
+            // We intentionally set initialize = false because instanceof shouldn't trigger
+            // static initialization.
+            Class<?> clazz = Class.forName(className, false, loader);
+            return clazz.isInstance(obj);
+        } catch (ClassNotFoundException e) {
+            // If className is not in the ClassLoader, then this cannot be an instance.
+            return false;
+        }
+    }
+
+    /**
      * Utility method for fetching a method from {@param delegateLoader}, with the same signature
      * (package + class + method name + parameters) as a given method defined in another
      * classloader.
      */
     public static Method dupeMethod(Method method, ClassLoader delegateLoader)
             throws ClassNotFoundException, NoSuchMethodException {
+        // We're converting one type to another. This is analogous to instantiating the type on the
+        // other side of the Boundary, so it makes sense to perform static initialization if it
+        // hasn't already happened (initialize = true).
         Class<?> declaringClass =
                 Class.forName(method.getDeclaringClass().getName(), true, delegateLoader);
         // We do not need to convert parameter types across ClassLoaders because we never pass
diff --git a/android_webview/support_library/callback/java/src/org/chromium/support_lib_callback_glue/SupportLibWebViewContentsClientAdapter.java b/android_webview/support_library/callback/java/src/org/chromium/support_lib_callback_glue/SupportLibWebViewContentsClientAdapter.java
index eac6f83..8024a39 100644
--- a/android_webview/support_library/callback/java/src/org/chromium/support_lib_callback_glue/SupportLibWebViewContentsClientAdapter.java
+++ b/android_webview/support_library/callback/java/src/org/chromium/support_lib_callback_glue/SupportLibWebViewContentsClientAdapter.java
@@ -52,7 +52,10 @@
 
     @Nullable
     private WebViewClientBoundaryInterface convertCompatClient(WebViewClient possiblyCompatClient) {
-        if (!clientIsCompat(possiblyCompatClient)) return null;
+        if (!BoundaryInterfaceReflectionUtil.instanceOfInOwnClassLoader(
+                    possiblyCompatClient, WEBVIEW_CLIENT_COMPAT_NAME)) {
+            return null;
+        }
 
         InvocationHandler handler =
                 BoundaryInterfaceReflectionUtil.createInvocationHandlerFor(possiblyCompatClient);
@@ -61,18 +64,6 @@
                 WebViewClientBoundaryInterface.class, handler);
     }
 
-    private boolean clientIsCompat(WebViewClient possiblyCompatClient) {
-        try {
-            Class compatClass = Class.forName(WEBVIEW_CLIENT_COMPAT_NAME, false,
-                    possiblyCompatClient.getClass().getClassLoader());
-            return compatClass.isInstance(possiblyCompatClient);
-        } catch (ClassNotFoundException e) {
-            // If WEBVIEW_CLIENT_COMPAT_NAME is not in the ClassLoader, then this cannot be an
-            // instance of WebViewClientCompat.
-            return false;
-        }
-    }
-
     /**
      * Indicates whether this client can handle the callback(s) assocated with {@param featureName}.
      * This should be called with the correct feature name before invoking the corresponding
diff --git a/android_webview/ui/grit_strings_whitelist.txt b/android_webview/ui/grit_strings_whitelist.txt
index c9e55b2..efd4782 100644
--- a/android_webview/ui/grit_strings_whitelist.txt
+++ b/android_webview/ui/grit_strings_whitelist.txt
@@ -17,7 +17,6 @@
 IDS_HARMFUL_V3_EXPLANATION_PARAGRAPH_SUBRESOURCE
 IDS_HARMFUL_V3_PROCEED_PARAGRAPH
 IDS_SAFE_BROWSING_PRIVACY_POLICY_PAGE
-IDS_SAFE_BROWSING_MALWARE_REPORTING_AGREE
 IDS_SAFE_BROWSING_SCOUT_REPORTING_AGREE
 IDS_PHISHING_V4_HEADING
 IDS_PHISHING_V4_PRIMARY_PARAGRAPH
diff --git a/ash/cursor_unittest.cc b/ash/cursor_unittest.cc
index 390239a..e6d9736 100644
--- a/ash/cursor_unittest.cc
+++ b/ash/cursor_unittest.cc
@@ -29,7 +29,7 @@
   ui::test::EventGenerator generator(window.get());
   generator.MoveMouseToInHost(50, 50);
   ASSERT_EQ(1U, GetTestWindowTreeClient()->input_events().size());
-  EXPECT_EQ(ui::EventType::ET_POINTER_MOVED,
+  EXPECT_EQ(ui::EventType::ET_MOUSE_MOVED,
             GetTestWindowTreeClient()->PopInputEvent().event->type());
 
   // Check that WindowTree actually sets the cursor.
diff --git a/ash/keyboard/virtual_keyboard_controller_unittest.cc b/ash/keyboard/virtual_keyboard_controller_unittest.cc
index 9a194ea..495aef3 100644
--- a/ash/keyboard/virtual_keyboard_controller_unittest.cc
+++ b/ash/keyboard/virtual_keyboard_controller_unittest.cc
@@ -50,6 +50,20 @@
     ws::InputDeviceClientTestApi().SetTouchscreenDevices({});
   }
 
+  void TearDown() override {
+    // Ensure keyboard is reset for the next test.
+    keyboard::SetAccessibilityKeyboardEnabled(false);
+    keyboard::SetKeyboardEnabledFromShelf(false);
+    keyboard::SetTouchKeyboardEnabled(false);
+    keyboard::SetRequestedKeyboardState(keyboard::KEYBOARD_STATE_AUTO);
+
+    // Ensure inputs devices are reset for the next test.
+    ws::InputDeviceClientTestApi().SetKeyboardDevices({});
+    ws::InputDeviceClientTestApi().SetTouchscreenDevices({});
+
+    AshTestBase::TearDown();
+  }
+
   display::Display GetPrimaryDisplay() {
     return display::Screen::GetScreen()->GetPrimaryDisplay();
   }
@@ -223,17 +237,13 @@
   ~VirtualKeyboardControllerAutoTest() override = default;
 
   void SetUp() override {
-    AshTestBase::SetUp();
-    // Set the current list of devices to empty so that they don't interfere
-    // with the test.
-    ws::InputDeviceClientTestApi().SetKeyboardDevices({});
-    ws::InputDeviceClientTestApi().SetTouchscreenDevices({});
+    VirtualKeyboardControllerTest::SetUp();
     Shell::Get()->system_tray_notifier()->AddVirtualKeyboardObserver(this);
   }
 
   void TearDown() override {
     Shell::Get()->system_tray_notifier()->RemoveVirtualKeyboardObserver(this);
-    AshTestBase::TearDown();
+    VirtualKeyboardControllerTest::TearDown();
   }
 
   void OnKeyboardSuppressionChanged(bool suppressed) override {
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
index 919dad6..094dea7 100644
--- a/base/metrics/histogram.cc
+++ b/base/metrics/histogram.cc
@@ -157,8 +157,6 @@
 
 HistogramBase* Histogram::Factory::Build() {
   HistogramBase* histogram = StatisticsRecorder::FindHistogram(name_);
-  const bool found = (histogram != nullptr);
-  debug::Alias(&found);
   if (!histogram) {
     // TODO(gayane): |HashMetricName()| is called again in Histogram
     // constructor. Refactor code to avoid the additional call.
@@ -332,43 +330,6 @@
                        static_cast<Sample>(HashMetricName(name_)));
     DLOG(ERROR) << "Histogram " << name_
                 << " has mismatched construction arguments";
-
-// crbug.com/836238: Temporarily create crashes for this condition in order
-// to find out why it is happening for many metrics that are hard-coded and
-// thus should never have a mismatch.
-// TODO(bcwhite): Revert this once some crashes have been collected.
-#if defined(OS_WIN)  // Only Windows has a debugger that makes this useful.
-    // Don't crash for linear histograms as these have never shown an error
-    // but mismitches still occur because of extensions that have different
-    // enumeration lists than what is inside Chrome. Continue to return the
-    // "dummy" histogram (below) instead.
-    if (histogram_type_ != LINEAR_HISTOGRAM) {
-      // Create local copies of the parameters to be sure they'll be available
-      // in the crash dump for the debugger to see.
-      const Histogram* h = static_cast<Histogram*>(histogram);
-      Sample hash_32 = static_cast<Sample>(HashMetricName(name_));
-      debug::Alias(&hash_32);
-      DEBUG_ALIAS_FOR_CSTR(new_name, name_.c_str(), 100);
-      HistogramType new_type = histogram_type_;
-      Sample new_min = minimum_;
-      Sample new_max = maximum_;
-      uint32_t new_count = bucket_count_;
-      debug::Alias(&new_type);
-      debug::Alias(&new_min);
-      debug::Alias(&new_max);
-      debug::Alias(&new_count);
-      DEBUG_ALIAS_FOR_CSTR(old_name, h->histogram_name(), 100);
-      HistogramType old_type = h->GetHistogramType();
-      Sample old_min = h->declared_min();
-      Sample old_max = h->declared_max();
-      uint32_t old_count = h->bucket_count();
-      debug::Alias(&old_type);
-      debug::Alias(&old_min);
-      debug::Alias(&old_max);
-      debug::Alias(&old_count);
-      CHECK(false) << name_;
-    }
-#endif
     return DummyHistogram::GetInstance();
   }
   return histogram;
diff --git a/base/metrics/histogram_unittest.cc b/base/metrics/histogram_unittest.cc
index f142298..e516acb 100644
--- a/base/metrics/histogram_unittest.cc
+++ b/base/metrics/histogram_unittest.cc
@@ -653,7 +653,6 @@
   EXPECT_FALSE(iter.SkipBytes(1));
 }
 
-#if 0  // TODO(crbug.com/836238): Temporarily disabled for field crash test.
 TEST_P(HistogramTest, BadConstruction) {
   HistogramBase* histogram = Histogram::FactoryGet(
       "BadConstruction", 0, 100, 8, HistogramBase::kNoFlags);
@@ -679,7 +678,6 @@
       "BadConstructionLinear", 10, 100, 8, HistogramBase::kNoFlags);
   EXPECT_EQ(DummyHistogram::GetInstance(), bad_histogram);
 }
-#endif
 
 TEST_P(HistogramTest, FactoryTime) {
   const int kTestCreateCount = 1 << 14;  // Must be power-of-2.
diff --git a/base/metrics/single_sample_metrics_unittest.cc b/base/metrics/single_sample_metrics_unittest.cc
index cca7514..d4d5913 100644
--- a/base/metrics/single_sample_metrics_unittest.cc
+++ b/base/metrics/single_sample_metrics_unittest.cc
@@ -81,7 +81,6 @@
   // Verify only the last sample sent to SetSample() is recorded.
   tester.ExpectUniqueSample(kMetricName, kLastSample, 1);
 
-#if 0  // TODO(crbug.com/836238): Temporarily disabled for field crash test.
   // Verify construction implicitly by requesting a histogram with the same
   // parameters; this test relies on the fact that histogram objects are unique
   // per name. Different parameters will result in a Dummy histogram returned.
@@ -91,7 +90,6 @@
   EXPECT_NE(DummyHistogram::GetInstance(),
             Histogram::FactoryGet(kMetricName, kMin, kMax, kBucketCount,
                                   HistogramBase::kUmaTargetedHistogramFlag));
-#endif
 }
 
 TEST_F(SingleSampleMetricsTest, MultipleMetricsAreDistinct) {
diff --git a/build/android/test_runner.py b/build/android/test_runner.py
index a8f50cb..fc241df 100755
--- a/build/android/test_runner.py
+++ b/build/android/test_runner.py
@@ -74,6 +74,7 @@
       '--test-launcher-retry-limit',
       '--test_launcher_retry_limit',
       '--num_retries', '--num-retries',
+      '--isolated-script-test-launcher-retry-limit',
       dest='num_retries', type=int, default=2,
       help='Number of retries for a test before '
            'giving up (default: %(default)s).')
@@ -193,7 +194,6 @@
       '--gs-results-bucket',
       help='Google Storage bucket to upload results to.')
 
-
   parser.add_argument(
       '--output-directory',
       dest='output_directory', type=os.path.realpath,
@@ -201,14 +201,21 @@
            ' located (must include build type). This will take'
            ' precedence over --debug and --release')
   parser.add_argument(
-      '--repeat', '--gtest_repeat', '--gtest-repeat',
-      dest='repeat', type=int, default=0,
-      help='Number of times to repeat the specified set of tests.')
-  parser.add_argument(
       '-v', '--verbose',
       dest='verbose_count', default=0, action='count',
       help='Verbose level (multiple times for more)')
 
+  parser.add_argument(
+      '--repeat', '--gtest_repeat', '--gtest-repeat',
+      '--isolated-script-test-repeat',
+      dest='repeat', type=int, default=0,
+      help='Number of times to repeat the specified set of tests.')
+  parser.add_argument(
+      '--gtest_also_run_disabled_tests', '--gtest-also-run-disabled-tests',
+      '--isolated-script-test-also-run-disabled-tests',
+      dest='run_disabled', action='store_true',
+      help='Also run disabled tests if applicable.')
+
   AddTestLauncherOptions(parser)
 
 
@@ -332,10 +339,6 @@
       help=('If present, test artifacts will be uploaded to this Google '
             'Storage bucket.'))
   parser.add_argument(
-      '--gtest_also_run_disabled_tests', '--gtest-also-run-disabled-tests',
-      dest='run_disabled', action='store_true',
-      help='Also run disabled tests if applicable.')
-  parser.add_argument(
       '--runtime-deps-path',
       dest='runtime_deps_path', type=os.path.realpath,
       help='Runtime data dependency file from GN.')
@@ -406,10 +409,6 @@
       dest='exclude_annotation_str',
       help='Comma-separated list of annotations. Exclude tests with these '
            'annotations.')
-  parser.add_argument(
-      '--gtest_also_run_disabled_tests', '--gtest-also-run-disabled-tests',
-      dest='run_disabled', action='store_true',
-      help='Also run disabled tests if applicable.')
   def package_replacement(arg):
     split_arg = arg.split(',')
     if len(split_arg) != 2:
diff --git a/build/check_gn_headers_whitelist.txt b/build/check_gn_headers_whitelist.txt
index 232ebfab..17acc9a 100644
--- a/build/check_gn_headers_whitelist.txt
+++ b/build/check_gn_headers_whitelist.txt
@@ -66,7 +66,6 @@
 chrome/browser/ui/ash/ash_util.h
 chrome/browser/ui/ash/multi_user/multi_user_util.h
 chrome/browser/ui/network_profile_bubble.h
-chrome/browser/ui/passwords/manage_passwords_icon.h
 chrome/browser/ui/views/frame/browser_frame_header_ash.h
 chrome/browser/ui/webui/large_icon_source.h
 chrome/common/mac/app_shim_launch.h
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index 1ef88c7c..3315d437 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -125,7 +125,7 @@
   if (layer_tree_host_) {
     layer_tree_host_->property_trees()->needs_rebuild = true;
     layer_tree_host_->UnregisterLayer(this);
-    if (!layer_tree_host_->IsUsingLayerLists() && inputs_.element_id) {
+    if (inputs_.element_id) {
       layer_tree_host_->UnregisterElement(inputs_.element_id,
                                           ElementListType::ACTIVE);
     }
@@ -135,9 +135,8 @@
   if (host) {
     host->property_trees()->needs_rebuild = true;
     host->RegisterLayer(this);
-    if (!host->IsUsingLayerLists() && inputs_.element_id) {
+    if (inputs_.element_id)
       host->RegisterElement(inputs_.element_id, ElementListType::ACTIVE, this);
-    }
     if (!host->IsUsingLayerLists())
       property_tree_indices_invalid = true;
   }
diff --git a/cc/layers/layer_unittest.cc b/cc/layers/layer_unittest.cc
index 42aaed9e..1b4dc11 100644
--- a/cc/layers/layer_unittest.cc
+++ b/cc/layers/layer_unittest.cc
@@ -1548,25 +1548,34 @@
   }
 };
 
-TEST_F(LayerTestWithLayerLists,
-       SetLayerTreeHostUsingLayerListsDoesNotManageElementId) {
+TEST_F(LayerTestWithLayerLists, LayerTreeHostRegistersElementId) {
   scoped_refptr<Layer> test_layer = Layer::Create();
   ElementId element_id = ElementId(2);
   test_layer->SetElementId(element_id);
 
-  // Only one call expected since we should skip the has-animation check.
-  EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1);
-  scoped_refptr<AnimationTimeline> timeline =
-      AnimationTimeline::Create(AnimationIdProvider::NextTimelineId());
-  animation_host_->AddAnimationTimeline(timeline);
-
-  AddOpacityTransitionToElementWithAnimation(element_id, timeline, 10.0, 1.f,
-                                             0.f, false);
-  EXPECT_TRUE(animation_host_->IsElementAnimating(element_id));
-
   EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(element_id));
   test_layer->SetLayerTreeHost(layer_tree_host_.get());
-  // Layer shouldn't have been registered by element id.
+  EXPECT_EQ(test_layer, layer_tree_host_->LayerByElementId(element_id));
+
+  test_layer->SetLayerTreeHost(nullptr);
+  EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(element_id));
+}
+
+TEST_F(LayerTestWithLayerLists, ChangingElementIdRegistersElement) {
+  scoped_refptr<Layer> test_layer = Layer::Create();
+  EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1);
+  test_layer->SetLayerTreeHost(layer_tree_host_.get());
+
+  ElementId element_id = ElementId(2);
+  EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(element_id));
+
+  // Setting the element id should register the layer.
+  test_layer->SetElementId(element_id);
+  EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1);
+  EXPECT_EQ(test_layer, layer_tree_host_->LayerByElementId(element_id));
+
+  // Unsetting the element id should unregister the layer.
+  test_layer->SetElementId(ElementId());
   EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(element_id));
 
   test_layer->SetLayerTreeHost(nullptr);
diff --git a/cc/test/pixel_test.cc b/cc/test/pixel_test.cc
index b3bbd81..9fe3b51 100644
--- a/cc/test/pixel_test.cc
+++ b/cc/test/pixel_test.cc
@@ -239,7 +239,7 @@
   SetUpGLWithoutRenderer(false);
   renderer_ = std::make_unique<viz::SkiaRenderer>(
       &renderer_settings_, output_surface_.get(), resource_provider_.get(),
-      nullptr /* skia_output_surface */);
+      nullptr /* skia_output_surface */, viz::SkiaRenderer::DrawMode::GL);
   renderer_->Initialize();
   renderer_->SetVisible(true);
 }
@@ -297,7 +297,8 @@
       nullptr /* shared_bitmap_manager */);
   renderer_ = std::make_unique<viz::SkiaRenderer>(
       &renderer_settings_, output_surface_.get(), resource_provider_.get(),
-      static_cast<viz::SkiaOutputSurfaceImpl*>(output_surface_.get()));
+      static_cast<viz::SkiaOutputSurfaceImpl*>(output_surface_.get()),
+      viz::SkiaRenderer::DrawMode::DDL);
   renderer_->Initialize();
   renderer_->SetVisible(true);
 
diff --git a/cc/test/pixel_test.h b/cc/test/pixel_test.h
index ea00f41c..82bf6af 100644
--- a/cc/test/pixel_test.h
+++ b/cc/test/pixel_test.h
@@ -179,7 +179,8 @@
       : viz::SkiaRenderer(settings,
                           output_surface,
                           resource_provider,
-                          skia_output_surface) {}
+                          skia_output_surface,
+                          viz::SkiaRenderer::DrawMode::DDL) {}
 };
 
 template <>
diff --git a/cc/trees/target_property.h b/cc/trees/target_property.h
index 53d8c13a..93fa839 100644
--- a/cc/trees/target_property.h
+++ b/cc/trees/target_property.h
@@ -21,9 +21,10 @@
   SCROLL_OFFSET,
   BACKGROUND_COLOR,
   BOUNDS,
+  CSS_CUSTOM_PROPERTY,
   // These sentinels must be last
   FIRST_TARGET_PROPERTY = TRANSFORM,
-  LAST_TARGET_PROPERTY = BOUNDS
+  LAST_TARGET_PROPERTY = CSS_CUSTOM_PROPERTY
 };
 
 }  // namespace TargetProperty
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index acabfb8..18cec13 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -1829,7 +1829,14 @@
 
 if (is_linux) {
   if (is_official_build) {
-    extract_symbols("linux") {
+    group("linux_symbols") {
+      deps = [
+        ":chrome_symbols",
+        ":swiftshader_egl_symbols",
+        ":swiftshader_gles_symbols",
+      ]
+    }
+    extract_symbols("chrome") {
       binary = "$root_out_dir/chrome"
 
       if (current_cpu == "x86") {
@@ -1843,6 +1850,34 @@
         ":chrome",
       ]
     }
+    extract_symbols("swiftshader_egl") {
+      binary = "$root_out_dir/swiftshader/libEGL.so"
+
+      if (current_cpu == "x86") {
+        # GYP used "ia32" so keep that naming for back-compat.
+        symbol_file = "$root_out_dir/swiftshader_libegl.breakpad.ia32"
+      } else {
+        symbol_file = "$root_out_dir/swiftshader_libegl.breakpad.$current_cpu"
+      }
+
+      deps = [
+        "//third_party/swiftshader/src/OpenGL/libEGL:swiftshader_libEGL",
+      ]
+    }
+    extract_symbols("swiftshader_gles") {
+      binary = "$root_out_dir/swiftshader/libGLESv2.so"
+
+      if (current_cpu == "x86") {
+        # GYP used "ia32" so keep that naming for back-compat.
+        symbol_file = "$root_out_dir/swiftshader_libgles.breakpad.ia32"
+      } else {
+        symbol_file = "$root_out_dir/swiftshader_libgles.breakpad.$current_cpu"
+      }
+
+      deps = [
+        "//third_party/swiftshader/src/OpenGL/libGLESv2:swiftshader_libGLESv2",
+      ]
+    }
   }
 
   # Copies some scripts and resources that are used for desktop integration.
diff --git a/chrome/android/java/res/color/blue_when_enabled.xml b/chrome/android/java/res/color/blue_when_enabled.xml
deleted file mode 100644
index b087663c1..0000000
--- a/chrome/android/java/res/color/blue_when_enabled.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2017 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.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false" android:color="@color/modern_grey_300" />
-    <item android:color="@color/default_icon_color_blue"/>
-</selector>
diff --git a/chrome/android/java/res/layout/contextual_suggestions_layout.xml b/chrome/android/java/res/layout/contextual_suggestions_layout.xml
index 1bd0ec6a..6c4d9a1 100644
--- a/chrome/android/java/res/layout/contextual_suggestions_layout.xml
+++ b/chrome/android/java/res/layout/contextual_suggestions_layout.xml
@@ -8,5 +8,5 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:scrollbars="vertical"
-    android:paddingTop="@dimen/bottom_sheet_peek_height"
+    android:layout_marginTop="@dimen/bottom_sheet_peek_height"
     android:background="@android:color/white" />
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java
index 5682b0a8..5e0c4a4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java
@@ -6,10 +6,12 @@
 
 import android.os.Bundle;
 
+import org.chromium.base.Callback;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.chrome.browser.autofill.PersonalDataManager;
 import org.chromium.chrome.browser.customtabs.CustomTabActivity;
+import org.chromium.chrome.browser.payments.AutofillAssistantPaymentRequest;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver;
@@ -17,6 +19,7 @@
 import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType;
 import org.chromium.components.variations.VariationsAssociatedData;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.payments.mojom.PaymentOptions;
 
 import java.util.ArrayList;
 import java.util.Date;
@@ -40,9 +43,12 @@
     /** Special parameter that enables the feature. */
     private static final String PARAMETER_ENABLED = "ENABLED";
 
+    private final WebContents mWebContents;
     private final long mUiControllerAndroid;
     private final AutofillAssistantUiDelegate mUiDelegate;
 
+    private AutofillAssistantPaymentRequest mAutofillAssistantPaymentRequest;
+
     /**
      * Returns true if all conditions are satisfied to construct an AutofillAssistantUiController.
      *
@@ -68,9 +74,10 @@
         parameters.remove(PARAMETER_ENABLED);
 
         Tab activityTab = activity.getActivityTab();
-        mUiControllerAndroid = nativeInit(activityTab.getWebContents(),
-                parameters.keySet().toArray(new String[parameters.size()]),
-                parameters.values().toArray(new String[parameters.size()]));
+        mWebContents = activityTab.getWebContents();
+        mUiControllerAndroid =
+                nativeInit(mWebContents, parameters.keySet().toArray(new String[parameters.size()]),
+                        parameters.values().toArray(new String[parameters.size()]));
 
         // Shut down Autofill Assistant when the tab is detached from the activity.
         activityTab.addObserver(new EmptyTabObserver() {
@@ -96,7 +103,6 @@
                 // selected Tab.
             }
         });
-
     }
 
     @Override
@@ -184,6 +190,35 @@
     }
 
     @CalledByNative
+    private void onRequestPaymentInformation(boolean requestShipping, boolean requestPayerName,
+            boolean requestPayerPhone, boolean requestPayerEmail, int shippingType) {
+        PaymentOptions paymentOtions = new PaymentOptions();
+        paymentOtions.requestShipping = requestShipping;
+        paymentOtions.requestPayerName = requestPayerName;
+        paymentOtions.requestPayerPhone = requestPayerPhone;
+        paymentOtions.requestPayerEmail = requestPayerEmail;
+        paymentOtions.shippingType = shippingType;
+        mAutofillAssistantPaymentRequest =
+                new AutofillAssistantPaymentRequest(mWebContents, paymentOtions);
+        mAutofillAssistantPaymentRequest.show(
+                new Callback<AutofillAssistantPaymentRequest.SelectedPaymentInformation>() {
+                    @Override
+                    public void onResult(AutofillAssistantPaymentRequest.SelectedPaymentInformation
+                                                 selectedPaymentInformation) {
+                        nativeOnGetPaymentInformation(mUiControllerAndroid,
+                                selectedPaymentInformation.succeed,
+                                selectedPaymentInformation.cardGuid,
+                                selectedPaymentInformation.addressGuid,
+                                selectedPaymentInformation.payerName,
+                                selectedPaymentInformation.payerPhone,
+                                selectedPaymentInformation.payerEmail);
+                        mAutofillAssistantPaymentRequest.close();
+                        mAutofillAssistantPaymentRequest = null;
+                    }
+                });
+    }
+
+    @CalledByNative
     private void onHideDetails() {
         mUiDelegate.hideDetails();
     }
@@ -206,4 +241,7 @@
     private native void nativeOnScriptSelected(long nativeUiControllerAndroid, String scriptPath);
     private native void nativeOnAddressSelected(long nativeUiControllerAndroid, String guid);
     private native void nativeOnCardSelected(long nativeUiControllerAndroid, String guid);
+    private native void nativeOnGetPaymentInformation(long nativeUiControllerAndroid,
+            boolean succeed, String cardGuid, String addressGuid, String payerName,
+            String payerPhone, String payerEmail);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactsPickerToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactsPickerToolbar.java
index 6b0ab21..06aae52 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactsPickerToolbar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactsPickerToolbar.java
@@ -5,11 +5,11 @@
 package org.chromium.chrome.browser.contacts_picker;
 
 import android.content.Context;
-import android.graphics.Color;
 import android.util.AttributeSet;
 import android.widget.Button;
 import android.widget.TextView;
 
+import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.widget.selection.SelectableListToolbar;
 
@@ -31,9 +31,8 @@
 
         TextView up = (TextView) mNumberRollView.findViewById(R.id.up);
         TextView down = (TextView) mNumberRollView.findViewById(R.id.down);
-        // TODO(finnur): Change this to use pre-defined styles.
-        up.setTextColor(Color.BLACK);
-        down.setTextColor(Color.BLACK);
+        ApiCompatibilityUtils.setTextAppearance(up, R.style.BlackHeadline2);
+        ApiCompatibilityUtils.setTextAppearance(down, R.style.BlackHeadline2);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PaymentHandlerActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PaymentHandlerActivity.java
index de20569..eff7afa 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PaymentHandlerActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/PaymentHandlerActivity.java
@@ -11,6 +11,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.payments.ServiceWorkerPaymentAppBridge;
 import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.ui.display.DisplayUtil;
 
 /**
  * Simple wrapper around CustomTabActivity to be used when launching a payment handler tab, which
@@ -51,7 +52,8 @@
     }
 
     private void updateHeight() {
-        int displayHeightInPixels = getWindowAndroid().getDisplay().getDisplayHeight();
+        int displayHeightInPixels = DisplayUtil.dpToPx(
+                getWindowAndroid().getDisplay(), getResources().getConfiguration().screenHeightDp);
         int heightInPhysicalPixels = (int) (displayHeightInPixels * BOTTOM_SHEET_HEIGHT_RATIO);
         int minimumHeightInPhysicalPixels = getResources().getDimensionPixelSize(
                 R.dimen.payments_handler_window_minimum_height);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java
index 7a6fb915..62537a44 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java
@@ -19,6 +19,7 @@
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.suggestions.SuggestionsConfig.TileStyle;
 import org.chromium.chrome.browser.suggestions.TileGridLayout;
+import org.chromium.chrome.browser.util.ViewUtils;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.ui.base.PageTransition;
 import org.chromium.ui.mojom.WindowOpenDisposition;
@@ -156,12 +157,13 @@
                 if (v == null) {
                     continue;
                 }
-                ExploreSitesBridge.getCategoryImage(mProfile, category.getId(),
-                        v.getContext().getResources().getDimensionPixelSize(
-                                R.dimen.tile_view_icon_size),
-                        (Bitmap image) -> {
+                int iconSizePx = v.getContext().getResources().getDimensionPixelSize(
+                        R.dimen.tile_view_icon_size);
+                ExploreSitesBridge.getCategoryImage(
+                        mProfile, category.getId(), iconSizePx, (Bitmap image) -> {
                             if (image != null) {
-                                category.setIcon(mExploreSection.getContext(), image);
+                                category.setDrawable(ViewUtils.createRoundedBitmapDrawable(
+                                        image, iconSizePx / 2));
                                 v.renderIcon(category);
                             }
                         });
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillAssistantPaymentRequest.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillAssistantPaymentRequest.java
new file mode 100644
index 0000000..c5ff3756
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillAssistantPaymentRequest.java
@@ -0,0 +1,486 @@
+// Copyright 2018 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.
+
+package org.chromium.chrome.browser.payments;
+
+import android.content.Context;
+import android.os.Handler;
+import android.support.v4.util.ArrayMap;
+import android.text.TextUtils;
+
+import org.chromium.base.Callback;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.autofill.PersonalDataManager;
+import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
+import org.chromium.chrome.browser.favicon.FaviconHelper;
+import org.chromium.chrome.browser.payments.ui.ContactDetailsSection;
+import org.chromium.chrome.browser.payments.ui.PaymentInformation;
+import org.chromium.chrome.browser.payments.ui.PaymentRequestUI;
+import org.chromium.chrome.browser.payments.ui.SectionInformation;
+import org.chromium.chrome.browser.payments.ui.ShoppingCart;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.ssl.SecurityStateModel;
+import org.chromium.chrome.browser.widget.prefeditor.Completable;
+import org.chromium.chrome.browser.widget.prefeditor.EditableOption;
+import org.chromium.components.url_formatter.UrlFormatter;
+import org.chromium.content_public.browser.WebContents;
+import org.chromium.payments.mojom.PaymentMethodData;
+import org.chromium.payments.mojom.PaymentOptions;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class simplifies payment request UX to get payment information for Autofill Assistant.
+ *
+ * TODO(crbug.com/806868): Refactor shared codes with PaymentRequestImpl to a common place when the
+ * UX is fixed.
+ */
+public class AutofillAssistantPaymentRequest implements PaymentRequestUI.Client {
+    private static final String BASIC_CARD_PAYMENT_METHOD = "basic-card";
+    private static final Comparator<Completable> COMPLETENESS_COMPARATOR =
+            (a, b) -> (b.isComplete() ? 1 : 0) - (a.isComplete() ? 1 : 0);
+
+    private final WebContents mWebContents;
+    private final PaymentOptions mPaymentOptions;
+    private final CardEditor mCardEditor;
+    private final AddressEditor mAddressEditor;
+    private final Map<String, PaymentMethodData> mMethodData;
+    private final Handler mHandler = new Handler();
+
+    private PaymentRequestUI mUI;
+    private ContactEditor mContactEditor;
+    private SectionInformation mPaymentMethodsSection;
+    private SectionInformation mShippingAddressesSection;
+    private ContactDetailsSection mContactSection;
+    private Callback<SelectedPaymentInformation> mCallback;
+
+    /** The class to return payment information. */
+    public class SelectedPaymentInformation {
+        /** Whether selection succeed. */
+        public boolean succeed;
+
+        /** Selected payment card's guid in personal data manager. */
+        public String cardGuid;
+
+        /** Selected shipping address's guid in personal data manager. */
+        public String addressGuid;
+
+        /** Payer's contact name. */
+        public String payerName;
+
+        /** Payer's contact email. */
+        public String payerEmail;
+
+        /** Payer's contact phone. */
+        public String payerPhone;
+    }
+
+    /**
+     * Constructor of AutofillAssistantPaymentRequest.
+     *
+     * @webContents    The web contents of the payment request associated with.
+     * @paymentOptions The options to request payment information.
+     */
+    public AutofillAssistantPaymentRequest(WebContents webContents, PaymentOptions paymentOptions) {
+        mWebContents = webContents;
+        mPaymentOptions = paymentOptions;
+
+        // This feature should only works in non-incognito mode.
+        mAddressEditor = new AddressEditor(/* emailFieldIncluded= */ true, /* saveToDisk= */ true);
+        mCardEditor = new CardEditor(mWebContents, mAddressEditor, /* observerForTest= */ null);
+
+        // Only enable 'basic-card' payment method.
+        PaymentMethodData methodData = new PaymentMethodData();
+        methodData.supportedMethod = BASIC_CARD_PAYMENT_METHOD;
+        mMethodData = new ArrayMap<>();
+        mMethodData.put(BASIC_CARD_PAYMENT_METHOD, methodData);
+        mCardEditor.addAcceptedPaymentMethodIfRecognized(methodData);
+    }
+
+    /**
+     * Show payment request UI to ask for payment information.
+     *
+     * @param callback The callback to return payment information.
+     */
+    public void show(Callback<SelectedPaymentInformation> callback) {
+        // Do not expect calling show multiple times.
+        assert mCallback == null;
+        assert mUI != null;
+
+        mCallback = callback;
+        buidUI(ChromeActivity.fromWebContents(mWebContents));
+        mUI.show();
+    }
+
+    private void buidUI(ChromeActivity activity) {
+        assert activity != null;
+
+        mPaymentMethodsSection = new SectionInformation(PaymentRequestUI.DataType.PAYMENT_METHODS,
+                SectionInformation.NO_SELECTION,
+                (new AutofillPaymentApp(mWebContents)).getInstruments(mMethodData));
+        if (!mPaymentMethodsSection.isEmpty() && mPaymentMethodsSection.getItem(0).isComplete()) {
+            mPaymentMethodsSection.setSelectedItemIndex(0);
+        }
+
+        List<AutofillProfile> profiles = null;
+        if (mPaymentOptions.requestShipping || mPaymentOptions.requestPayerName
+                || mPaymentOptions.requestPayerPhone || mPaymentOptions.requestPayerEmail) {
+            profiles = PersonalDataManager.getInstance().getProfilesToSuggest(
+                    /* includeNameInLabel= */ false);
+        }
+
+        if (mPaymentOptions.requestShipping) {
+            createShippingSection(activity, Collections.unmodifiableList(profiles));
+        }
+
+        if (mPaymentOptions.requestPayerName || mPaymentOptions.requestPayerPhone
+                || mPaymentOptions.requestPayerEmail) {
+            mContactEditor = new ContactEditor(mPaymentOptions.requestPayerName,
+                    mPaymentOptions.requestPayerPhone, mPaymentOptions.requestPayerEmail,
+                    /* saveToDisk= */ true);
+            mContactSection = new ContactDetailsSection(activity,
+                    Collections.unmodifiableList(profiles), mContactEditor,
+                    /* journeyLogger= */ null);
+        }
+
+        mUI = new PaymentRequestUI(activity, this, mPaymentOptions.requestShipping,
+                /* requestShippingOption= */ false,
+                mPaymentOptions.requestPayerName || mPaymentOptions.requestPayerPhone
+                        || mPaymentOptions.requestPayerEmail,
+                /* canAddCards= */ true, /* showDataSource= */ true, mWebContents.getTitle(),
+                UrlFormatter.formatUrlForSecurityDisplay(mWebContents.getLastCommittedUrl()),
+                SecurityStateModel.getSecurityLevelForWebContents(mWebContents),
+                new ShippingStrings(mPaymentOptions.shippingType));
+
+        final FaviconHelper faviconHelper = new FaviconHelper();
+        faviconHelper.getLocalFaviconImageForURL(Profile.getLastUsedProfile(),
+                mWebContents.getLastCommittedUrl(),
+                activity.getResources().getDimensionPixelSize(R.dimen.payments_favicon_size),
+                (bitmap, iconUrl) -> {
+                    if (mUI != null && bitmap != null) mUI.setTitleBitmap(bitmap);
+                    faviconHelper.destroy();
+                });
+
+        mAddressEditor.setEditorDialog(mUI.getEditorDialog());
+        mCardEditor.setEditorDialog(mUI.getCardEditorDialog());
+        if (mContactEditor != null) mContactEditor.setEditorDialog(mUI.getEditorDialog());
+    }
+
+    private void createShippingSection(
+            Context context, List<AutofillProfile> unmodifiableProfiles) {
+        List<AutofillAddress> addresses = new ArrayList<>();
+
+        for (int i = 0; i < unmodifiableProfiles.size(); i++) {
+            AutofillProfile profile = unmodifiableProfiles.get(i);
+            mAddressEditor.addPhoneNumberIfValid(profile.getPhoneNumber());
+
+            // Only suggest addresses that have a street address.
+            if (!TextUtils.isEmpty(profile.getStreetAddress())) {
+                addresses.add(new AutofillAddress(context, profile));
+            }
+        }
+
+        // Suggest complete addresses first.
+        Collections.sort(addresses, COMPLETENESS_COMPARATOR);
+
+        // Automatically select the first address if one is complete.
+        int firstCompleteAddressIndex = SectionInformation.NO_SELECTION;
+        if (!addresses.isEmpty() && addresses.get(0).isComplete()) {
+            firstCompleteAddressIndex = 0;
+
+            // The initial label for the selected shipping address should not include the
+            // country.
+            addresses.get(firstCompleteAddressIndex).setShippingAddressLabelWithoutCountry();
+        }
+
+        mShippingAddressesSection = new SectionInformation(
+                PaymentRequestUI.DataType.SHIPPING_ADDRESSES, firstCompleteAddressIndex, addresses);
+    }
+
+    /** Close payment request. */
+    public void close() {
+        if (mUI != null) {
+            // Close the UI immediately and do not wait for finishing animations.
+            mUI.close(/* shouldCloseImmediately = */ true, () -> {});
+            mUI = null;
+        }
+
+        // Do not call callback if closed by caller.
+        mCallback = null;
+    }
+
+    @Override
+    public void getDefaultPaymentInformation(Callback<PaymentInformation> callback) {
+        mHandler.post(() -> {
+            if (mUI != null) {
+                callback.onResult(new PaymentInformation(/* shoppingCart= */ null,
+                        mShippingAddressesSection,
+                        /* shippingOptions= */ null, mContactSection, mPaymentMethodsSection));
+            }
+        });
+    }
+
+    @Override
+    public void getShoppingCart(Callback<ShoppingCart> callback) {
+        // Do not display anything for shopping cart.
+        mHandler.post(() -> callback.onResult(null));
+    }
+
+    @Override
+    public void getSectionInformation(
+            @PaymentRequestUI.DataType int optionType, Callback<SectionInformation> callback) {
+        mHandler.post(() -> {
+            if (optionType == PaymentRequestUI.DataType.SHIPPING_ADDRESSES) {
+                callback.onResult(mShippingAddressesSection);
+            } else if (optionType == PaymentRequestUI.DataType.CONTACT_DETAILS) {
+                callback.onResult(mContactSection);
+            } else if (optionType == PaymentRequestUI.DataType.PAYMENT_METHODS) {
+                assert mPaymentMethodsSection != null;
+                callback.onResult(mPaymentMethodsSection);
+            } else {
+                // Only support above sections for now.
+                assert false;
+            }
+        });
+    }
+
+    @Override
+    @PaymentRequestUI.SelectionResult
+    public int onSectionOptionSelected(@PaymentRequestUI.DataType int optionType,
+            EditableOption option, Callback<PaymentInformation> checkedCallback) {
+        if (optionType == PaymentRequestUI.DataType.SHIPPING_ADDRESSES) {
+            AutofillAddress address = (AutofillAddress) option;
+            if (address.isComplete()) {
+                mShippingAddressesSection.setSelectedItem(option);
+            } else {
+                editAddress(address);
+                return PaymentRequestUI.SelectionResult.EDITOR_LAUNCH;
+            }
+        } else if (optionType == PaymentRequestUI.DataType.CONTACT_DETAILS) {
+            AutofillContact contact = (AutofillContact) option;
+            if (contact.isComplete()) {
+                mContactSection.setSelectedItem(option);
+            } else {
+                editContact(contact);
+                return PaymentRequestUI.SelectionResult.EDITOR_LAUNCH;
+            }
+        } else if (optionType == PaymentRequestUI.DataType.PAYMENT_METHODS) {
+            AutofillPaymentInstrument card = (AutofillPaymentInstrument) option;
+            if (card.isComplete()) {
+                mPaymentMethodsSection.setSelectedItem(option);
+            } else {
+                editCard(card);
+                return PaymentRequestUI.SelectionResult.EDITOR_LAUNCH;
+            }
+        } else {
+            // Only support above sections for now.
+            assert false;
+        }
+
+        return PaymentRequestUI.SelectionResult.NONE;
+    }
+
+    @Override
+    @PaymentRequestUI.SelectionResult
+    public int onSectionEditOption(@PaymentRequestUI.DataType int optionType, EditableOption option,
+            Callback<PaymentInformation> checkedCallback) {
+        if (optionType == PaymentRequestUI.DataType.SHIPPING_ADDRESSES) {
+            editAddress((AutofillAddress) option);
+            return PaymentRequestUI.SelectionResult.EDITOR_LAUNCH;
+        }
+
+        if (optionType == PaymentRequestUI.DataType.CONTACT_DETAILS) {
+            editContact((AutofillContact) option);
+            return PaymentRequestUI.SelectionResult.EDITOR_LAUNCH;
+        }
+
+        if (optionType == PaymentRequestUI.DataType.PAYMENT_METHODS) {
+            editCard((AutofillPaymentInstrument) option);
+            return PaymentRequestUI.SelectionResult.EDITOR_LAUNCH;
+        }
+
+        // Only support above sections for now.
+        assert false;
+        return PaymentRequestUI.SelectionResult.NONE;
+    }
+
+    @Override
+    @PaymentRequestUI.SelectionResult
+    public int onSectionAddOption(@PaymentRequestUI.DataType int optionType,
+            Callback<PaymentInformation> checkedCallback) {
+        if (optionType == PaymentRequestUI.DataType.SHIPPING_ADDRESSES) {
+            editAddress(null);
+            return PaymentRequestUI.SelectionResult.EDITOR_LAUNCH;
+        } else if (optionType == PaymentRequestUI.DataType.CONTACT_DETAILS) {
+            editContact(null);
+            return PaymentRequestUI.SelectionResult.EDITOR_LAUNCH;
+        } else if (optionType == PaymentRequestUI.DataType.PAYMENT_METHODS) {
+            editCard(null);
+            return PaymentRequestUI.SelectionResult.EDITOR_LAUNCH;
+        }
+
+        // Only support above sections for now.
+        assert false;
+        return PaymentRequestUI.SelectionResult.NONE;
+    }
+
+    private void editAddress(final AutofillAddress toEdit) {
+        mAddressEditor.edit(toEdit, new Callback<AutofillAddress>() {
+            @Override
+            public void onResult(AutofillAddress editedAddress) {
+                if (mUI == null) return;
+
+                if (editedAddress != null) {
+                    // Sets or updates the shipping address label.
+                    editedAddress.setShippingAddressLabelWithCountry();
+
+                    mCardEditor.updateBillingAddressIfComplete(editedAddress);
+
+                    // A partial or complete address came back from the editor (could have been from
+                    // adding/editing or cancelling out of the edit flow).
+                    if (!editedAddress.isComplete()) {
+                        // If the address is not complete, deselect it (editor can return incomplete
+                        // information when cancelled).
+                        mShippingAddressesSection.setSelectedItemIndex(
+                                SectionInformation.NO_SELECTION);
+                    } else {
+                        if (toEdit == null) {
+                            // Address is complete and user was in the "Add flow": add an item to
+                            // the list.
+                            mShippingAddressesSection.addAndSelectItem(editedAddress);
+                        }
+
+                        if (mContactSection != null) {
+                            // Update |mContactSection| with the new/edited address, which will
+                            // update an existing item or add a new one to the end of the list.
+                            mContactSection.addOrUpdateWithAutofillAddress(editedAddress);
+                            mUI.updateSection(
+                                    PaymentRequestUI.DataType.CONTACT_DETAILS, mContactSection);
+                        }
+                    }
+
+                    mUI.updateSection(PaymentRequestUI.DataType.SHIPPING_ADDRESSES,
+                            mShippingAddressesSection);
+                }
+            }
+        });
+    }
+
+    private void editContact(final AutofillContact toEdit) {
+        mContactEditor.edit(toEdit, new Callback<AutofillContact>() {
+            @Override
+            public void onResult(AutofillContact editedContact) {
+                if (mUI == null) return;
+
+                if (editedContact != null) {
+                    // A partial or complete contact came back from the editor (could have been from
+                    // adding/editing or cancelling out of the edit flow).
+                    if (!editedContact.isComplete()) {
+                        // If the contact is not complete according to the requirements of the flow,
+                        // deselect it (editor can return incomplete information when cancelled).
+                        mContactSection.setSelectedItemIndex(SectionInformation.NO_SELECTION);
+                    } else if (toEdit == null) {
+                        // Contact is complete and we were in the "Add flow": add an item to the
+                        // list.
+                        mContactSection.addAndSelectItem(editedContact);
+                    }
+                    // If contact is complete and (toEdit != null), no action needed: the contact
+                    // was already selected in the UI.
+                }
+                // If |editedContact| is null, the user has cancelled out of the "Add flow". No
+                // action to take (if a contact was selected in the UI, it will stay selected).
+
+                mUI.updateSection(PaymentRequestUI.DataType.CONTACT_DETAILS, mContactSection);
+            }
+        });
+    }
+
+    private void editCard(final AutofillPaymentInstrument toEdit) {
+        mCardEditor.edit(toEdit, new Callback<AutofillPaymentInstrument>() {
+            @Override
+            public void onResult(AutofillPaymentInstrument editedCard) {
+                if (mUI == null) return;
+
+                if (editedCard != null) {
+                    // A partial or complete card came back from the editor (could have been from
+                    // adding/editing or cancelling out of the edit flow).
+                    if (!editedCard.isComplete()) {
+                        // If the card is not complete, deselect it (editor can return incomplete
+                        // information when cancelled).
+                        mPaymentMethodsSection.setSelectedItemIndex(
+                                SectionInformation.NO_SELECTION);
+                    } else if (toEdit == null) {
+                        // Card is complete and we were in the "Add flow": add an item to the list.
+                        mPaymentMethodsSection.addAndSelectItem(editedCard);
+                    }
+                    // If card is complete and (toEdit != null), no action needed: the card was
+                    // already selected in the UI.
+                }
+                // If |editedCard| is null, the user has cancelled out of the "Add flow". No action
+                // to take (if another card was selected prior to the add flow, it will stay
+                // selected).
+
+                mUI.updateSection(
+                        PaymentRequestUI.DataType.PAYMENT_METHODS, mPaymentMethodsSection);
+            }
+        });
+    }
+
+    @Override
+    public boolean onPayClicked(EditableOption selectedShippingAddress,
+            EditableOption selectedShippingOption, EditableOption selectedPaymentMethod) {
+        if (mCallback != null) {
+            SelectedPaymentInformation selectedPaymentInformation =
+                    new SelectedPaymentInformation();
+
+            selectedPaymentInformation.cardGuid =
+                    ((AutofillPaymentInstrument) selectedPaymentMethod).getCard().getGUID();
+            if (mPaymentOptions.requestShipping && selectedShippingAddress != null) {
+                selectedPaymentInformation.addressGuid =
+                        ((AutofillAddress) selectedShippingAddress).getProfile().getGUID();
+            }
+            if (mPaymentOptions.requestPayerName || mPaymentOptions.requestPayerPhone
+                    || mPaymentOptions.requestPayerEmail) {
+                EditableOption selectedContact =
+                        mContactSection != null ? mContactSection.getSelectedItem() : null;
+                if (selectedContact != null) {
+                    selectedPaymentInformation.payerName =
+                            ((AutofillContact) selectedContact).getPayerName();
+                    selectedPaymentInformation.payerPhone =
+                            ((AutofillContact) selectedContact).getPayerPhone();
+                    selectedPaymentInformation.payerEmail =
+                            ((AutofillContact) selectedContact).getPayerEmail();
+                }
+            }
+            selectedPaymentInformation.succeed = true;
+            mCallback.onResult(selectedPaymentInformation);
+            mCallback = null;
+        }
+
+        return false;
+    }
+
+    @Override
+    public void onDismiss() {
+        if (mCallback != null) {
+            SelectedPaymentInformation selectedPaymentInformation =
+                    new SelectedPaymentInformation();
+            selectedPaymentInformation.succeed = false;
+            mCallback.onResult(selectedPaymentInformation);
+            mCallback = null;
+        }
+
+        close();
+    }
+
+    @Override
+    public void onCardAndAddressSettingsClicked() {
+        // TODO(crbug.com/806868): Allow user to control cards and addresses.
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentApp.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentApp.java
index 488e15a..b8ae7880 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentApp.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentApp.java
@@ -46,12 +46,20 @@
     @Override
     public void getInstruments(Map<String, PaymentMethodData> methodDataMap, String unusedOrigin,
             String unusedIFRameOrigin, byte[][] unusedCertificateChain,
-            Map<String, PaymentDetailsModifier> modifiers, final InstrumentsCallback callback) {
+            Map<String, PaymentDetailsModifier> unusedModifiers,
+            final InstrumentsCallback callback) {
+        new Handler().post(()
+                                   -> callback.onInstrumentsReady(
+                                           AutofillPaymentApp.this, getInstruments(methodDataMap)));
+    }
+
+    /** Method to get instruments synchronously. */
+    public List<PaymentInstrument> getInstruments(Map<String, PaymentMethodData> methodDataMap) {
         PersonalDataManager pdm = PersonalDataManager.getInstance();
         List<CreditCard> cards =
                 pdm.getCreditCardsToSuggest(/*includeServerCards=*/ChromeFeatureList.isEnabled(
                         ChromeFeatureList.WEB_PAYMENTS_RETURN_GOOGLE_PAY_IN_BASIC_CARD));
-        final List<PaymentInstrument> instruments = new ArrayList<>(cards.size());
+        List<PaymentInstrument> instruments = new ArrayList<>(cards.size());
 
         if (methodDataMap.containsKey(BasicCardUtils.BASIC_CARD_METHOD_NAME)) {
             mBasicCardSupportedNetworks = BasicCardUtils.convertBasicCardToNetworks(
@@ -69,7 +77,7 @@
             if (instrument != null) instruments.add(instrument);
         }
 
-        new Handler().post(() -> callback.onInstrumentsReady(AutofillPaymentApp.this, instruments));
+        return instruments;
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
index 7fd27e1..876773b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
@@ -546,6 +546,7 @@
 
         setIsAnyPaymentRequestShowing(true);
         mUI = new PaymentRequestUI(activity, this, mRequestShipping,
+                /* requestShippingOption= */ mRequestShipping,
                 mRequestPayerName || mRequestPayerPhone || mRequestPayerEmail,
                 mMerchantSupportsAutofillPaymentInstruments,
                 !PaymentPreferencesUtil.isPaymentCompleteOnce(), mMerchantName, mTopLevelOrigin,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
index 29947bd..6e03467 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
@@ -270,6 +270,7 @@
     private final Context mContext;
     private final Client mClient;
     private final boolean mRequestShipping;
+    private final boolean mRequestShippingOption;
     private final boolean mRequestContactDetails;
     private final boolean mShowDataSource;
 
@@ -317,31 +318,35 @@
     /**
      * Builds the UI for PaymentRequest.
      *
-     * @param activity        The activity on top of which the UI should be displayed.
-     * @param client          The consumer of the PaymentRequest UI.
-     * @param requestShipping Whether the UI should show the shipping address and option selection.
-     * @param requestContact  Whether the UI should show the payer name, email address and
-     *                        phone number selection.
-     * @param canAddCards     Whether the UI should show the [+ADD CARD] button. This can be false,
-     *                        for example, when the merchant does not accept credit cards, so
-     *                        there's no point in adding cards within PaymentRequest UI.
-     * @param showDataSource  Whether the UI should describe the source of Autofill data.
-     * @param title           The title to show at the top of the UI. This can be, for example, the
-     *                        &lt;title&gt; of the merchant website. If the string is too long for
-     *                        UI, it elides at the end.
-     * @param origin          The origin (https://tools.ietf.org/html/rfc6454) to show under the
-     *                        title. For example, "https://shop.momandpop.com". If the origin is too
-     *                        long for the UI, it should elide according to:
+     * @param activity              The activity on top of which the UI should be displayed.
+     * @param client                The consumer of the PaymentRequest UI.
+     * @param requestShipping       Whether the UI should show the shipping address selection.
+     * @param requestShippingOption Whether the UI should show the shipping option selection.
+     * @param requestContact        Whether the UI should show the payer name, email address and
+     *                              phone number selection.
+     * @param canAddCards           Whether the UI should show the [+ADD CARD] button. This can be
+     *                              false, for example, when the merchant does not accept credit
+     *                              cards, so there's no point in adding cards within PaymentRequest
+     *                              UI.
+     * @param showDataSource        Whether the UI should describe the source of Autofill data.
+     * @param title                 The title to show at the top of the UI. This can be, for
+     *                              example, the &lt;title&gt; of the merchant website. If the
+     *                              string is too long for UI, it elides at the end.
+     * @param origin                The origin (https://tools.ietf.org/html/rfc6454) to show under
+     *                              the title. For example, "https://shop.momandpop.com". If the
+     *                              origin is too long for the UI, it should elide according to:
      * https://www.chromium.org/Home/chromium-security/enamel#TOC-Eliding-Origin-Names-And-Hostnames
      * @param securityLevel   The security level of the page that invoked PaymentRequest.
      * @param shippingStrings The string resource identifiers to use in the shipping sections.
      */
     public PaymentRequestUI(Activity activity, Client client, boolean requestShipping,
-            boolean requestContact, boolean canAddCards, boolean showDataSource, String title,
-            String origin, int securityLevel, ShippingStrings shippingStrings) {
+            boolean requestShippingOption, boolean requestContact, boolean canAddCards,
+            boolean showDataSource, String title, String origin, int securityLevel,
+            ShippingStrings shippingStrings) {
         mContext = activity;
         mClient = client;
         mRequestShipping = requestShipping;
+        mRequestShippingOption = requestShippingOption;
         mRequestContactDetails = requestContact;
         mShowDataSource = showDataSource;
         mAnimatorTranslation = mContext.getResources().getDimensionPixelSize(
@@ -370,6 +375,8 @@
                 updateOrderSummarySection(result.getShoppingCart());
                 if (mRequestShipping) {
                     updateSection(DataType.SHIPPING_ADDRESSES, result.getShippingAddresses());
+                }
+                if (mRequestShippingOption) {
                     updateSection(DataType.SHIPPING_OPTIONS, result.getShippingOptions());
                 }
                 if (mRequestContactDetails) {
@@ -418,14 +425,10 @@
 
                 if (mRequestShipping) {
                     updateSection(DataType.SHIPPING_ADDRESSES, result.getShippingAddresses());
-                    updateSection(DataType.SHIPPING_OPTIONS, result.getShippingOptions());
+                }
 
-                    // Let the summary display a CHOOSE/ADD button for the first subsection that
-                    // needs it.
-                    PaymentRequestSection section =
-                            mShippingAddressSection.getEditButtonState() == EDIT_BUTTON_GONE
-                            ? mShippingOptionSection
-                            : mShippingAddressSection;
+                if (mRequestShippingOption) {
+                    updateSection(DataType.SHIPPING_OPTIONS, result.getShippingOptions());
                 }
 
                 if (mRequestContactDetails) {
@@ -659,7 +662,7 @@
 
     // Only show shipping option section once there are shipping options.
     private void showShippingOptionSectionIfNecessary() {
-        if (!mRequestShipping || mShippingOptionsSectionInformation.isEmpty()
+        if (!mRequestShippingOption || mShippingOptionsSectionInformation.isEmpty()
                 || mPaymentContainerLayout.indexOfChild(mShippingOptionSection) != -1) {
             return;
         }
@@ -915,15 +918,14 @@
                            && mContactDetailsSectionInformation.getSelectedItem() != null);
         boolean shippingInfoOk = !mRequestShipping
                 || (mShippingAddressSectionInformation != null
-                           && mShippingAddressSectionInformation.getSelectedItem() != null
-                           && mShippingOptionsSectionInformation != null
+                           && mShippingAddressSectionInformation.getSelectedItem() != null);
+        boolean shippingOptionInfoOk = !mRequestShippingOption
+                || (mShippingOptionsSectionInformation != null
                            && mShippingOptionsSectionInformation.getSelectedItem() != null);
-        mPayButton.setEnabled(contactInfoOk && shippingInfoOk
+        mPayButton.setEnabled(contactInfoOk && shippingInfoOk && shippingOptionInfoOk
                 && mPaymentMethodSectionInformation != null
                 && mPaymentMethodSectionInformation.getSelectedItem() != null
-                && !mIsClientCheckingSelection
-                && !mIsEditingPaymentItem
-                && !mIsClosing);
+                && !mIsClientCheckingSelection && !mIsEditingPaymentItem && !mIsClosing);
         mReadyToPayNotifierForTest.run();
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PhotoPickerToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PhotoPickerToolbar.java
index 63472e69..03b6a31 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PhotoPickerToolbar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PhotoPickerToolbar.java
@@ -5,11 +5,11 @@
 package org.chromium.chrome.browser.photo_picker;
 
 import android.content.Context;
-import android.graphics.Color;
 import android.util.AttributeSet;
 import android.widget.Button;
 import android.widget.TextView;
 
+import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.widget.selection.SelectableListToolbar;
 
@@ -19,7 +19,6 @@
  * Handles toolbar functionality for the Photo Picker class.
  */
 public class PhotoPickerToolbar extends SelectableListToolbar<PickerBitmap> {
-    // TODO(finnur): Match style changes from Contacts Picker and delete blue_when_enabled.
     public PhotoPickerToolbar(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
@@ -33,8 +32,8 @@
 
         TextView up = (TextView) mNumberRollView.findViewById(R.id.up);
         TextView down = (TextView) mNumberRollView.findViewById(R.id.down);
-        up.setTextColor(Color.BLACK);
-        down.setTextColor(Color.BLACK);
+        ApiCompatibilityUtils.setTextAppearance(up, R.style.BlackHeadline2);
+        ApiCompatibilityUtils.setTextAppearance(down, R.style.BlackHeadline2);
     }
 
     @Override
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 069df25c..735849b 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -614,7 +614,7 @@
       <message name="IDS_CONTEXTUAL_SUGGESTIONS_DESCRIPTION" desc="Description of contextual suggestions, which tells the user what contextual suggestions does.">
         When you scroll up, show quick links to related pages. The URLs of pages you visit are sent to Google.
       </message>
-      <message name="IDS_CONTEXTUAL_SUGGESTIONS_DESCRIPTION_TOOLBAR_BUTTON" desc="Description of contextual suggestions, which tells the user that when they tap the ‘More like this’ button they will be shown links to pages related to their current page. An icon will be inserted into the string after ‘More like this’. Please ensure ‘More like this’ in this message matches the ‘More like this’ toolbar button.">
+      <message name="IDS_CONTEXTUAL_SUGGESTIONS_DESCRIPTION_TOOLBAR_BUTTON" desc="Description of contextual suggestions, which tells the user that when they tap the ‘More like this’ button they will be shown links to pages related to their current page. An icon will be inserted into the string after ‘More like this’. 'More like this' should match TC ID 1418444397960583910.">
         When you tap More like this <ph name="ICON">&lt;icon&gt; &lt;/icon&gt;</ph> in the address bar, show quick links to related pages. The URLs of pages you visit are sent to Google.
       </message>
       <message name="IDS_CONTEXTUAL_SUGGESTIONS_MESSAGE" desc="Message of contextual suggestions settings, which tells the user how to opt in contextual suggestions.">
@@ -2869,25 +2869,25 @@
       </message>
 
       <!-- Contextual suggestions strings -->
-      <message name="IDS_CONTEXTUAL_SUGGESTIONS_IN_PRODUCT_HELP" desc="The string displayed in an in-product help bubble when contextual suggestions are displayed for the first time. The bubble points to a toolbar button that shows suggestions related to the webpage the user is currently viewing when pressed.">
+      <message name="IDS_CONTEXTUAL_SUGGESTIONS_IN_PRODUCT_HELP" desc="The string displayed in an in-product help bubble when contextual suggestions are displayed for the first time. The bubble points to a toolbar button that shows suggestions related to the webpage the user is currently viewing when pressed. 'More like this' should match TC ID 1418444397960583910.">
         See more like this from Google
       </message>
-      <message name="IDS_CONTEXTUAL_SUGGESTIONS_IN_PRODUCT_HELP_ACCESSIBILITY" desc="The string displayed in an in-product help bubble when contextual suggestions are displayed for the first time and accessibility mode is enabled. The bubble points to a toolbar button that shows suggestions related to the webpage the user is currently viewing when pressed.">
+      <message name="IDS_CONTEXTUAL_SUGGESTIONS_IN_PRODUCT_HELP_ACCESSIBILITY" desc="The string displayed in an in-product help bubble when contextual suggestions are displayed for the first time and accessibility mode is enabled. The bubble points to a toolbar button that shows suggestions related to the webpage the user is currently viewing when pressed. 'More like this' should match TC ID 1418444397960583910.">
         See more like this from Google using the More Like This button
       </message>
-      <message name="IDS_CONTEXTUAL_SUGGESTIONS_BUTTON_DESCRIPTION" desc="The content description for a toolbar button that shows contextual suggestions related to the current web page when tapped. 'More like this' should be the same as in the contextual_suggestions_in_product_help string.">
+      <message name="IDS_CONTEXTUAL_SUGGESTIONS_BUTTON_DESCRIPTION" desc="The content description for a toolbar button that shows contextual suggestions related to the current web page when tapped. The suggestions show up in an overlay sheet. This string is also the default title for that sheet (see IDS_CONTEXTUAL_SUGGESTIONS_SHEET_OPENED_HALF for screenshot). 'More like this' is the name of the feature and is used in several other related strings.">
         More like this
       </message>
-      <message name="IDS_CONTEXTUAL_SUGGESTIONS_CLOSE_BUTTON_DESCRIPTION" desc="The content description for the contextual suggestions close button. Tapping the button closing the UI. 'More like this' should be the same as in the contextual_suggestions_in_product_help string.">
+      <message name="IDS_CONTEXTUAL_SUGGESTIONS_CLOSE_BUTTON_DESCRIPTION" desc="The content description for the contextual suggestions close button. Tapping the button closing the UI. 'More like this' should match TC ID 1418444397960583910.">
          Close more like this
       </message>
-      <message name="IDS_CONTEXTUAL_SUGGESTIONS_SHEET_OPENED_HALF" desc="Accessibility string read when the 'more like this' sheet is opened at half height. The sheet will occupy the bottom half the screen. 'More like this' should be the same as in the contextual_suggestions_in_product_help string">
+      <message name="IDS_CONTEXTUAL_SUGGESTIONS_SHEET_OPENED_HALF" desc="Accessibility string read when the 'more like this' sheet is opened at half height. The sheet will occupy the bottom half the screen. 'More like this' should match TC ID 1418444397960583910.">
          More like this opened at half height
       </message>
-      <message name="IDS_CONTEXTUAL_SUGGESTIONS_SHEET_OPENED_FULL" desc="Accessibility string read when the 'more like this' sheet is opened at full height. The sheet will occupy the entire screen. 'More like this' should be the same as in the contextual_suggestions_in_product_help string">
+      <message name="IDS_CONTEXTUAL_SUGGESTIONS_SHEET_OPENED_FULL" desc="Accessibility string read when the 'more like this' sheet is opened at full height. The sheet will occupy the entire screen. 'More like this' should match TC ID 1418444397960583910.">
          More like this opened at full height
       </message>
-      <message name="IDS_CONTEXTUAL_SUGGESTIONS_SHEET_CLOSED" desc="Accessibility string read when the'more like this' sheet is closed. 'More like this' should be the same as in the contextual_suggestions_in_product_help string">
+      <message name="IDS_CONTEXTUAL_SUGGESTIONS_SHEET_CLOSED" desc="Accessibility string read when the 'more like this' sheet is closed. 'More like this' should match TC ID 1418444397960583910.">
          More like this closed
       </message>
 
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 1c0457a..4273bb9d 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -1108,6 +1108,7 @@
   "java/src/org/chromium/chrome/browser/payments/AutofillContact.java",
   "java/src/org/chromium/chrome/browser/payments/AutofillPaymentApp.java",
   "java/src/org/chromium/chrome/browser/payments/AutofillPaymentInstrument.java",
+  "java/src/org/chromium/chrome/browser/payments/AutofillAssistantPaymentRequest.java",
   "java/src/org/chromium/chrome/browser/payments/BasicCardUtils.java",
   "java/src/org/chromium/chrome/browser/payments/CardEditor.java",
   "java/src/org/chromium/chrome/browser/payments/ContactEditor.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationService2Test.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationService2Test.java
index c379ac8..9bd5190 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationService2Test.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationService2Test.java
@@ -25,6 +25,7 @@
 import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate;
 import org.chromium.base.test.params.ParameterSet;
 import org.chromium.base.test.params.ParameterizedRunner;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate;
@@ -230,6 +231,7 @@
     @SmallTest
     @UiThreadTest
     @Feature({"Download"})
+    @DisabledTest(message = "https://crbug.com/837298")
     public void testResumeAllPendingDownloads() {
         // Queue a few pending downloads.
         mDownloadSharedPreferenceHelper.addOrReplaceSharedPreferenceEntry(
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index 33ff630..c4d92156 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-71.0.3574.0_rc-r1.afdo.bz2
\ No newline at end of file
+chromeos-chrome-amd64-71.0.3575.0_rc-r1.afdo.bz2
\ No newline at end of file
diff --git a/chrome/app/vector_icons/generic_stop.icon b/chrome/app/vector_icons/generic_stop.icon
index 43d5372..f0cca542 100644
--- a/chrome/app/vector_icons/generic_stop.icon
+++ b/chrome/app/vector_icons/generic_stop.icon
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// This file cannot be named stop.icon because that expands to
+// kStopIcon which is a predefined constant in OSX's Dialogs.h
+
 CANVAS_DIMENSIONS, 20,
 ROUND_RECT, 7, 7, 6, 6, 0,
 NEW_PATH,
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.cc b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
index f2019825..400c4fa 100644
--- a/chrome/browser/android/autofill_assistant/ui_controller_android.cc
+++ b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
@@ -149,6 +149,35 @@
   std::move(address_or_card_callback_).Run(guid);
 }
 
+void UiControllerAndroid::OnGetPaymentInformation(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& jcaller,
+    jboolean jsucceed,
+    const base::android::JavaParamRef<jstring>& jcard_guid,
+    const base::android::JavaParamRef<jstring>& jaddress_guid,
+    const base::android::JavaParamRef<jstring>& jpayer_name,
+    const base::android::JavaParamRef<jstring>& jpayer_phone,
+    const base::android::JavaParamRef<jstring>& jpayer_email) {
+  DCHECK(get_payment_information_callback_);
+
+  std::unique_ptr<PaymentInformation> payment_info =
+      std::make_unique<PaymentInformation>();
+  payment_info->succeed = jsucceed;
+  if (payment_info->succeed) {
+    base::android::ConvertJavaStringToUTF8(env, jcard_guid,
+                                           &payment_info->card_guid);
+    base::android::ConvertJavaStringToUTF8(env, jaddress_guid,
+                                           &payment_info->address_guid);
+    base::android::ConvertJavaStringToUTF8(env, jpayer_name,
+                                           &payment_info->payer_name);
+    base::android::ConvertJavaStringToUTF8(env, jpayer_phone,
+                                           &payment_info->payer_phone);
+    base::android::ConvertJavaStringToUTF8(env, jpayer_email,
+                                           &payment_info->payer_email);
+  }
+  std::move(get_payment_information_callback_).Run(std::move(payment_info));
+}
+
 void UiControllerAndroid::ChooseAddress(
     base::OnceCallback<void(const std::string&)> callback) {
   DCHECK(!address_or_card_callback_);
@@ -167,6 +196,19 @@
       env, java_autofill_assistant_ui_controller_);
 }
 
+void UiControllerAndroid::GetPaymentInformation(
+    payments::mojom::PaymentOptionsPtr payment_options,
+    base::OnceCallback<void(std::unique_ptr<PaymentInformation>)> callback) {
+  DCHECK(!get_payment_information_callback_);
+  get_payment_information_callback_ = std::move(callback);
+  Java_AutofillAssistantUiController_onRequestPaymentInformation(
+      AttachCurrentThread(), java_autofill_assistant_ui_controller_,
+      payment_options->request_shipping, payment_options->request_payer_name,
+      payment_options->request_payer_phone,
+      payment_options->request_payer_email,
+      static_cast<int>(payment_options->shipping_type));
+}
+
 void UiControllerAndroid::HideDetails() {
   Java_AutofillAssistantUiController_onHideDetails(
       AttachCurrentThread(), java_autofill_assistant_ui_controller_);
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.h b/chrome/browser/android/autofill_assistant/ui_controller_android.h
index f1b2d8a..aaf1f2d 100644
--- a/chrome/browser/android/autofill_assistant/ui_controller_android.h
+++ b/chrome/browser/android/autofill_assistant/ui_controller_android.h
@@ -36,6 +36,10 @@
       base::OnceCallback<void(const std::string&)> callback) override;
   void ChooseCard(
       base::OnceCallback<void(const std::string&)> callback) override;
+  void GetPaymentInformation(
+      payments::mojom::PaymentOptionsPtr payment_options,
+      base::OnceCallback<void(std::unique_ptr<PaymentInformation>)> callback)
+      override;
   void HideDetails() override;
   void ShowDetails(const DetailsProto& details) override;
 
@@ -58,6 +62,15 @@
   void OnCardSelected(JNIEnv* env,
                       const base::android::JavaParamRef<jobject>& jcaller,
                       const base::android::JavaParamRef<jstring>& jcard_guid);
+  void OnGetPaymentInformation(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& jcaller,
+      jboolean jsucceed,
+      const base::android::JavaParamRef<jstring>& jcard_guid,
+      const base::android::JavaParamRef<jstring>& jaddress_guid,
+      const base::android::JavaParamRef<jstring>& jpayer_name,
+      const base::android::JavaParamRef<jstring>& jpayer_phone,
+      const base::android::JavaParamRef<jstring>& jpayer_email);
 
  private:
   // Java-side AutofillAssistantUiController object.
@@ -67,6 +80,8 @@
   UiDelegate* ui_delegate_;
 
   base::OnceCallback<void(const std::string&)> address_or_card_callback_;
+  base::OnceCallback<void(std::unique_ptr<PaymentInformation>)>
+      get_payment_information_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(UiControllerAndroid);
 };
diff --git a/chrome/browser/android/explore_sites/explore_sites_service_impl.h b/chrome/browser/android/explore_sites/explore_sites_service_impl.h
index dcfcfd5..1640944 100644
--- a/chrome/browser/android/explore_sites/explore_sites_service_impl.h
+++ b/chrome/browser/android/explore_sites/explore_sites_service_impl.h
@@ -35,6 +35,7 @@
 
   // ExploreSitesService implementation.
   void GetCatalog(CatalogCallback callback) override;
+
   void GetCategoryImage(int category_id,
                         int pixel_size,
                         BitmapCallback callback) override;
diff --git a/chrome/browser/android/explore_sites/image_helper.cc b/chrome/browser/android/explore_sites/image_helper.cc
index 5f88a0bf..7b417c4 100644
--- a/chrome/browser/android/explore_sites/image_helper.cc
+++ b/chrome/browser/android/explore_sites/image_helper.cc
@@ -176,11 +176,12 @@
 
   DVLOG(1) << "pixel_size_: " << pixel_size_;
   int icon_padding_pixel_size = pixel_size_ / kIconPaddingScale;
-  int size = pixel_size_ + icon_padding_pixel_size;
-  DVLOG(1) << "size: " << size;
+
+  // Offset to write icons out of frame due to padding.
+  int icon_write_offset = icon_padding_pixel_size / 2;
 
   SkBitmap composite_bitmap;
-  SkImageInfo image_info = bitmaps_[0].info().makeWH(size, size);
+  SkImageInfo image_info = bitmaps_[0].info().makeWH(pixel_size_, pixel_size_);
   composite_bitmap.setInfo(image_info);
   composite_bitmap.allocPixels();
   composite_bitmap.eraseColor(gfx::kGoogleGrey100);  // Set background to grey.
@@ -195,9 +196,10 @@
       if (scaledBitmap.empty()) {
         return nullptr;
       }
-      composite_bitmap.writePixels(scaledBitmap.pixmap(),
-                                   (icon_size + icon_padding_pixel_size) / 2,
-                                   (icon_size + icon_padding_pixel_size) / 2);
+      composite_bitmap.writePixels(
+          scaledBitmap.pixmap(),
+          ((icon_size + icon_padding_pixel_size) / 2) - icon_write_offset,
+          ((icon_size + icon_padding_pixel_size) / 2) - icon_write_offset);
       break;
     }
     case 2: {
@@ -207,9 +209,10 @@
         if (scaledBitmap.empty()) {
           return nullptr;
         }
-        composite_bitmap.writePixels(scaledBitmap.pixmap(),
-                                     i * (icon_size + icon_padding_pixel_size),
-                                     (icon_size + icon_padding_pixel_size) / 2);
+        composite_bitmap.writePixels(
+            scaledBitmap.pixmap(),
+            (i * (icon_size + icon_padding_pixel_size)) - icon_write_offset,
+            ((icon_size + icon_padding_pixel_size) / 2) - icon_write_offset);
       }
       break;
     }
@@ -222,18 +225,20 @@
         }
         switch (i) {
           case 0:
-            composite_bitmap.writePixels(scaledBitmap.pixmap(), 0, 0);
+            composite_bitmap.writePixels(
+                scaledBitmap.pixmap(), -icon_write_offset, -icon_write_offset);
             break;
           case 1:
-            composite_bitmap.writePixels(scaledBitmap.pixmap(),
-                                         (icon_size + icon_padding_pixel_size),
-                                         0);
+            composite_bitmap.writePixels(
+                scaledBitmap.pixmap(),
+                (icon_size + icon_padding_pixel_size) - icon_write_offset,
+                -icon_write_offset);
             break;
           default:
             composite_bitmap.writePixels(
                 scaledBitmap.pixmap(),
-                (icon_size + icon_padding_pixel_size) / 2,
-                (icon_size + icon_padding_pixel_size));
+                ((icon_size + icon_padding_pixel_size) / 2) - icon_write_offset,
+                (icon_size + icon_padding_pixel_size) - icon_write_offset);
             break;
         }
       }
@@ -249,8 +254,9 @@
             return nullptr;
           }
           composite_bitmap.writePixels(
-              scaledBitmap.pixmap(), j * (icon_size + icon_padding_pixel_size),
-              i * (icon_size + icon_padding_pixel_size));
+              scaledBitmap.pixmap(),
+              (j * (icon_size + icon_padding_pixel_size)) - icon_write_offset,
+              (i * (icon_size + icon_padding_pixel_size)) - icon_write_offset);
         }
       }
       break;
diff --git a/chrome/browser/android/explore_sites/image_helper.h b/chrome/browser/android/explore_sites/image_helper.h
index c410c855..5166dad7 100644
--- a/chrome/browser/android/explore_sites/image_helper.h
+++ b/chrome/browser/android/explore_sites/image_helper.h
@@ -32,6 +32,7 @@
       BitmapCallback callback,
       EncodedImageList images,
       std::unique_ptr<service_manager::Connector> connector = nullptr);
+
   // Compose a category icon containing [1 - 4] site icons and return via
   // |callback|.
   void ComposeCategoryImage(
diff --git a/chrome/browser/android/explore_sites/image_helper_unittest.cc b/chrome/browser/android/explore_sites/image_helper_unittest.cc
index 1879177..7b23998 100644
--- a/chrome/browser/android/explore_sites/image_helper_unittest.cc
+++ b/chrome/browser/android/explore_sites/image_helper_unittest.cc
@@ -35,14 +35,12 @@
 };
 
 const int kIconSize = 48;
-const int kPaddingScale = 8;
-const int kCompositeSize = kIconSize + (kIconSize / kPaddingScale);
 
 // Bounds for icon size of 48.
-const int kLowerBoundCenter = 14;
-const int kUpperBoundCenter = 39;
-const int kLowerBoundCorner = 24;
-const int kUpperBoundCorner = 29;
+const int kLowerBoundCenter = 11;
+const int kUpperBoundCenter = 36;
+const int kLowerBoundCorner = 21;
+const int kUpperBoundCorner = 26;
 
 class ExploreSitesImageHelperTest : public testing::Test {
  public:
@@ -57,7 +55,6 @@
   ~ExploreSitesImageHelperTest() override{};
 
   EncodedImageList GetEncodedImageList(int num_icons);
-
   BitmapCallback StoreBitmap() {
     return base::BindLambdaForTesting([&](std::unique_ptr<SkBitmap> bitmap) {
       last_bitmap_list.push_back(std::move(bitmap));
@@ -144,8 +141,8 @@
 
   ASSERT_NE(nullptr, last_bitmap_list[0]);
   EXPECT_FALSE(last_bitmap_list[0]->isNull());
-  EXPECT_EQ(last_bitmap_list[0]->width(), kCompositeSize);
-  EXPECT_EQ(last_bitmap_list[0]->height(), kCompositeSize);
+  EXPECT_EQ(last_bitmap_list[0]->width(), kIconSize);
+  EXPECT_EQ(last_bitmap_list[0]->height(), kIconSize);
 
   // One square in the center. If inside the bounds, the color should be 0.
   // If outside of the bounds the color should be kGoogleGrey100.
@@ -171,8 +168,8 @@
 
   ASSERT_NE(nullptr, last_bitmap_list[0]);
   EXPECT_FALSE(last_bitmap_list[0]->isNull());
-  EXPECT_EQ(last_bitmap_list[0]->width(), kCompositeSize);
-  EXPECT_EQ(last_bitmap_list[0]->height(), kCompositeSize);
+  EXPECT_EQ(last_bitmap_list[0]->width(), kIconSize);
+  EXPECT_EQ(last_bitmap_list[0]->height(), kIconSize);
 
   // Two squares, side by side. If inside the bounds, the color should be 0.
   // If outside of the bounds the color should be kGoogleGrey100.
@@ -197,8 +194,8 @@
 
   ASSERT_NE(nullptr, last_bitmap_list[0]);
   EXPECT_FALSE(last_bitmap_list[0]->isNull());
-  EXPECT_EQ(last_bitmap_list[0]->width(), kCompositeSize);
-  EXPECT_EQ(last_bitmap_list[0]->height(), kCompositeSize);
+  EXPECT_EQ(last_bitmap_list[0]->width(), kIconSize);
+  EXPECT_EQ(last_bitmap_list[0]->height(), kIconSize);
 
   // Three squares, two on top and one on bottom. If inside the bounds, the
   // color should be 0. If outside of the bounds the color should be
@@ -226,8 +223,8 @@
 
   ASSERT_NE(nullptr, last_bitmap_list[0]);
   EXPECT_FALSE(last_bitmap_list[0]->isNull());
-  EXPECT_EQ(last_bitmap_list[0]->width(), kCompositeSize);
-  EXPECT_EQ(last_bitmap_list[0]->height(), kCompositeSize);
+  EXPECT_EQ(last_bitmap_list[0]->width(), kIconSize);
+  EXPECT_EQ(last_bitmap_list[0]->height(), kIconSize);
 
   // Four squares in each corner. If inside the bounds, the color should be 0.
   // If outside of the bounds the color should be kGoogleGrey100.
diff --git a/chrome/browser/extensions/api/debugger/debugger_api.cc b/chrome/browser/extensions/api/debugger/debugger_api.cc
index b610acb5..b71a51f 100644
--- a/chrome/browser/extensions/api/debugger/debugger_api.cc
+++ b/chrome/browser/extensions/api/debugger/debugger_api.cc
@@ -149,6 +149,7 @@
                            bool is_webui) override;
   bool MayAttachToBrowser() override;
   bool MayDiscoverTargets() override;
+  bool MayAffectLocalFiles() override;
 
  private:
   using PendingRequests =
@@ -386,6 +387,10 @@
   return false;
 }
 
+bool ExtensionDevToolsClientHost::MayAffectLocalFiles() {
+  return false;
+}
+
 // DebuggerFunction -----------------------------------------------------------
 
 DebuggerFunction::DebuggerFunction()
diff --git a/chrome/browser/extensions/api/streams_private/streams_private_api.cc b/chrome/browser/extensions/api/streams_private/streams_private_api.cc
index 1cb0524..9e81f0a 100644
--- a/chrome/browser/extensions/api/streams_private/streams_private_api.cc
+++ b/chrome/browser/extensions/api/streams_private/streams_private_api.cc
@@ -4,59 +4,22 @@
 
 #include "chrome/browser/extensions/api/streams_private/streams_private_api.h"
 
-#include <limits.h>
 #include <utility>
 
-#include "base/lazy_instance.h"
-#include "base/values.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/prerender/prerender_contents.h"
-#include "chrome/common/extensions/api/streams_private.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/stream_handle.h"
 #include "content/public/browser/stream_info.h"
 #include "content/public/browser/web_contents.h"
-#include "extensions/browser/event_router.h"
-#include "extensions/browser/extension_function_registry.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/guest_view/mime_handler_view/mime_handler_stream_manager.h"
 #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
 #include "extensions/common/manifest_handlers/mime_types_handler.h"
-#include "net/http/http_response_headers.h"
 
 namespace extensions {
-namespace {
-
-StreamsPrivateAPI* GetStreamsPrivateAPI(content::BrowserContext* context) {
-  return StreamsPrivateAPI::GetFactoryInstance()->Get(context);
-}
-
-void CreateResponseHeadersDictionary(const net::HttpResponseHeaders* headers,
-                                     base::DictionaryValue* result) {
-  if (!headers)
-    return;
-
-  size_t iter = 0;
-  std::string header_name;
-  std::string header_value;
-  while (headers->EnumerateHeaderLines(&iter, &header_name, &header_value)) {
-    base::Value* existing_value = NULL;
-    if (result->Get(header_name, &existing_value)) {
-      *existing_value =
-          base::Value(existing_value->GetString() + ", " + header_value);
-    } else {
-      result->SetString(header_name, header_value);
-    }
-  }
-}
-
-}  // namespace
-
-namespace streams_private = api::streams_private;
 
 void StreamsPrivateAPI::SendExecuteMimeTypeHandlerEvent(
-    int64_t expected_content_size,
     const std::string& extension_id,
     const std::string& view_id,
     bool embedded,
@@ -90,9 +53,6 @@
   }
 
   auto* browser_context = web_contents->GetBrowserContext();
-  StreamsPrivateAPI* streams_private = GetStreamsPrivateAPI(browser_context);
-  if (!streams_private)
-    return;
 
   const Extension* extension = ExtensionRegistry::Get(browser_context)
                                    ->enabled_extensions()
@@ -101,119 +61,20 @@
     return;
 
   MimeTypesHandler* handler = MimeTypesHandler::GetHandler(extension);
+  if (!handler->HasPlugin())
+    return;
+
   // If the mime handler uses MimeHandlerViewGuest, the MimeHandlerViewGuest
-  // will take ownership of the stream. Otherwise, store the stream handle in
-  // |streams_| and fire an event notifying the extension.
-  if (handler->HasPlugin()) {
-    GURL handler_url(Extension::GetBaseURLFromExtensionId(extension_id).spec() +
-                     handler->handler_url());
-    int tab_id = ExtensionTabUtil::GetTabId(web_contents);
-    std::unique_ptr<StreamContainer> stream_container(new StreamContainer(
-        std::move(stream), tab_id, embedded, handler_url, extension_id,
-        std::move(transferrable_loader), original_url));
-    MimeHandlerStreamManager::Get(browser_context)
-        ->AddStream(view_id, std::move(stream_container), frame_tree_node_id,
-                    render_process_id, render_frame_id);
-    return;
-  }
-
-  if (!stream) {
-    NOTREACHED();
-    return;
-  }
-
-  // Create the event's arguments value.
-  streams_private::StreamInfo info;
-  info.mime_type = stream->mime_type;
-  info.original_url = stream->original_url.spec();
-  info.stream_url = stream->handle->GetURL().spec();
-  info.tab_id = ExtensionTabUtil::GetTabId(web_contents);
-  info.embedded = embedded;
-
-  if (!view_id.empty()) {
-    info.view_id.reset(new std::string(view_id));
-  }
-
-  int size = -1;
-  if (expected_content_size <= INT_MAX)
-    size = expected_content_size;
-  info.expected_content_size = size;
-
-  CreateResponseHeadersDictionary(stream->response_headers.get(),
-                                  &info.response_headers.additional_properties);
-
-  std::unique_ptr<Event> event(
-      new Event(events::STREAMS_PRIVATE_ON_EXECUTE_MIME_TYPE_HANDLER,
-                streams_private::OnExecuteMimeTypeHandler::kEventName,
-                streams_private::OnExecuteMimeTypeHandler::Create(info)));
-
-  EventRouter::Get(browser_context)
-      ->DispatchEventToExtension(extension_id, std::move(event));
-
-  GURL url = stream->handle->GetURL();
-  streams_private->streams_[extension_id][url] = std::move(stream->handle);
-}
-
-StreamsPrivateAPI::StreamsPrivateAPI(content::BrowserContext* context)
-    : browser_context_(context),
-      extension_registry_observer_(this),
-      weak_ptr_factory_(this) {
-  extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
-}
-
-StreamsPrivateAPI::~StreamsPrivateAPI() {}
-
-void StreamsPrivateAPI::AbortStream(const std::string& extension_id,
-                                    const GURL& stream_url,
-                                    const base::Closure& callback) {
-  auto extension_it = streams_.find(extension_id);
-  if (extension_it == streams_.end()) {
-    callback.Run();
-    return;
-  }
-
-  StreamMap::mapped_type* url_map = &extension_it->second;
-  auto url_it = url_map->find(stream_url);
-  if (url_it == url_map->end()) {
-    callback.Run();
-    return;
-  }
-
-  url_it->second->AddCloseListener(callback);
-  url_map->erase(url_it);
-}
-
-void StreamsPrivateAPI::OnExtensionUnloaded(
-    content::BrowserContext* browser_context,
-    const Extension* extension,
-    UnloadedExtensionReason reason) {
-  streams_.erase(extension->id());
-}
-
-StreamsPrivateAbortFunction::StreamsPrivateAbortFunction() {
-}
-
-ExtensionFunction::ResponseAction StreamsPrivateAbortFunction::Run() {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &stream_url_));
-  GetStreamsPrivateAPI(browser_context())
-      ->AbortStream(extension_id(), GURL(stream_url_),
-                    base::Bind(&StreamsPrivateAbortFunction::OnClose, this));
-  return RespondLater();
-}
-
-void StreamsPrivateAbortFunction::OnClose() {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  Respond(NoArguments());
-}
-
-static base::LazyInstance<BrowserContextKeyedAPIFactory<StreamsPrivateAPI>>::
-    DestructorAtExit g_streams_private_api_factory = LAZY_INSTANCE_INITIALIZER;
-
-// static
-BrowserContextKeyedAPIFactory<StreamsPrivateAPI>*
-StreamsPrivateAPI::GetFactoryInstance() {
-  return g_streams_private_api_factory.Pointer();
+  // will take ownership of the stream.
+  GURL handler_url(Extension::GetBaseURLFromExtensionId(extension_id).spec() +
+                   handler->handler_url());
+  int tab_id = ExtensionTabUtil::GetTabId(web_contents);
+  std::unique_ptr<StreamContainer> stream_container(new StreamContainer(
+      std::move(stream), tab_id, embedded, handler_url, extension_id,
+      std::move(transferrable_loader), original_url));
+  MimeHandlerStreamManager::Get(browser_context)
+      ->AddStream(view_id, std::move(stream_container), frame_tree_node_id,
+                  render_process_id, render_frame_id);
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/streams_private/streams_private_api.h b/chrome/browser/extensions/api/streams_private/streams_private_api.h
index bf1e7b9..32908bc 100644
--- a/chrome/browser/extensions/api/streams_private/streams_private_api.h
+++ b/chrome/browser/extensions/api/streams_private/streams_private_api.h
@@ -5,44 +5,36 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_STREAMS_PRIVATE_STREAMS_PRIVATE_API_H_
 #define CHROME_BROWSER_EXTENSIONS_API_STREAMS_PRIVATE_STREAMS_PRIVATE_API_H_
 
-#include <stdint.h>
-
-#include <map>
+#include <memory>
 #include <string>
 
-#include "base/scoped_observer.h"
+#include "base/macros.h"
 #include "content/public/common/transferrable_url_loader.mojom.h"
-#include "extensions/browser/browser_context_keyed_api_factory.h"
-#include "extensions/browser/extension_function.h"
-#include "extensions/browser/extension_registry_observer.h"
 
 namespace content {
-class BrowserContext;
-class StreamHandle;
 struct StreamInfo;
 }
 
 namespace extensions {
-class ExtensionRegistry;
 
-class StreamsPrivateAPI : public BrowserContextKeyedAPI,
-                          public ExtensionRegistryObserver {
+// TODO(devlin): This is now only used for the MimeTypesHandler API. We should
+// rename and move it to make that clear. https://crbug.com/890401.
+class StreamsPrivateAPI {
  public:
   // Send the onExecuteMimeTypeHandler event to |extension_id|.
-  // The data for the document will be readable from |stream|, and
-  // should be |expected_content_size| bytes long. If the viewer is being opened
-  // in a BrowserPlugin, specify a non-empty |view_id| of the plugin. |embedded|
-  // should be set to whether the document is embedded within another document.
-  // The |frame_tree_node_id| parameter is used for PlzNavigate for the top
-  // level plugins case. (PDF, etc). If this parameter has a valid value then
-  // it overrides the |render_process_id| and |render_frame_id| parameters.
-  // The |render_process_id| is the id of the renderer process.
-  // The |render_frame_id| is the routing id of the RenderFrameHost.
+  // The data for the document will be readable from |stream|. If the viewer is
+  // being opened in a BrowserPlugin, specify a non-empty |view_id| of the
+  // plugin. |embedded| should be set to whether the document is embedded
+  // within another document. The |frame_tree_node_id| parameter is used for
+  // PlzNavigate for the top level plugins case. (PDF, etc). If this parameter
+  // has a valid value then it overrides the |render_process_id| and
+  // |render_frame_id| parameters. The |render_process_id| is the id of the
+  // renderer process. The |render_frame_id| is the routing id of the
+  // RenderFrameHost.
   //
   // If the network service is not enabled, |stream| is used; otherwise,
   // |transferrable_loader| and |original_url| are used instead.
   static void SendExecuteMimeTypeHandlerEvent(
-      int64_t expected_content_size,
       const std::string& extension_id,
       const std::string& view_id,
       bool embedded,
@@ -52,61 +44,6 @@
       std::unique_ptr<content::StreamInfo> stream,
       content::mojom::TransferrableURLLoaderPtr transferrable_loader,
       const GURL& original_url);
-
-  explicit StreamsPrivateAPI(content::BrowserContext* context);
-  ~StreamsPrivateAPI() override;
-
-  void AbortStream(const std::string& extension_id,
-                   const GURL& stream_url,
-                   const base::Closure& callback);
-
-  // BrowserContextKeyedAPI implementation.
-  static BrowserContextKeyedAPIFactory<StreamsPrivateAPI>* GetFactoryInstance();
-
- private:
-  friend class BrowserContextKeyedAPIFactory<StreamsPrivateAPI>;
-
-  // ExtensionRegistryObserver implementation.
-  void OnExtensionUnloaded(content::BrowserContext* browser_context,
-                           const Extension* extension,
-                           UnloadedExtensionReason reason) override;
-
-  // BrowserContextKeyedAPI implementation.
-  static const char* service_name() {
-    return "StreamsPrivateAPI";
-  }
-  static const bool kServiceIsNULLWhileTesting = true;
-  static const bool kServiceRedirectedInIncognito = true;
-
-  content::BrowserContext* const browser_context_;
-  using StreamMap =
-      std::map<std::string,
-               std::map<GURL, std::unique_ptr<content::StreamHandle>>>;
-  StreamMap streams_;
-
-  // Listen to extension unloaded notifications.
-  ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver>
-      extension_registry_observer_;
-
-  base::WeakPtrFactory<StreamsPrivateAPI> weak_ptr_factory_;
-
-};
-
-class StreamsPrivateAbortFunction : public UIThreadExtensionFunction {
- public:
-  StreamsPrivateAbortFunction();
-  DECLARE_EXTENSION_FUNCTION("streamsPrivate.abort", STREAMSPRIVATE_ABORT)
-
- protected:
-  ~StreamsPrivateAbortFunction() override {}
-
-  // ExtensionFunction:
-  ExtensionFunction::ResponseAction Run() override;
-
- private:
-  void OnClose();
-
-  std::string stream_url_;
 };
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/streams_private/streams_private_apitest.cc b/chrome/browser/extensions/api/streams_private/streams_private_apitest.cc
deleted file mode 100644
index dc572510..0000000
--- a/chrome/browser/extensions/api/streams_private/streams_private_apitest.cc
+++ /dev/null
@@ -1,488 +0,0 @@
-// Copyright (c) 2012 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 <utility>
-
-#include "base/command_line.h"
-#include "base/run_loop.h"
-#include "base/threading/thread_restrictions.h"
-#include "build/build_config.h"
-#include "chrome/browser/download/download_prefs.h"
-#include "chrome/browser/extensions/extension_apitest.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/extensions/api/streams_private.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/test/base/ui_test_utils.h"
-#include "components/download/public/common/download_item.h"
-#include "components/prefs/pref_service.h"
-#include "content/public/browser/download_manager.h"
-#include "content/public/browser/download_request_utils.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/test/download_test_observer.h"
-#include "extensions/browser/event_router.h"
-#include "extensions/browser/extension_system.h"
-#include "extensions/common/manifest_handlers/mime_types_handler.h"
-#include "extensions/test/result_catcher.h"
-#include "net/dns/mock_host_resolver.h"
-#include "net/test/embedded_test_server/embedded_test_server.h"
-#include "net/test/embedded_test_server/http_request.h"
-#include "net/test/embedded_test_server/http_response.h"
-#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
-#include "services/network/public/cpp/features.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-using content::BrowserContext;
-using content::BrowserThread;
-using content::DownloadManager;
-using content::WebContents;
-using download::DownloadItem;
-using download::DownloadUrlParameters;
-using extensions::Event;
-using extensions::ExtensionSystem;
-using extensions::ResultCatcher;
-using net::test_server::BasicHttpResponse;
-using net::test_server::HttpRequest;
-using net::test_server::HttpResponse;
-using testing::_;
-
-namespace streams_private = extensions::api::streams_private;
-
-namespace {
-
-// Test server's request handler.
-// Returns response that should be sent by the test server.
-std::unique_ptr<HttpResponse> HandleRequest(const HttpRequest& request) {
-  std::unique_ptr<BasicHttpResponse> response(new BasicHttpResponse());
-
-  // For relative path "/doc_path.doc", return success response with MIME type
-  // "application/msword".
-  if (request.relative_url == "/doc_path.doc") {
-    response->set_code(net::HTTP_OK);
-    response->set_content_type("application/msword");
-    return std::move(response);
-  }
-
-  // For relative path "/spreadsheet_path.xls", return success response with
-  // MIME type "application/xls".
-  if (request.relative_url == "/spreadsheet_path.xls") {
-    response->set_code(net::HTTP_OK);
-    response->set_content_type("application/msexcel");
-    // Test that multiple headers with the same name are merged.
-    response->AddCustomHeader("Test-Header", "part1");
-    response->AddCustomHeader("Test-Header", "part2");
-    return std::move(response);
-  }
-
-  // For relative path "/text_path_attch.txt", return success response with
-  // MIME type "text/plain" and content "txt content". Also, set content
-  // disposition to be attachment.
-  if (request.relative_url == "/text_path_attch.txt") {
-    response->set_code(net::HTTP_OK);
-    response->set_content("txt content");
-    response->set_content_type("text/plain");
-    response->AddCustomHeader("Content-Disposition",
-                              "attachment; filename=test_path.txt");
-    return std::move(response);
-  }
-
-  // For relative path "/test_path_attch.txt", return success response with
-  // MIME type "text/plain" and content "txt content".
-  if (request.relative_url == "/text_path.txt") {
-    response->set_code(net::HTTP_OK);
-    response->set_content("txt content");
-    response->set_content_type("text/plain");
-    return std::move(response);
-  }
-
-  // A random HTML file to navigate to.
-  if (request.relative_url == "/index.html") {
-    response->set_code(net::HTTP_OK);
-    response->set_content("html content");
-    response->set_content_type("text/html");
-    return std::move(response);
-  }
-
-  // RTF files for testing chrome.streamsPrivate.abort().
-  if (request.relative_url == "/abort.rtf" ||
-      request.relative_url == "/no_abort.rtf") {
-    response->set_code(net::HTTP_OK);
-    response->set_content_type("application/rtf");
-    return std::move(response);
-  }
-
-  // Respond to /favicon.ico for navigating to the page.
-  if (request.relative_url == "/favicon.ico") {
-    response->set_code(net::HTTP_NOT_FOUND);
-    return std::move(response);
-  }
-
-  // No other requests should be handled in the tests.
-  EXPECT_TRUE(false) << "NOTREACHED!";
-  response->set_code(net::HTTP_NOT_FOUND);
-  return std::move(response);
-}
-
-// Tests to verify that resources are correctly intercepted by
-// StreamsResourceThrottle.
-// The test extension expects the resources that should be handed to the
-// extension to have MIME type 'application/msword' and the resources that
-// should be downloaded by the browser to have MIME type 'text/plain'.
-class StreamsPrivateApiTest : public extensions::ExtensionApiTest {
- public:
-  StreamsPrivateApiTest() {}
-
-  ~StreamsPrivateApiTest() override {}
-
-  void SetUpOnMainThread() override {
-    // Init test server.
-    test_server_.reset(new net::EmbeddedTestServer);
-    test_server_->RegisterRequestHandler(base::Bind(&HandleRequest));
-    ASSERT_TRUE(test_server_->Start());
-    host_resolver()->AddRule("*", "127.0.0.1");
-    extensions::ExtensionApiTest::SetUpOnMainThread();
-  }
-
-  void TearDownOnMainThread() override {
-    // Tear down the test server.
-    EXPECT_TRUE(test_server_->ShutdownAndWaitUntilComplete());
-    test_server_.reset();
-    extensions::ExtensionApiTest::TearDownOnMainThread();
-  }
-
-  void InitializeDownloadSettings() {
-    ASSERT_TRUE(browser());
-
-    // Ensure there are no prompts for download during the test.
-    browser()->profile()->GetPrefs()->SetBoolean(
-        prefs::kPromptForDownload, false);
-
-    DownloadManager* manager = GetDownloadManager();
-    DownloadPrefs::FromDownloadManager(manager)->ResetAutoOpen();
-  }
-
-  // Sends onExecuteContentHandler event with the MIME type "test/done" to the
-  // test extension.
-  // The test extension calls 'chrome.test.notifySuccess' when it receives the
-  // event with the "test/done" MIME type (unless the 'chrome.test.notifyFail'
-  // has already been called).
-  void SendDoneEvent() {
-    streams_private::StreamInfo info;
-    info.mime_type = "test/done";
-    info.original_url = "http://foo";
-    info.stream_url = "blob://bar";
-    info.tab_id = 10;
-    info.expected_content_size = 20;
-
-    std::unique_ptr<Event> event(new Event(
-        extensions::events::STREAMS_PRIVATE_ON_EXECUTE_MIME_TYPE_HANDLER,
-        streams_private::OnExecuteMimeTypeHandler::kEventName,
-        streams_private::OnExecuteMimeTypeHandler::Create(info)));
-
-    extensions::EventRouter::Get(browser()->profile())
-        ->DispatchEventToExtension(test_extension_id_, std::move(event));
-  }
-
-  // Loads the test extension and set's up its file_browser_handler to handle
-  // 'application/msword' and 'text/plain' MIME types.
-  // The extension will notify success when it detects an event with the MIME
-  // type 'application/msword' and notify fail when it detects an event with the
-  // MIME type 'text/plain'.
-  const extensions::Extension* LoadTestExtension() {
-    // The test extension id is set by the key value in the manifest.
-    test_extension_id_ = "oickdpebdnfbgkcaoklfcdhjniefkcji";
-
-    const extensions::Extension* extension = LoadExtension(
-        test_data_dir_.AppendASCII("streams_private/handle_mime_type"));
-    if (!extension)
-      return NULL;
-
-    MimeTypesHandler* handler = MimeTypesHandler::GetHandler(extension);
-    if (!handler) {
-      message_ = "No mime type handlers defined.";
-      return NULL;
-    }
-
-    DCHECK_EQ(test_extension_id_, extension->id());
-
-    return extension;
-  }
-
-  // Returns the download manager for the current browser.
-  DownloadManager* GetDownloadManager() const {
-    DownloadManager* download_manager =
-        BrowserContext::GetDownloadManager(browser()->profile());
-    EXPECT_TRUE(download_manager);
-    return download_manager;
-  }
-
-  // Deletes the download and waits until it's flushed.
-  // The |manager| should have |download| in its list of downloads.
-  void DeleteDownloadAndWaitForFlush(DownloadItem* download,
-                                     DownloadManager* manager) {
-    content::DownloadTestFlushObserver flush_observer(manager);
-    download->Remove();
-    flush_observer.WaitForFlush();
-  }
-
- protected:
-  std::string test_extension_id_;
-  // The HTTP server used in the tests.
-  std::unique_ptr<net::EmbeddedTestServer> test_server_;
-};
-
-// Tests that navigating to a resource with a MIME type handleable by an
-// installed, white-listed extension invokes the extension's
-// onExecuteContentHandler event (and does not start a download).
-IN_PROC_BROWSER_TEST_F(StreamsPrivateApiTest, Navigate) {
-  if (base::FeatureList::IsEnabled(network::features::kNetworkService))
-    return;  // Streams not used with network service.
-
-  ASSERT_TRUE(LoadTestExtension()) << message_;
-
-  ResultCatcher catcher;
-
-  ui_test_utils::NavigateToURL(browser(),
-                               test_server_->GetURL("/doc_path.doc"));
-
-  // Wait for the response from the test server.
-  base::RunLoop().RunUntilIdle();
-
-  // There should be no downloads started by the navigation.
-  DownloadManager* download_manager = GetDownloadManager();
-  std::vector<DownloadItem*> downloads;
-  download_manager->GetAllDownloads(&downloads);
-  ASSERT_EQ(0u, downloads.size());
-
-  // The test extension should receive onExecuteContentHandler event with MIME
-  // type 'application/msword' (and call chrome.test.notifySuccess).
-  EXPECT_TRUE(catcher.GetNextResult());
-}
-
-// Tests that navigating to a file URL also intercepts despite there being no
-// HTTP headers. This is a regression test for https://crbug.com/416433.
-IN_PROC_BROWSER_TEST_F(StreamsPrivateApiTest, FileURL) {
-  if (base::FeatureList::IsEnabled(network::features::kNetworkService))
-    return;  // Streams not used with network service.
-
-  ASSERT_TRUE(LoadTestExtension()) << message_;
-
-  ResultCatcher catcher;
-
-  ui_test_utils::NavigateToURL(browser(), ui_test_utils::GetTestUrl(
-      base::FilePath(FILE_PATH_LITERAL("downloads")),
-      base::FilePath(FILE_PATH_LITERAL("Picture_1.doc"))));
-
-  // There should be no downloads started by the navigation.
-  DownloadManager* download_manager = GetDownloadManager();
-  std::vector<DownloadItem*> downloads;
-  download_manager->GetAllDownloads(&downloads);
-  ASSERT_EQ(0u, downloads.size());
-
-  // The test extension should receive onExecuteContentHandler event with MIME
-  // type 'application/msword' (and call chrome.test.notifySuccess).
-  EXPECT_TRUE(catcher.GetNextResult());
-}
-
-// Tests that navigating cross-site to a resource with a MIME type handleable by
-// an installed, white-listed extension invokes the extension's
-// onExecuteContentHandler event (and does not start a download).
-// Regression test for http://crbug.com/342999.
-IN_PROC_BROWSER_TEST_F(StreamsPrivateApiTest, NavigateCrossSite) {
-  if (base::FeatureList::IsEnabled(network::features::kNetworkService))
-    return;  // Streams not used with network service.
-
-  ASSERT_TRUE(LoadTestExtension()) << message_;
-
-  ResultCatcher catcher;
-
-  // Navigate to a URL on a different hostname.
-  static const char kInitialHost[] = "www.example.com";
-  GURL::Replacements replacements;
-  replacements.SetHostStr(kInitialHost);
-  GURL initial_url =
-      test_server_->GetURL("/index.html").ReplaceComponents(replacements);
-  ui_test_utils::NavigateToURL(browser(), initial_url);
-
-  // Now navigate to the doc file; the extension should pick it up normally.
-  ui_test_utils::NavigateToURL(browser(),
-                               test_server_->GetURL("/doc_path.doc"));
-
-  // Wait for the response from the test server.
-  base::RunLoop().RunUntilIdle();
-
-  // There should be no downloads started by the navigation.
-  DownloadManager* download_manager = GetDownloadManager();
-  std::vector<DownloadItem*> downloads;
-  download_manager->GetAllDownloads(&downloads);
-  ASSERT_EQ(0u, downloads.size());
-
-  // The test extension should receive onExecuteContentHandler event with MIME
-  // type 'application/msword' (and call chrome.test.notifySuccess).
-  EXPECT_TRUE(catcher.GetNextResult());
-}
-
-// Flaky on Linux and ChromeOS: http://crbug.com/746526.
-#if defined(OS_LINUX)
-#define MAYBE_NavigateToAnAttachment DISABLED_NavigateToAnAttachment
-#else
-#define MAYBE_NavigateToAnAttachment NavigateToAnAttachment
-#endif
-
-// Tests that navigation to an attachment starts a download, even if there is an
-// extension with a file browser handler that can handle the attachment's MIME
-// type.
-IN_PROC_BROWSER_TEST_F(StreamsPrivateApiTest, MAYBE_NavigateToAnAttachment) {
-  if (base::FeatureList::IsEnabled(network::features::kNetworkService))
-    return;  // Streams not used with network service.
-
-  InitializeDownloadSettings();
-
-  ASSERT_TRUE(LoadTestExtension()) << message_;
-
-  ResultCatcher catcher;
-
-  // The test should start a download.
-  DownloadManager* download_manager = GetDownloadManager();
-  std::unique_ptr<content::DownloadTestObserver> download_observer(
-      new content::DownloadTestObserverInProgress(download_manager, 1));
-
-  ui_test_utils::NavigateToURL(browser(),
-                               test_server_->GetURL("/text_path_attch.txt"));
-
-  // Wait for the download to start.
-  download_observer->WaitForFinished();
-
-  // There should be one download started by the navigation.
-  DownloadManager::DownloadVector downloads;
-  download_manager->GetAllDownloads(&downloads);
-  ASSERT_EQ(1u, downloads.size());
-
-  // Cancel and delete the download started in the test.
-  DeleteDownloadAndWaitForFlush(downloads[0], download_manager);
-
-  // The test extension should not receive any events by now. Send it an event
-  // with MIME type "test/done", so it stops waiting for the events. (If there
-  // was an event with MIME type 'text/plain', |catcher.GetNextResult()| will
-  // fail regardless of the sent event; chrome.test.notifySuccess will not be
-  // called by the extension).
-  SendDoneEvent();
-  EXPECT_TRUE(catcher.GetNextResult());
-}
-
-// Flaky on Linux and Win 10: http://crbug.com/746526.
-#if defined(OS_LINUX) || defined(OS_WIN)
-#define MAYBE_DirectDownload DISABLED_DirectDownload
-#else
-#define MAYBE_DirectDownload DirectDownload
-#endif
-
-// Tests that direct download requests don't get intercepted by
-// StreamsResourceThrottle, even if there is an extension with a file
-// browser handler that can handle the download's MIME type.
-IN_PROC_BROWSER_TEST_F(StreamsPrivateApiTest, MAYBE_DirectDownload) {
-  if (base::FeatureList::IsEnabled(network::features::kNetworkService))
-    return;  // Streams not used with network service.
-
-  InitializeDownloadSettings();
-
-  ASSERT_TRUE(LoadTestExtension()) << message_;
-
-  ResultCatcher catcher;
-
-  DownloadManager* download_manager = GetDownloadManager();
-  std::unique_ptr<content::DownloadTestObserver> download_observer(
-      new content::DownloadTestObserverInProgress(download_manager, 1));
-
-  // The resource's URL on the test server.
-  GURL url = test_server_->GetURL("/text_path.txt");
-
-  // The download's target file path.
-  base::FilePath target_path =
-      DownloadPrefs(browser()->profile())
-          .DownloadPath()
-          .Append(FILE_PATH_LITERAL("download_target.txt"));
-
-  // Set the downloads parameters.
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_TRUE(web_contents);
-  std::unique_ptr<DownloadUrlParameters> params(
-      content::DownloadRequestUtils::CreateDownloadForWebContentsMainFrame(
-          web_contents, url, TRAFFIC_ANNOTATION_FOR_TESTS));
-
-  params->set_file_path(target_path);
-
-  // Start download of the URL with a path "/text_path.txt" on the test server.
-  download_manager->DownloadUrl(std::move(params));
-
-  // Wait for the download to start.
-  download_observer->WaitForFinished();
-
-  // There should have been one download.
-  std::vector<DownloadItem*> downloads;
-  download_manager->GetAllDownloads(&downloads);
-  ASSERT_EQ(1u, downloads.size());
-
-  // Cancel and delete the download statred in the test.
-  DeleteDownloadAndWaitForFlush(downloads[0], download_manager);
-
-  // The test extension should not receive any events by now. Send it an event
-  // with MIME type "test/done", so it stops waiting for the events. (If there
-  // was an event with MIME type 'text/plain', |catcher.GetNextResult()| will
-  // fail regardless of the sent event; chrome.test.notifySuccess will not be
-  // called by the extension).
-  SendDoneEvent();
-  EXPECT_TRUE(catcher.GetNextResult());
-}
-
-// Tests that response headers are correctly passed to the API and that multiple
-// repsonse headers with the same name are merged correctly.
-IN_PROC_BROWSER_TEST_F(StreamsPrivateApiTest, Headers) {
-  if (base::FeatureList::IsEnabled(network::features::kNetworkService))
-    return;  // Streams not used with network service.
-
-  ASSERT_TRUE(LoadTestExtension()) << message_;
-
-  ResultCatcher catcher;
-
-  ui_test_utils::NavigateToURL(browser(),
-                               test_server_->GetURL("/spreadsheet_path.xls"));
-
-  // Wait for the response from the test server.
-  base::RunLoop().RunUntilIdle();
-
-  // There should be no downloads started by the navigation.
-  DownloadManager* download_manager = GetDownloadManager();
-  std::vector<DownloadItem*> downloads;
-  download_manager->GetAllDownloads(&downloads);
-  ASSERT_EQ(0u, downloads.size());
-
-  // The test extension should receive onExecuteContentHandler event with MIME
-  // type 'application/msexcel' (and call chrome.test.notifySuccess).
-  EXPECT_TRUE(catcher.GetNextResult());
-}
-
-// Tests that chrome.streamsPrivate.abort() works correctly.
-IN_PROC_BROWSER_TEST_F(StreamsPrivateApiTest, Abort) {
-  if (base::FeatureList::IsEnabled(network::features::kNetworkService))
-    return;  // Streams not used with network service.
-
-  ASSERT_TRUE(LoadTestExtension()) << message_;
-
-  ResultCatcher catcher;
-  ui_test_utils::NavigateToURL(browser(),
-                               test_server_->GetURL("/no_abort.rtf"));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(catcher.GetNextResult());
-
-  ui_test_utils::NavigateToURL(browser(),
-                               test_server_->GetURL("/abort.rtf"));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(catcher.GetNextResult());
-}
-
-}  // namespace
diff --git a/chrome/browser/extensions/browser_context_keyed_service_factories.cc b/chrome/browser/extensions/browser_context_keyed_service_factories.cc
index 64bd49d..4aa636f8 100644
--- a/chrome/browser/extensions/browser_context_keyed_service_factories.cc
+++ b/chrome/browser/extensions/browser_context_keyed_service_factories.cc
@@ -28,7 +28,6 @@
 #include "chrome/browser/extensions/api/settings_overrides/settings_overrides_api.h"
 #include "chrome/browser/extensions/api/settings_private/settings_private_event_router_factory.h"
 #include "chrome/browser/extensions/api/signed_in_devices/signed_in_devices_manager.h"
-#include "chrome/browser/extensions/api/streams_private/streams_private_api.h"
 #include "chrome/browser/extensions/api/tab_capture/tab_capture_registry.h"
 #include "chrome/browser/extensions/api/tabs/tabs_windows_api.h"
 #include "chrome/browser/extensions/api/web_navigation/web_navigation_api.h"
@@ -127,7 +126,6 @@
 #if BUILDFLAG(ENABLE_SPELLCHECK)
   extensions::SpellcheckAPI::GetFactoryInstance();
 #endif
-  extensions::StreamsPrivateAPI::GetFactoryInstance();
   extensions::TabCaptureRegistry::GetFactoryInstance();
   extensions::TabsWindowsAPI::GetFactoryInstance();
   extensions::TtsAPI::GetFactoryInstance();
diff --git a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
index 3a9d39b..e7e02207 100644
--- a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
+++ b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
@@ -98,6 +98,7 @@
 #if BUILDFLAG(ENABLE_EXTENSIONS)
 #include "chrome/browser/extensions/api/streams_private/streams_private_api.h"
 #include "extensions/browser/guest_view/web_view/web_view_renderer_state.h"
+#include "extensions/common/extension.h"
 #include "extensions/common/extension_urls.h"
 #include "extensions/common/user_script.h"
 #endif
@@ -521,9 +522,9 @@
       FROM_HERE, {content::BrowserThread::UI},
       base::BindOnce(
           &extensions::StreamsPrivateAPI::SendExecuteMimeTypeHandlerEvent,
-          request->GetExpectedContentSize(), ix->second.extension_id,
-          ix->second.view_id, embedded, info->GetFrameTreeNodeId(),
-          info->GetChildID(), info->GetRenderFrameID(), std::move(stream),
+          ix->second.extension_id, ix->second.view_id, embedded,
+          info->GetFrameTreeNodeId(), info->GetChildID(),
+          info->GetRenderFrameID(), std::move(stream),
           nullptr /* transferrable_loader */, GURL()));
   stream_target_info_.erase(request);
 #endif
diff --git a/chrome/browser/media/webrtc/webrtc_log_uploader.cc b/chrome/browser/media/webrtc/webrtc_log_uploader.cc
index f3b5ef01..cd61849 100644
--- a/chrome/browser/media/webrtc/webrtc_log_uploader.cc
+++ b/chrome/browser/media/webrtc/webrtc_log_uploader.cc
@@ -333,7 +333,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(!shutting_down_);
 
-  if (!url_loader_factory_.is_bound())
+  if (url_loader_factory_.is_bound())
     return;
 
   // Clone UI thread URLLoaderFactory for use on the IO thread.
diff --git a/chrome/browser/net/net_error_diagnostics_dialog_win.cc b/chrome/browser/net/net_error_diagnostics_dialog_win.cc
index ec33fed..d3c04831 100644
--- a/chrome/browser/net/net_error_diagnostics_dialog_win.cc
+++ b/chrome/browser/net/net_error_diagnostics_dialog_win.cc
@@ -48,7 +48,7 @@
       return;
 
     RunState run_state = BeginRun(parent);
-    run_state.dialog_thread->task_runner()->PostTaskAndReply(
+    run_state.dialog_task_runner->PostTaskAndReply(
         FROM_HERE,
         base::Bind(&NetErrorDiagnosticsDialog::ShowDialogOnPrivateThread,
                    base::Unretained(this), parent, failed_url),
diff --git a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.cc
index f231b1b..8d258cf 100644
--- a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.cc
@@ -16,6 +16,8 @@
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "net/base/mime_util.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
+#include "services/metrics/public/cpp/ukm_recorder.h"
 #include "third_party/blink/public/common/mime_util/mime_util.h"
 #include "url/gurl.h"
 
@@ -76,6 +78,8 @@
                           base::CompareCase::SENSITIVE);
 }
 
+using ResourceMimeType = AdsPageLoadMetricsObserver::ResourceMimeType;
+
 }  // namespace
 
 AdsPageLoadMetricsObserver::AdFrameData::AdFrameData(
@@ -155,8 +159,7 @@
   }
 
   // Determine who the parent frame's ad ancestor is.  If we don't know who it
-  // is (UMA suggested 1.8% of the time in September 2018), return, such as with
-  // a frame from a previous navigation.
+  // is, return, such as with a frame from a previous navigation.
   content::RenderFrameHost* parent_frame_host =
       ad_host ? ad_host->GetParent() : nullptr;
   const auto& parent_id_and_data =
@@ -222,8 +225,11 @@
     const page_load_metrics::PageLoadExtraInfo& extra_info) {
   // The browser may come back, but there is no guarantee. To be safe, record
   // what we have now and ignore future changes to this navigation.
-  if (extra_info.did_commit)
-    RecordHistograms();
+  if (extra_info.did_commit) {
+    if (timing.response_start)
+      time_commit_ = timing.navigation_start + *timing.response_start;
+    RecordHistograms(extra_info.source_id);
+  }
 
   return STOP_OBSERVING;
 }
@@ -236,7 +242,9 @@
 void AdsPageLoadMetricsObserver::OnComplete(
     const page_load_metrics::mojom::PageLoadTiming& timing,
     const page_load_metrics::PageLoadExtraInfo& info) {
-  RecordHistograms();
+  if (info.did_commit && timing.response_start)
+    time_commit_ = timing.navigation_start + *timing.response_start;
+  RecordHistograms(info.source_id);
 }
 
 void AdsPageLoadMetricsObserver::OnResourceDataUseObserved(
@@ -260,6 +268,15 @@
   }
 }
 
+void AdsPageLoadMetricsObserver::OnPageInteractive(
+    const page_load_metrics::mojom::PageLoadTiming& timing,
+    const page_load_metrics::PageLoadExtraInfo& info) {
+  if (timing.interactive_timing->interactive) {
+    time_interactive_ =
+        timing.navigation_start + *timing.interactive_timing->interactive;
+  }
+}
+
 void AdsPageLoadMetricsObserver::OnAdSubframeDetected(
     content::RenderFrameHost* render_frame_host) {
   AdTypes ad_types;
@@ -340,6 +357,31 @@
   }
 }
 
+AdsPageLoadMetricsObserver::ResourceMimeType
+AdsPageLoadMetricsObserver::GetResourceMimeType(
+    const page_load_metrics::mojom::ResourceDataUpdatePtr& resource) {
+  if (blink::IsSupportedImageMimeType(resource->mime_type))
+    return ResourceMimeType::kImage;
+  if (blink::IsSupportedJavascriptMimeType(resource->mime_type))
+    return ResourceMimeType::kJavascript;
+
+  std::string top_level_type;
+  std::string subtype;
+  // Categorize invalid mime types as "Other".
+  if (!net::ParseMimeTypeWithoutParameter(resource->mime_type, &top_level_type,
+                                          &subtype)) {
+    return ResourceMimeType::kOther;
+  }
+  if (top_level_type.compare("video") == 0)
+    return ResourceMimeType::kVideo;
+  else if (top_level_type.compare("text") == 0 && subtype.compare("css") == 0)
+    return ResourceMimeType::kCss;
+  else if (top_level_type.compare("text") == 0 && subtype.compare("html") == 0)
+    return ResourceMimeType::kHtml;
+  else
+    return ResourceMimeType::kOther;
+}
+
 void AdsPageLoadMetricsObserver::UpdateResource(
     const page_load_metrics::mojom::ResourceDataUpdatePtr& resource) {
   auto it = page_resources_.find(resource->request_id);
@@ -361,6 +403,15 @@
       page_main_frame_ad_resource_bytes_ +=
           resource->delta_bytes + unaccounted_ad_bytes;
     }
+    if (!time_interactive_.is_null()) {
+      page_ad_resource_bytes_since_interactive_ +=
+          resource->delta_bytes + unaccounted_ad_bytes;
+    }
+    ResourceMimeType mime_type = GetResourceMimeType(resource);
+    if (mime_type == ResourceMimeType::kVideo)
+      page_ad_video_bytes_ += resource->delta_bytes + unaccounted_ad_bytes;
+    if (mime_type == ResourceMimeType::kJavascript)
+      page_ad_javascript_bytes_ += resource->delta_bytes + unaccounted_ad_bytes;
   }
 
   // Update resource map.
@@ -383,39 +434,25 @@
 
 void AdsPageLoadMetricsObserver::RecordResourceMimeHistograms(
     const page_load_metrics::mojom::ResourceDataUpdatePtr& resource) {
-  if (blink::IsSupportedImageMimeType(resource->mime_type)) {
+  ResourceMimeType mime_type = GetResourceMimeType(resource);
+  if (mime_type == ResourceMimeType::kImage) {
     PAGE_BYTES_HISTOGRAM("Ads.ResourceUsage.Size.Mime.Image",
                          resource->received_data_length);
-  } else if (blink::IsSupportedJavascriptMimeType(resource->mime_type)) {
+  } else if (mime_type == ResourceMimeType::kJavascript) {
     PAGE_BYTES_HISTOGRAM("Ads.ResourceUsage.Size.Mime.JS",
                          resource->received_data_length);
-  } else {
-    std::string top_level_type;
-    std::string subtype;
-
-    if (!net::ParseMimeTypeWithoutParameter(resource->mime_type,
-                                            &top_level_type, &subtype)) {
-      // Log invalid mime types as "Other".
-      PAGE_BYTES_HISTOGRAM("Ads.ResourceUsage.Size.Mime.Other",
-                           resource->received_data_length);
-      return;
-    }
-
-    if (top_level_type.compare("video") == 0) {
-      PAGE_BYTES_HISTOGRAM("Ads.ResourceUsage.Size.Mime.Video",
-                           resource->received_data_length);
-    } else if (top_level_type.compare("text") == 0 &&
-               subtype.compare("css") == 0) {
-      PAGE_BYTES_HISTOGRAM("Ads.ResourceUsage.Size.Mime.CSS",
-                           resource->received_data_length);
-    } else if (top_level_type.compare("text") == 0 &&
-               subtype.compare("html") == 0) {
-      PAGE_BYTES_HISTOGRAM("Ads.ResourceUsage.Size.Mime.HTML",
-                           resource->received_data_length);
-    } else {
-      PAGE_BYTES_HISTOGRAM("Ads.ResourceUsage.Size.Mime.Other",
-                           resource->received_data_length);
-    }
+  } else if (mime_type == ResourceMimeType::kVideo) {
+    PAGE_BYTES_HISTOGRAM("Ads.ResourceUsage.Size.Mime.Video",
+                         resource->received_data_length);
+  } else if (mime_type == ResourceMimeType::kCss) {
+    PAGE_BYTES_HISTOGRAM("Ads.ResourceUsage.Size.Mime.CSS",
+                         resource->received_data_length);
+  } else if (mime_type == ResourceMimeType::kHtml) {
+    PAGE_BYTES_HISTOGRAM("Ads.ResourceUsage.Size.Mime.HTML",
+                         resource->received_data_length);
+  } else if (mime_type == ResourceMimeType::kOther) {
+    PAGE_BYTES_HISTOGRAM("Ads.ResourceUsage.Size.Mime.Other",
+                         resource->received_data_length);
   }
 }
 
@@ -440,7 +477,8 @@
     RecordResourceMimeHistograms(resource);
 }
 
-void AdsPageLoadMetricsObserver::RecordPageResourceTotalHistograms() {
+void AdsPageLoadMetricsObserver::RecordPageResourceTotalHistograms(
+    ukm::SourceId source_id) {
   // Only records histograms on pages that have some ad bytes.
   if (page_ad_resource_bytes_ == 0)
     return;
@@ -455,13 +493,40 @@
     unfinished_bytes += kv.second->received_data_length;
   PAGE_BYTES_HISTOGRAM("PageLoad.Clients.Ads.Resources.Bytes.Unfinished",
                        unfinished_bytes);
+
+  auto* ukm_recorder = ukm::UkmRecorder::Get();
+  ukm::builders::AdPageLoad builder(source_id);
+  builder.SetTotalBytes(page_resource_bytes_ >> 10)
+      .SetAdBytes(page_ad_resource_bytes_ >> 10)
+      .SetAdJavascriptBytes(page_ad_javascript_bytes_ >> 10)
+      .SetAdVideoBytes(page_ad_video_bytes_ >> 10);
+  base::Time current_time = base::Time::Now();
+  if (!time_commit_.is_null()) {
+    int time_since_commit = (current_time - time_commit_).InMicroseconds();
+    if (time_since_commit > 0) {
+      int ad_kbps_from_commit =
+          (page_ad_resource_bytes_ >> 10) * 1000 * 1000 / time_since_commit;
+      builder.SetAdBytesPerSecond(ad_kbps_from_commit);
+    }
+  }
+  if (!time_interactive_.is_null()) {
+    int time_since_interactive =
+        (current_time - time_interactive_).InMicroseconds();
+    if (time_since_interactive > 0) {
+      int ad_kbps_since_interactive =
+          (page_ad_resource_bytes_since_interactive_ >> 10) * 1000 * 1000 /
+          time_since_interactive;
+      builder.SetAdBytesPerSecondAfterInteractive(ad_kbps_since_interactive);
+    }
+  }
+  builder.Record(ukm_recorder->Get());
 }
 
-void AdsPageLoadMetricsObserver::RecordHistograms() {
+void AdsPageLoadMetricsObserver::RecordHistograms(ukm::SourceId source_id) {
   RecordHistogramsForType(AD_TYPE_GOOGLE);
   RecordHistogramsForType(AD_TYPE_SUBRESOURCE_FILTER);
   RecordHistogramsForType(AD_TYPE_ALL);
-  RecordPageResourceTotalHistograms();
+  RecordPageResourceTotalHistograms(source_id);
   for (auto const& kv : page_resources_)
     RecordResourceHistograms(kv.second);
 }
diff --git a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.h
index 15a5f87..1f03c58 100644
--- a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.h
@@ -44,6 +44,17 @@
     kMaxValue = kCross,
   };
 
+  // High level categories of mime types for resources loaded by the page.
+  enum class ResourceMimeType {
+    kJavascript = 0,
+    kVideo = 1,
+    kImage = 2,
+    kCss = 3,
+    kHtml = 4,
+    kOther = 5,
+    kMaxValue = kOther,
+  };
+
   using AdTypes = std::bitset<AD_TYPE_MAX>;
 
   // Returns a new AdsPageLoadMetricObserver. If the feature is disabled it
@@ -75,6 +86,9 @@
   void OnResourceDataUseObserved(
       const std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr>&
           resources) override;
+  void OnPageInteractive(
+      const page_load_metrics::mojom::PageLoadTiming& timing,
+      const page_load_metrics::PageLoadExtraInfo& extra_info) override;
 
  private:
   struct AdFrameData {
@@ -111,6 +125,12 @@
   void ProcessLoadedResource(
       const page_load_metrics::ExtraRequestCompleteInfo& extra_request_info);
 
+  // Get the mime type of a resource. This only returns a subset of mime types,
+  // grouped at a higher level. For example, all video mime types return the
+  // same value.
+  ResourceMimeType GetResourceMimeType(
+      const page_load_metrics::mojom::ResourceDataUpdatePtr& resource);
+
   // Update all of the per-resource page counters given a new resource data
   // update. Updates |page_resources_| to reflect the new state of the resource.
   // Called once per ResourceDataUpdate.
@@ -124,8 +144,8 @@
   // Records per-resource histograms.
   void RecordResourceHistograms(
       const page_load_metrics::mojom::ResourceDataUpdatePtr& resource);
-  void RecordPageResourceTotalHistograms();
-  void RecordHistograms();
+  void RecordPageResourceTotalHistograms(ukm::SourceId source_id);
+  void RecordHistograms(ukm::SourceId source_id);
   void RecordHistogramsForType(int ad_type);
 
   // Checks to see if a resource is waiting for a navigation with the given
@@ -162,11 +182,22 @@
 
   // Tallies for bytes and counts observed in resource data updates for the
   // entire page.
+  size_t page_ad_javascript_bytes_ = 0u;
+  size_t page_ad_video_bytes_ = 0u;
   size_t page_resource_bytes_ = 0u;
   size_t page_ad_resource_bytes_ = 0u;
   size_t page_main_frame_ad_resource_bytes_ = 0u;
   uint32_t total_number_page_resources_ = 0;
 
+  // Time the page was committed.
+  base::Time time_commit_;
+
+  // Time the page was observed to be interactive.
+  base::Time time_interactive_;
+
+  // Total ad bytes loaded by the page since it was observed to be interactive.
+  size_t page_ad_resource_bytes_since_interactive_ = 0u;
+
   size_t page_bytes_ = 0u;
   size_t uncached_page_bytes_ = 0u;
   bool committed_ = false;
diff --git a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_browsertest.cc
index b9827921..073a39b 100644
--- a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_browsertest.cc
+++ b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_browsertest.cc
@@ -22,11 +22,14 @@
 #include "components/subresource_filter/core/common/common_features.h"
 #include "components/subresource_filter/core/common/test_ruleset_utils.h"
 #include "components/subresource_filter/mojom/subresource_filter.mojom.h"
+#include "components/ukm/test_ukm_recorder.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/controllable_http_response.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
+#include "services/metrics/public/cpp/ukm_source.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 #include "url/url_constants.h"
@@ -376,6 +379,7 @@
 IN_PROC_BROWSER_TEST_F(AdsPageLoadMetricsObserverResourceBrowserTest,
                        RecordedMimeMetrics) {
   base::HistogramTester histogram_tester;
+  ukm::TestAutoSetUkmRecorder ukm_recorder;
   embedded_test_server()->ServeFilesFromSourceDirectory(
       "chrome/test/data/ad_tagging");
   content::SetupCrossSiteRedirector(embedded_test_server());
@@ -385,9 +389,8 @@
 
   content::WebContents* contents =
       browser()->tab_strip_model()->GetActiveWebContents();
-  ui_test_utils::NavigateToURL(
-      browser(),
-      embedded_test_server()->GetURL("foo.com", "/frame_factory.html"));
+  GURL url = embedded_test_server()->GetURL("foo.com", "/frame_factory.html");
+  ui_test_utils::NavigateToURL(browser(), url);
   contents->GetMainFrame()->ExecuteJavaScriptForTests(
       base::ASCIIToUTF16("createFrame('multiple_mimes.html', 'test');"));
   waiter->AddMinimumAdResourceExpectation(8);
@@ -405,4 +408,29 @@
   histogram_tester.ExpectTotalCount("Ads.ResourceUsage.Size.Mime.Image", 1);
   histogram_tester.ExpectTotalCount("Ads.ResourceUsage.Size.Mime.Video", 1);
   histogram_tester.ExpectTotalCount("Ads.ResourceUsage.Size.Mime.Other", 1);
+
+  // Verify UKM Metrics recorded.
+  auto entries =
+      ukm_recorder.GetEntriesByName(ukm::builders::AdPageLoad::kEntryName);
+  EXPECT_EQ(1u, entries.size());
+  ukm_recorder.ExpectEntrySourceHasUrl(entries.front(), url);
+  EXPECT_GT(*ukm_recorder.GetEntryMetric(
+                entries.front(), ukm::builders::AdPageLoad::kAdBytesName),
+            0);
+  EXPECT_GT(
+      *ukm_recorder.GetEntryMetric(
+          entries.front(), ukm::builders::AdPageLoad::kAdBytesPerSecondName),
+      0);
+
+  // TTI is not reached by this page and thus should not have this recorded.
+  EXPECT_FALSE(ukm_recorder.EntryHasMetric(
+      entries.front(),
+      ukm::builders::AdPageLoad::kAdBytesPerSecondAfterInteractiveName));
+  EXPECT_GT(
+      *ukm_recorder.GetEntryMetric(
+          entries.front(), ukm::builders::AdPageLoad::kAdJavascriptBytesName),
+      0);
+  EXPECT_GT(*ukm_recorder.GetEntryMetric(
+                entries.front(), ukm::builders::AdPageLoad::kAdVideoBytesName),
+            0);
 }
diff --git a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_unittest.cc
index b75d87b3..a177291f 100644
--- a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_unittest.cc
@@ -22,8 +22,10 @@
 #include "chrome/browser/page_load_metrics/page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/page_load_tracker.h"
 #include "chrome/browser/subresource_filter/subresource_filter_test_harness.h"
+#include "chrome/common/page_load_metrics/test/page_load_metrics_test_util.h"
 #include "components/subresource_filter/content/browser/subresource_filter_observer_manager.h"
 #include "components/subresource_filter/core/common/load_policy.h"
+#include "components/ukm/test_ukm_recorder.h"
 #include "content/public/browser/global_request_id.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/navigation_throttle.h"
@@ -36,6 +38,7 @@
 #include "content/public/test/test_navigation_throttle_inserter.h"
 #include "content/public/test/test_renderer_host.h"
 #include "net/base/host_port_pair.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
 #include "url/gurl.h"
 
 using content::TestNavigationThrottle;
@@ -272,6 +275,25 @@
     tester_->SimulateLoadedResource(request);
   }
 
+  void ResourceDataUpdate(int resource_size_in_kbyte,
+                          std::string mime_type,
+                          bool is_ad_resource) {
+    std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr> resources;
+    page_load_metrics::mojom::ResourceDataUpdatePtr resource =
+        page_load_metrics::mojom::ResourceDataUpdate::New();
+    resource->received_data_length = resource_size_in_kbyte;
+    resource->delta_bytes = resource_size_in_kbyte;
+    resource->reported_as_ad_resource = is_ad_resource;
+    resource->is_complete = true;
+    resource->mime_type = mime_type;
+    resources.push_back(std::move(resource));
+    tester_->SimulateResourceDataUseUpdate(resources);
+  }
+
+  void TimingUpdate(const page_load_metrics::mojom::PageLoadTiming& timing) {
+    tester_->SimulateTimingUpdate(timing);
+  }
+
   page_load_metrics::PageLoadMetricsObserverTester* tester() {
     return tester_.get();
   }
@@ -706,3 +728,53 @@
                  0u /* non_ad_cached_kb */, 0u /* non_ad_uncached_kb */,
                  AdType::SUBRESOURCE_FILTER);
 }
+
+// UKM metrics for ad page load are recorded correctly.
+TEST_F(AdsPageLoadMetricsObserverTest, AdPageLoadUKM) {
+  ukm::TestAutoSetUkmRecorder ukm_recorder;
+  NavigateMainFrame(kNonAdUrl);
+
+  page_load_metrics::mojom::PageLoadTiming timing;
+  page_load_metrics::InitPageLoadTimingForTest(&timing);
+  timing.navigation_start = base::Time::Now();
+  timing.response_start = base::TimeDelta::FromSeconds(0);
+  timing.interactive_timing->interactive = base::TimeDelta::FromSeconds(0);
+  PopulateRequiredTimingFields(&timing);
+  TimingUpdate(timing);
+  ResourceDataUpdate(10 << 10 /* resource_size_in_kbyte */,
+                     "application/javascript" /* mime_type */,
+                     false /* is_ad_resource */);
+  ResourceDataUpdate(10 << 10 /* resource_size_in_kbyte */,
+                     "application/javascript" /* mime_type */,
+                     true /* is_ad_resource */);
+  ResourceDataUpdate(10 << 10 /* resource_size_in_kbyte */,
+                     "video/webm" /* mime_type */, true /* is_ad_resource */);
+  NavigateMainFrame(kNonAdUrl);
+
+  auto entries =
+      ukm_recorder.GetEntriesByName(ukm::builders::AdPageLoad::kEntryName);
+  EXPECT_EQ(1u, entries.size());
+
+  EXPECT_EQ(*ukm_recorder.GetEntryMetric(
+                entries.front(), ukm::builders::AdPageLoad::kTotalBytesName),
+            30);
+  EXPECT_EQ(*ukm_recorder.GetEntryMetric(
+                entries.front(), ukm::builders::AdPageLoad::kAdBytesName),
+            20);
+  EXPECT_EQ(
+      *ukm_recorder.GetEntryMetric(
+          entries.front(), ukm::builders::AdPageLoad::kAdJavascriptBytesName),
+      10);
+  EXPECT_EQ(*ukm_recorder.GetEntryMetric(
+                entries.front(), ukm::builders::AdPageLoad::kAdVideoBytesName),
+            10);
+  EXPECT_GT(
+      *ukm_recorder.GetEntryMetric(
+          entries.front(), ukm::builders::AdPageLoad::kAdBytesPerSecondName),
+      0);
+  EXPECT_GT(
+      *ukm_recorder.GetEntryMetric(
+          entries.front(),
+          ukm::builders::AdPageLoad::kAdBytesPerSecondAfterInteractiveName),
+      0);
+}
diff --git a/chrome/browser/page_load_metrics/observers/use_counter_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/use_counter_page_load_metrics_observer.cc
index 370c5fe..1eb77bf 100644
--- a/chrome/browser/page_load_metrics/observers/use_counter_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/use_counter_page_load_metrics_observer.cc
@@ -22,6 +22,9 @@
     ukm::SourceId source_id) {
   // Verify that no feature usage is observed before commit
   DCHECK(features_recorded_.count() <= 0);
+  ukm::builders::Blink_UseCounter(source_id)
+      .SetFeature(static_cast<int64_t>(WebFeature::kPageVisits))
+      .Record(ukm::UkmRecorder::Get());
   UMA_HISTOGRAM_ENUMERATION(internal::kFeaturesHistogramName,
                             WebFeature::kPageVisits,
                             WebFeature::kNumberOfFeatures);
diff --git a/chrome/browser/page_load_metrics/observers/use_counter_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/use_counter_page_load_metrics_observer_unittest.cc
index cac2da1..241033aa 100644
--- a/chrome/browser/page_load_metrics/observers/use_counter_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/use_counter_page_load_metrics_observer_unittest.cc
@@ -171,14 +171,18 @@
   std::vector<const ukm::mojom::UkmEntry*> entries =
       test_ukm_recorder().GetEntriesByName(
           ukm::builders::Blink_UseCounter::kEntryName);
-  EXPECT_EQ(2ul, entries.size());
+  EXPECT_EQ(3ul, entries.size());
   test_ukm_recorder().ExpectEntrySourceHasUrl(entries[0], GURL(kTestUrl));
   test_ukm_recorder().ExpectEntryMetric(
       entries[0], ukm::builders::Blink_UseCounter::kFeatureName,
-      static_cast<int64_t>(WebFeature::kNavigatorVibrate));
+      static_cast<int64_t>(WebFeature::kPageVisits));
   test_ukm_recorder().ExpectEntrySourceHasUrl(entries[1], GURL(kTestUrl));
   test_ukm_recorder().ExpectEntryMetric(
       entries[1], ukm::builders::Blink_UseCounter::kFeatureName,
+      static_cast<int64_t>(WebFeature::kNavigatorVibrate));
+  test_ukm_recorder().ExpectEntrySourceHasUrl(entries[2], GURL(kTestUrl));
+  test_ukm_recorder().ExpectEntryMetric(
+      entries[2], ukm::builders::Blink_UseCounter::kFeatureName,
       static_cast<int64_t>(WebFeature::kTouchEventPreventedNoTouchAction));
 }
 
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
index 3b83e34..9f98d56 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
@@ -1137,7 +1137,7 @@
 
   const auto& entries = test_ukm_recorder_->GetEntriesByName(
       ukm::builders::Blink_UseCounter::kEntryName);
-  EXPECT_EQ(4u, entries.size());
+  EXPECT_EQ(5u, entries.size());
   std::vector<int64_t> ukm_features;
   for (const auto* entry : entries) {
     test_ukm_recorder_->ExpectEntrySourceHasUrl(entry, url);
@@ -1149,6 +1149,7 @@
   EXPECT_THAT(
       ukm_features,
       UnorderedElementsAre(
+          static_cast<int64_t>(WebFeature::kPageVisits),
           static_cast<int64_t>(WebFeature::kFullscreenSecureOrigin),
           static_cast<int64_t>(WebFeature::kNavigatorVibrate),
           static_cast<int64_t>(WebFeature::kDataUriHasOctothorpe),
@@ -1177,7 +1178,7 @@
 
   const auto& entries = test_ukm_recorder_->GetEntriesByName(
       ukm::builders::Blink_UseCounter::kEntryName);
-  EXPECT_EQ(7u, entries.size());
+  EXPECT_EQ(8u, entries.size());
   std::vector<int64_t> ukm_features;
   for (const auto* entry : entries) {
     test_ukm_recorder_->ExpectEntrySourceHasUrl(entry, url);
@@ -1188,6 +1189,7 @@
   }
   EXPECT_THAT(ukm_features,
               UnorderedElementsAre(
+                  static_cast<int64_t>(WebFeature::kPageVisits),
                   static_cast<int64_t>(WebFeature::kFullscreenSecureOrigin),
                   static_cast<int64_t>(WebFeature::kNavigatorVibrate),
                   static_cast<int64_t>(WebFeature::kDataUriHasOctothorpe),
diff --git a/chrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.cc b/chrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.cc
index 93a27e4..b5837e0 100644
--- a/chrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.cc
+++ b/chrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.cc
@@ -14,6 +14,7 @@
 #include "content/public/browser/stream_info.h"
 #include "content/public/common/resource_type.h"
 #include "content/public/common/transferrable_url_loader.mojom.h"
+#include "extensions/common/extension.h"
 #include "mojo/public/cpp/system/data_pipe.h"
 
 PluginResponseInterceptorURLLoaderThrottle::
@@ -82,14 +83,12 @@
   transferrable_loader->url_loader_client = std::move(original_client);
   transferrable_loader->head = std::move(deep_copied_response->head);
 
-  int64_t expected_content_size = response_head->content_length;
   bool embedded = resource_type_ != content::RESOURCE_TYPE_MAIN_FRAME;
   base::PostTaskWithTraits(
       FROM_HERE, {content::BrowserThread::UI},
       base::BindOnce(
           &extensions::StreamsPrivateAPI::SendExecuteMimeTypeHandlerEvent,
-          expected_content_size, extension_id, view_id, embedded,
-          frame_tree_node_id_, -1 /* render_process_id */,
-          -1 /* render_frame_id */, nullptr /* stream */,
-          std::move(transferrable_loader), response_url));
+          extension_id, view_id, embedded, frame_tree_node_id_,
+          -1 /* render_process_id */, -1 /* render_frame_id */,
+          nullptr /* stream */, std::move(transferrable_loader), response_url));
 }
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index fe35e4d..ee879f58 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -205,6 +205,8 @@
 #include "content/public/test/url_loader_interceptor.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
+#include "device/usb/mock_usb_device.h"
+#include "device/usb/mojo/type_converters.h"
 #include "extensions/browser/api/messaging/messaging_delegate.h"
 #include "extensions/browser/disable_reason.h"
 #include "extensions/browser/extension_dialog_auto_confirm.h"
@@ -6291,6 +6293,52 @@
   EXPECT_TRUE(context->CanRequestObjectPermission(kTestUrl, kTestUrl));
 }
 
+IN_PROC_BROWSER_TEST_F(PolicyTest, WebUsbAllowDevicesForUrls) {
+  const GURL kTestUrl("https://foo.com:443");
+  scoped_refptr<device::UsbDevice> device =
+      base::MakeRefCounted<device::MockUsbDevice>(0, 0, "Google", "Gizmo",
+                                                  "123ABC");
+  auto device_info = device::mojom::UsbDeviceInfo::From(*device);
+
+  // Expect the default permission value to be empty.
+  auto* context = UsbChooserContextFactory::GetForProfile(browser()->profile());
+  EXPECT_FALSE(context->HasDevicePermission(kTestUrl, kTestUrl, *device_info));
+
+  // Update policy to add an entry to the permission value to allow |kTestUrl|
+  // to access the device described by |device_info|.
+  PolicyMap policies;
+
+  base::Value device_value(base::Value::Type::DICTIONARY);
+  device_value.SetKey("vendor_id", base::Value(0));
+  device_value.SetKey("product_id", base::Value(0));
+
+  base::Value devices_value(base::Value::Type::LIST);
+  devices_value.GetList().push_back(std::move(device_value));
+
+  base::Value url_patterns_value(base::Value::Type::LIST);
+  url_patterns_value.GetList().emplace_back(base::Value("https://[*.]foo.com"));
+
+  base::Value entry(base::Value::Type::DICTIONARY);
+  entry.SetKey("devices", std::move(devices_value));
+  entry.SetKey("url_patterns", std::move(url_patterns_value));
+
+  auto policy_value = std::make_unique<base::Value>(base::Value::Type::LIST);
+  policy_value->GetList().push_back(std::move(entry));
+
+  SetPolicy(&policies, key::kWebUsbAllowDevicesForUrls,
+            std::move(policy_value));
+  UpdateProviderPolicy(policies);
+
+  EXPECT_TRUE(context->HasDevicePermission(kTestUrl, kTestUrl, *device_info));
+
+  // Remove the policy to ensure that it can be dynamically updated.
+  SetPolicy(&policies, key::kWebUsbAllowDevicesForUrls,
+            std::make_unique<base::Value>(base::Value::Type::LIST));
+  UpdateProviderPolicy(policies);
+
+  EXPECT_FALSE(context->HasDevicePermission(kTestUrl, kTestUrl, *device_info));
+}
+
 // Similar to PolicyTest but sets the WebAppInstallForceList policy before the
 // browser is started.
 class WebAppInstallForceListPolicyTest : public PolicyTest {
diff --git a/chrome/browser/prerender/prerender_browsertest.cc b/chrome/browser/prerender/prerender_browsertest.cc
index 20f3c80..e4d71b6f 100644
--- a/chrome/browser/prerender/prerender_browsertest.cc
+++ b/chrome/browser/prerender/prerender_browsertest.cc
@@ -2701,36 +2701,6 @@
   ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
 }
 
-// Test that prerenders abort when navigating to a stream.
-// See chrome/browser/extensions/api/streams_private/streams_private_apitest.cc
-IN_PROC_BROWSER_TEST_F(PrerenderBrowserTestWithExtensions, StreamsTest) {
-  if (base::FeatureList::IsEnabled(network::features::kNetworkService))
-    return;  // Streams not used with network service.
-
-  ASSERT_TRUE(StartEmbeddedTestServer());
-
-  const extensions::Extension* extension = LoadExtension(
-      test_data_dir_.AppendASCII("streams_private/handle_mime_type"));
-  ASSERT_TRUE(extension);
-  EXPECT_EQ(std::string(extension_misc::kMimeHandlerPrivateTestExtensionId),
-            extension->id());
-  MimeTypesHandler* handler = MimeTypesHandler::GetHandler(extension);
-  ASSERT_TRUE(handler);
-  EXPECT_TRUE(handler->CanHandleMIMEType("application/msword"));
-
-  PrerenderTestURL("/prerender/document.doc", FINAL_STATUS_DOWNLOAD, 0);
-
-  // Sanity-check that the extension would have picked up the stream in a normal
-  // navigation had prerender not intercepted it.
-  // The extension streams_private/handle_mime_type reports success if it has
-  // handled the application/msword type.
-  // Note: NavigateToDestURL() cannot be used because of the assertion shecking
-  //     for non-null PrerenderContents.
-  extensions::ResultCatcher catcher;
-  ui_test_utils::NavigateToURL(current_browser(), dest_url());
-  EXPECT_TRUE(catcher.GetNextResult());
-}
-
 // Checks that non-http/https/chrome-extension subresource cancels the
 // prerender.
 IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
diff --git a/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc b/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc
index 05d685fd..7edfb86 100644
--- a/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc
+++ b/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc
@@ -167,6 +167,14 @@
     subresource_expected_["/bar.jpg"] = expect_bar_jpg_requested;
   }
 
+  bool resource_loading_hint_intervention_header_seen() const {
+    return resource_loading_hint_intervention_header_seen_;
+  }
+
+  void ResetResourceLoadingHintInterventionHeaderSeen() {
+    resource_loading_hint_intervention_header_seen_ = false;
+  }
+
  protected:
   base::test::ScopedFeatureList scoped_feature_list_;
 
@@ -182,6 +190,13 @@
   void MonitorResourceRequest(const net::test_server::HttpRequest& request) {
     // This method is called on embedded test server thread. Post the
     // information on UI thread.
+    auto it = request.headers.find("Intervention");
+    // Chrome status entry for resource loading hints is hosted at
+    // https://www.chromestatus.com/features/4775088607985664.
+    if (it != request.headers.end() &&
+        it->second.find("4510564810227712") != std::string::npos) {
+      resource_loading_hint_intervention_header_seen_ = true;
+    }
     base::PostTaskWithTraits(
         FROM_HERE, {content::BrowserThread::UI},
         base::BindOnce(&ResourceLoadingNoFeaturesBrowserTest::
@@ -224,6 +239,8 @@
   GURL http_url_;
   GURL redirect_url_;
 
+  bool resource_loading_hint_intervention_header_seen_ = false;
+
   // Mapping from a subresource path to whether the resource is expected to be
   // fetched. Once a subresource present in this map is fetched, the
   // corresponding value is set to false.
@@ -315,11 +332,13 @@
   // SetResourceLoadingHints sets 3 resource loading hints patterns.
   histogram_tester.ExpectBucketCount(
       "ResourceLoadingHints.CountBlockedSubresourcePatterns", 3, 1);
+  EXPECT_TRUE(resource_loading_hint_intervention_header_seen());
 
   // Load the same webpage to ensure that the resource loading hints are sent
   // again.
   SetExpectedFooJpgRequest(false);
   SetExpectedBarJpgRequest(true);
+  ResetResourceLoadingHintInterventionHeaderSeen();
 
   ui_test_utils::NavigateToURL(browser(), https_url());
 
@@ -336,6 +355,7 @@
   // SetResourceLoadingHints sets 3 resource loading hints patterns.
   histogram_tester.ExpectBucketCount(
       "ResourceLoadingHints.CountBlockedSubresourcePatterns", 3, 2);
+  EXPECT_TRUE(resource_loading_hint_intervention_header_seen());
 }
 
 IN_PROC_BROWSER_TEST_F(
@@ -366,6 +386,7 @@
   // SetResourceLoadingHints sets 3 resource loading hints patterns.
   histogram_tester.ExpectBucketCount(
       "ResourceLoadingHints.CountBlockedSubresourcePatterns", 3, 1);
+  EXPECT_TRUE(resource_loading_hint_intervention_header_seen());
 }
 
 IN_PROC_BROWSER_TEST_F(ResourceLoadingHintsBrowserTest,
@@ -395,6 +416,7 @@
       "Previews.InfoBarAction.ResourceLoadingHints", 0);
   histogram_tester.ExpectTotalCount(
       "ResourceLoadingHints.CountBlockedSubresourcePatterns", 0);
+  EXPECT_FALSE(resource_loading_hint_intervention_header_seen());
 }
 
 IN_PROC_BROWSER_TEST_F(ResourceLoadingHintsBrowserTest,
@@ -422,6 +444,7 @@
       "Previews.InfoBarAction.ResourceLoadingHints", 0);
   histogram_tester.ExpectTotalCount(
       "ResourceLoadingHints.CountBlockedSubresourcePatterns", 0);
+  EXPECT_FALSE(resource_loading_hint_intervention_header_seen());
 }
 
 IN_PROC_BROWSER_TEST_F(ResourceLoadingHintsBrowserTest,
@@ -449,4 +472,5 @@
       "Previews.InfoBarAction.ResourceLoadingHints", 0);
   histogram_tester.ExpectTotalCount(
       "ResourceLoadingHints.CountBlockedSubresourcePatterns", 0);
+  EXPECT_FALSE(resource_loading_hint_intervention_header_seen());
 }
diff --git a/chrome/browser/ssl/cert_report_helper.cc b/chrome/browser/ssl/cert_report_helper.cc
index b35b854..fa16eabf 100644
--- a/chrome/browser/ssl/cert_report_helper.cc
+++ b/chrome/browser/ssl/cert_report_helper.cc
@@ -105,10 +105,7 @@
 
   load_time_data->SetString(
       security_interstitials::kOptInLink,
-      l10n_util::GetStringFUTF16(safe_browsing::ChooseOptInTextResource(
-                                     *GetProfile(web_contents_)->GetPrefs(),
-                                     IDS_SAFE_BROWSING_MALWARE_REPORTING_AGREE,
-                                     IDS_SAFE_BROWSING_SCOUT_REPORTING_AGREE),
+      l10n_util::GetStringFUTF16(IDS_SAFE_BROWSING_SCOUT_REPORTING_AGREE,
                                  base::UTF8ToUTF16(privacy_link)));
 }
 
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc
index 35d792a..64c47f7 100644
--- a/chrome/browser/sync/chrome_sync_client.cc
+++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -480,27 +480,17 @@
       }
       return base::WeakPtr<syncer::SyncableService>();
     case syncer::AUTOFILL_WALLET_DATA: {
-      // TODO(feuunk): This doesn't allow switching which database to use at
-      // runtime. This should be fixed as part of the USS migration for
-      // payments.
-      auto service = account_web_data_service_ ? account_web_data_service_
-                                               : profile_web_data_service_;
-      if (service) {
+      if (profile_web_data_service_) {
         return autofill::AutofillWalletSyncableService::FromWebDataService(
-                   service.get())
+                   profile_web_data_service_.get())
             ->AsWeakPtr();
       }
       return base::WeakPtr<syncer::SyncableService>();
     }
     case syncer::AUTOFILL_WALLET_METADATA: {
-      // TODO(feuunk): This doesn't allow switching which database to use at
-      // runtime. This should be fixed as part of the USS migration for
-      // payments.
-      auto service = account_web_data_service_ ? account_web_data_service_
-                                               : profile_web_data_service_;
-      if (service) {
+      if (profile_web_data_service_) {
         return autofill::AutofillWalletMetadataSyncableService::
-            FromWebDataService(service.get())
+            FromWebDataService(profile_web_data_service_.get())
                 ->AsWeakPtr();
       }
       return base::WeakPtr<syncer::SyncableService>();
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index e5b8d780..1b7301f 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -48,24 +48,14 @@
     cocoa_browser_sources = [
       "cocoa/browser_dialogs_views_mac.cc",
       "cocoa/browser_dialogs_views_mac.h",
-      "cocoa/browser_window_layout.h",
-      "cocoa/browser_window_layout.mm",
-      "cocoa/browser_window_utils.h",
-      "cocoa/browser_window_utils.mm",
       "cocoa/bubble_anchor_helper.h",
       "cocoa/bubble_anchor_helper.mm",
       "cocoa/certificate_viewer_mac_cocoa.h",
       "cocoa/certificate_viewer_mac_cocoa.mm",
-      "cocoa/chrome_browser_window.h",
-      "cocoa/chrome_browser_window.mm",
-      "cocoa/chrome_event_processing_window.h",
-      "cocoa/chrome_event_processing_window.mm",
       "cocoa/constrained_window/constrained_window_control_utils.h",
       "cocoa/constrained_window/constrained_window_control_utils.mm",
       "cocoa/constrained_window/constrained_window_custom_sheet.h",
       "cocoa/constrained_window/constrained_window_custom_sheet.mm",
-      "cocoa/constrained_window/constrained_window_custom_window.h",
-      "cocoa/constrained_window/constrained_window_custom_window.mm",
       "cocoa/constrained_window/constrained_window_mac.h",
       "cocoa/constrained_window/constrained_window_mac.mm",
       "cocoa/constrained_window/constrained_window_sheet.h",
@@ -79,10 +69,6 @@
       "cocoa/drag_util.mm",
       "cocoa/extensions/extension_keybinding_registry_cocoa.h",
       "cocoa/extensions/extension_keybinding_registry_cocoa.mm",
-      "cocoa/fast_resize_view.h",
-      "cocoa/fast_resize_view.mm",
-      "cocoa/framed_browser_window.h",
-      "cocoa/framed_browser_window.mm",
       "cocoa/fullscreen/fullscreen_menubar_tracker.h",
       "cocoa/fullscreen/fullscreen_menubar_tracker.mm",
       "cocoa/fullscreen/fullscreen_toolbar_animation_controller.h",
@@ -97,11 +83,8 @@
       "cocoa/fullscreen/fullscreen_toolbar_visibility_lock_controller.mm",
       "cocoa/fullscreen/immersive_fullscreen_controller.h",
       "cocoa/fullscreen/immersive_fullscreen_controller.mm",
-      "cocoa/has_weak_browser_pointer.h",
       "cocoa/javascript_app_modal_dialog_cocoa.h",
       "cocoa/javascript_app_modal_dialog_cocoa.mm",
-      "cocoa/location_bar/location_bar_view_mac.h",
-      "cocoa/location_bar/location_bar_view_mac.mm",
       "cocoa/main_menu_item.h",
       "cocoa/restart_browser.h",
       "cocoa/restart_browser.mm",
@@ -111,16 +94,6 @@
       "cocoa/single_web_contents_dialog_manager_cocoa.mm",
       "cocoa/ssl_client_certificate_selector_cocoa.h",
       "cocoa/ssl_client_certificate_selector_cocoa.mm",
-      "cocoa/tab_contents/overlayable_contents_controller.h",
-      "cocoa/tab_contents/overlayable_contents_controller.mm",
-      "cocoa/tab_contents/tab_contents_controller.h",
-      "cocoa/tab_contents/tab_contents_controller.mm",
-      "cocoa/tabbed_browser_window.h",
-      "cocoa/tabbed_browser_window.mm",
-      "cocoa/tabs/tab_window_controller.h",
-      "cocoa/tabs/tab_window_controller.mm",
-      "cocoa/themed_window.h",
-      "cocoa/themed_window.mm",
       "cocoa/touchbar/credit_card_autofill_touch_bar_controller.h",
       "cocoa/touchbar/credit_card_autofill_touch_bar_controller.mm",
       "cocoa/touchbar/text_suggestions_touch_bar_controller.h",
@@ -129,12 +102,6 @@
       "cocoa/touchbar/web_textfield_touch_bar_controller.mm",
       "cocoa/url_drop_target.h",
       "cocoa/url_drop_target.mm",
-      "cocoa/view_resizer.h",
-
-      # TODO(estade): this class should be deleted in favor of a combobox model.
-      # See crbug.com/590850
-      "content_settings/content_setting_media_menu_model.cc",
-      "content_settings/content_setting_media_menu_model.h",
     ]
   }
 
@@ -2011,8 +1978,6 @@
       "cocoa/accelerator_utils_cocoa.mm",
       "cocoa/accelerators_cocoa.h",
       "cocoa/accelerators_cocoa.mm",
-      "cocoa/animated_icon.h",
-      "cocoa/animated_icon.mm",
       "cocoa/applescript/apple_event_util.h",
       "cocoa/applescript/apple_event_util.mm",
       "cocoa/applescript/bookmark_folder_applescript.h",
@@ -2049,8 +2014,6 @@
       "cocoa/browser_window_command_handler.mm",
       "cocoa/chrome_command_dispatcher_delegate.h",
       "cocoa/chrome_command_dispatcher_delegate.mm",
-      "cocoa/chrome_style.cc",
-      "cocoa/chrome_style.h",
       "cocoa/color_chooser_mac.h",
       "cocoa/color_chooser_mac.mm",
       "cocoa/confirm_quit.cc",
@@ -2084,8 +2047,6 @@
       "cocoa/last_active_browser_cocoa.h",
       "cocoa/main_menu_builder.h",
       "cocoa/main_menu_builder.mm",
-      "cocoa/md_util.h",
-      "cocoa/md_util.mm",
       "cocoa/media_picker/desktop_media_picker_bridge.h",
       "cocoa/media_picker/desktop_media_picker_bridge.mm",
       "cocoa/media_picker/desktop_media_picker_cocoa.h",
@@ -2132,11 +2093,6 @@
       "cocoa/web_contents_modal_dialog_host_cocoa.mm",
       "cocoa/window_size_autosaver.h",
       "cocoa/window_size_autosaver.mm",
-
-      # TODO(estade): this class should be folded into
-      # manage_passwords_decoration.mm
-      "passwords/manage_passwords_icon.cc",
-      "passwords/manage_passwords_icon.h",
       "views/apps/chrome_app_window_client_views_mac.mm",
       "views/certificate_viewer_mac_views.mm",
       "views/dropdown_bar_host_mac.mm",
diff --git a/chrome/browser/ui/cocoa/animated_icon.h b/chrome/browser/ui/cocoa/animated_icon.h
deleted file mode 100644
index 76cfe2b..0000000
--- a/chrome/browser/ui/cocoa/animated_icon.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2017 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 CHROME_BROWSER_UI_COCOA_ANIMATED_ICON_H_
-#define CHROME_BROWSER_UI_COCOA_ANIMATED_ICON_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/time/time.h"
-#include "ui/gfx/animation/animation_delegate.h"
-#include "ui/gfx/vector_icon_types.h"
-
-namespace gfx {
-
-class LinearAnimation;
-
-}  // namespace gfx
-
-// This class hosts a vector icon that defines transitions. It can be in the
-// start steady state, the end steady state, or transitioning in between.
-class AnimatedIcon : public gfx::AnimationDelegate {
- public:
-  AnimatedIcon(const gfx::VectorIcon& icon, NSView* host_view);
-  ~AnimatedIcon() override;
-
-  void set_color(SkColor color) { color_ = color; }
-
-  // Animates the icon. Restart from the beginning if it's already running.
-  // Virtual for testing.
-  virtual void Animate();
-
-  // Paints the icon on the current drawing context, centered in |frame|.
-  // Requires a NSGraphicsContext to be present.
-  void PaintIcon(NSRect frame);
-
-  // Returns true if |animation_| is currently animating. Virtual for testing.
-  virtual bool IsAnimating() const;
-
-  // gfx::AnimationDelegate:
-  void AnimationEnded(const gfx::Animation* animation) override;
-  void AnimationProgressed(const gfx::Animation* animation) override;
-
- private:
-  const gfx::VectorIcon& icon_;
-
-  // The NSView object that's displaying the icon.
-  NSView* const host_view_;
-
-  // The length of the animation.
-  const base::TimeDelta duration_;
-
-  std::unique_ptr<gfx::LinearAnimation> animation_;
-
-  SkColor color_;
-
-  DISALLOW_COPY_AND_ASSIGN(AnimatedIcon);
-};
-
-#endif  // CHROME_BROWSER_UI_COCOA_ANIMATED_ICON_H_
diff --git a/chrome/browser/ui/cocoa/animated_icon.mm b/chrome/browser/ui/cocoa/animated_icon.mm
deleted file mode 100644
index 2093d7d..0000000
--- a/chrome/browser/ui/cocoa/animated_icon.mm
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2017 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 "chrome/browser/ui/cocoa/animated_icon.h"
-
-#include "ui/gfx/animation/linear_animation.h"
-#include "ui/gfx/canvas_skia_paint.h"
-#include "ui/gfx/paint_vector_icon.h"
-
-AnimatedIcon::AnimatedIcon(const gfx::VectorIcon& icon, NSView* host_view)
-    : icon_(icon),
-      host_view_(host_view),
-      duration_(gfx::GetDurationOfAnimation(icon)),
-      animation_(std::make_unique<gfx::LinearAnimation>(this)) {
-  animation_->SetDuration(duration_);
-}
-
-AnimatedIcon::~AnimatedIcon() {}
-
-void AnimatedIcon::Animate() {
-  animation_->End();
-  animation_->Start();
-}
-
-void AnimatedIcon::PaintIcon(NSRect frame) {
-  gfx::CanvasSkiaPaint canvas(frame, false);
-  canvas.set_composite_alpha(true);
-
-  int size = GetDefaultSizeOfVectorIcon(icon_);
-  canvas.Translate(
-      gfx::Vector2d((NSWidth(frame) - size) / 2, (NSHeight(frame) - size) / 2));
-  base::TimeDelta elapsed = animation_->GetCurrentValue() * duration_;
-  gfx::PaintVectorIcon(&canvas, icon_, color_, elapsed);
-
-  canvas.Restore();
-}
-
-bool AnimatedIcon::IsAnimating() const {
-  return animation_->is_animating();
-}
-
-void AnimatedIcon::AnimationEnded(const gfx::Animation* animation) {}
-
-void AnimatedIcon::AnimationProgressed(const gfx::Animation* animation) {
-  [host_view_ setNeedsDisplay:YES];
-}
diff --git a/chrome/browser/ui/cocoa/browser_window_layout.h b/chrome/browser/ui/cocoa/browser_window_layout.h
deleted file mode 100644
index 0628343..0000000
--- a/chrome/browser/ui/cocoa/browser_window_layout.h
+++ /dev/null
@@ -1,175 +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 CHROME_BROWSER_UI_COCOA_BROWSER_WINDOW_LAYOUT_H_
-#define CHROME_BROWSER_UI_COCOA_BROWSER_WINDOW_LAYOUT_H_
-
-#import <Cocoa/Cocoa.h>
-
-namespace chrome {
-
-// The height of the tab strip.
-extern const CGFloat kTabStripHeight;
-
-// Returns true if windows should use NSFullSizeContentViewWindowMask style
-// mask.
-bool ShouldUseFullSizeContentView();
-
-// The parameters used to calculate the layout of the views managed by the
-// BrowserWindowController.
-struct LayoutParameters {
-  // The size of the content view of the window.
-  NSSize contentViewSize;
-  // The size of the window.
-  NSSize windowSize;
-
-  // Whether the controller is in any fullscreen mode. This parameter should be
-  // NO if the controller is in the process of entering fullscreen.
-  BOOL inAnyFullscreen;
-  // The minY of the AppKit Menu Bar, relative to the top of the screen. Ranges
-  // from 0 to -22. Only relevant in fullscreen mode.
-  CGFloat menubarOffset;
-  // The fraction of the toolbar that is visible in fullscreen mode.
-  // Ranges from 0 to 1. Only relevant in fullscreen mode.
-  CGFloat toolbarFraction;
-
-  BOOL hasTabStrip;
-  // The frame of the fullscreen button. May be NSZeroRect if the fullscreen
-  // button doesn't exist. Only needs to be set when hasTabStrip is YES.
-  NSRect fullscreenButtonFrame;
-  // Whether the avatar button should be shown. Only needs to be set when
-  // hasTabStrip is YES.
-  BOOL shouldShowAvatar;
-  // Whether to use the new avatar button. Only needs to be set when
-  // shouldShowAvatar is YES.
-  BOOL shouldUseNewAvatar;
-  // True if the avatar button is a generic avatar.
-  BOOL isGenericAvatar;
-  // The size of the avatar button. Only needs to be set when shouldShowAvatar
-  // is YES.
-  NSSize avatarSize;
-  // The line width that will generate a 1 pixel wide line for the avatar's
-  // superview. Only needs to be set when shouldShowAvatar is YES.
-  CGFloat avatarLineWidth;
-
-  BOOL hasToolbar;
-  BOOL hasLocationBar;
-  CGFloat toolbarHeight;
-
-  BOOL bookmarkBarHidden;
-  // If the bookmark bar is not hidden, then the bookmark bar should either be
-  // directly below the omnibox, or directly below the info bar. This parameter
-  // selects between those 2 cases.
-  BOOL placeBookmarkBarBelowInfoBar;
-  CGFloat bookmarkBarHeight;
-
-  CGFloat infoBarHeight;
-
-  BOOL hasDownloadShelf;
-  CGFloat downloadShelfHeight;
-
-  // This parameter exists so that unit tests can configure the OS version.
-  BOOL isOSYosemiteOrLater;
-};
-
-// The parameters required to lay out the tab strip and its components.
-struct TabStripLayout {
-  // The frame of the tab strip in window coordinates.
-  NSRect frame;
-  // The leading indent for the controls of the TabStripControllerCocoa.
-  CGFloat leadingIndent;
-  // The trailing indent for the controls of the TabStripControllerCocoa.
-  CGFloat trailingIndent;
-  // Whether the TabStripControllerCocoa needs to add custom traffic light
-  // buttons.
-  BOOL addCustomWindowControls;
-  // The frame of the avatar in window coordinates.
-  NSRect avatarFrame;
-};
-
-// The output frames of the views managed by the BrowserWindowController. All
-// frames are in the coordinate system of the window. The lower-left corner of
-// the contentView coincides with the lower-left corner of the window, so these
-// frames are also in the coordinate system of the contentView.
-struct LayoutOutput {
-  TabStripLayout tabStripLayout;
-  NSRect toolbarFrame;
-  NSRect bookmarkFrame;
-  NSRect fullscreenBackingBarFrame;
-  CGFloat findBarMaxY;
-  NSRect infoBarFrame;
-  NSRect downloadShelfFrame;
-  NSRect contentAreaFrame;
-};
-
-}  // namespace chrome
-
-// This class is the sole entity responsible for calculating the layout of the
-// views managed by the BrowserWindowController. The parameters used to
-// calculate the layout are the fields of |parameters_|. These fields should be
-// filled by calling the appropriate setters on this class. Once the parameters
-// have been set, calling -computeLayout will return a LayoutOutput that
-// includes sufficient information to lay out all views managed by
-// BrowserWindowController.
-//
-// This is a lightweight class. It should be created on demand.
-@interface BrowserWindowLayout : NSObject {
- @private
-  // Stores the parameters used to compute layout.
-  chrome::LayoutParameters parameters_;
-
-  // Stores the layout output as it's being computed.
-  chrome::LayoutOutput output_;
-
-  // The offset of the maxY of the tab strip during fullscreen mode.
-  CGFloat fullscreenYOffset_;
-
-  // The views are laid out from highest Y to lowest Y. This variable holds the
-  // current highest Y that the next view is expected to be laid under.
-  CGFloat maxY_;
-}
-
-// Designated initializer.
-- (instancetype)init;
-
-// Performs the layout computation and returns the results. This method is fast
-// and does not perform any caching.
-- (chrome::LayoutOutput)computeLayout;
-
-- (void)setContentViewSize:(NSSize)size;
-- (void)setWindowSize:(NSSize)size;
-
-// Whether the controller is in any fullscreen mode. |inAnyFullscreen| should
-// be NO if the controller is in the process of entering fullscreen.
-- (void)setInAnyFullscreen:(BOOL)inAnyFullscreen;
-- (void)setFullscreenMenubarOffset:(CGFloat)menubarOffset;
-- (void)setFullscreenToolbarFraction:(CGFloat)toolbarFraction;
-
-- (void)setHasTabStrip:(BOOL)hasTabStrip;
-- (void)setFullscreenButtonFrame:(NSRect)frame;
-- (void)setShouldShowAvatar:(BOOL)shouldShowAvatar;
-- (void)setShouldUseNewAvatar:(BOOL)shouldUseNewAvatar;
-- (void)setIsGenericAvatar:(BOOL)isGenericAvatar;
-- (void)setAvatarSize:(NSSize)avatarSize;
-- (void)setAvatarLineWidth:(CGFloat)avatarLineWidth;
-
-- (void)setHasToolbar:(BOOL)hasToolbar;
-- (void)setHasLocationBar:(BOOL)hasLocationBar;
-- (void)setToolbarHeight:(CGFloat)toolbarHeight;
-
-- (void)setBookmarkBarHidden:(BOOL)bookmarkBarHidden;
-- (void)setPlaceBookmarkBarBelowInfoBar:(BOOL)placeBookmarkBarBelowInfoBar;
-- (void)setBookmarkBarHeight:(CGFloat)bookmarkBarHeight;
-
-- (void)setInfoBarHeight:(CGFloat)infoBarHeight;
-
-- (void)setHasDownloadShelf:(BOOL)hasDownloadShelf;
-- (void)setDownloadShelfHeight:(CGFloat)downloadShelfHeight;
-@end
-
-@interface BrowserWindowLayout (ExposedForTesting)
-- (void)setOSYosemiteOrLater:(BOOL)osYosemiteOrLater;
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_BROWSER_WINDOW_LAYOUT_H_
diff --git a/chrome/browser/ui/cocoa/browser_window_layout.mm b/chrome/browser/ui/cocoa/browser_window_layout.mm
deleted file mode 100644
index 7bf0fc4..0000000
--- a/chrome/browser/ui/cocoa/browser_window_layout.mm
+++ /dev/null
@@ -1,289 +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.
-
-#import "chrome/browser/ui/cocoa/browser_window_layout.h"
-
-#include <math.h>
-#include <string.h>
-
-#include "base/logging.h"
-#include "base/mac/mac_util.h"
-#include "chrome/browser/ui/cocoa/l10n_util.h"
-#include "chrome/common/chrome_features.h"
-
-namespace chrome {
-
-// The height of the tab strip.
-const CGFloat kTabStripHeight = 37;
-
-bool ShouldUseFullSizeContentView() {
-  // Chrome historically added a subview to the window's frame view
-  // (window.contentView.superview), which AppKit warns about at runtime. This
-  // stopped the window buttons from being covered by the content view. This
-  // may break in a future macOS release. NSFullSizeContentViewWindowMask is a
-  // new (10.10+), supported way to make the content view the full size of the
-  // window without covering the controls. It's only enabled in 10.12+ due to a
-  // performance regression seen in 10.11 (https://crbug.com/742472).
-  return base::FeatureList::IsEnabled(features::kMacFullSizeContentView) &&
-         base::mac::IsAtLeastOS10_12();
-}
-
-}  // namespace chrome
-
-namespace {
-
-// Insets for the location bar, used when the full toolbar is hidden.
-// TODO(viettrungluu): We can argue about the "correct" insetting; I like the
-// following best, though arguably 0 inset is better/more correct.
-const CGFloat kLocBarLeftRightInset = 1;
-const CGFloat kLocBarTopInset = 0;
-const CGFloat kLocBarBottomInset = 1;
-
-}  // namespace
-
-@interface BrowserWindowLayout ()
-
-// Computes the y offset to use when laying out the tab strip in fullscreen
-// mode.
-- (void)computeFullscreenYOffset;
-
-// Computes the layout of the tab strip.
-- (void)computeTabStripLayout;
-
-// Computes the layout of the subviews of the content view.
-- (void)computeContentViewLayout;
-
-// Computes the height of the backing bar for the views in the omnibox area in
-// fullscreen mode.
-- (CGFloat)fullscreenBackingBarHeight;
-
-@end
-
-@implementation BrowserWindowLayout
-
-- (instancetype)init {
-  if ((self = [super init])) {
-    parameters_.isOSYosemiteOrLater = base::mac::IsAtLeastOS10_10();
-  }
-  return self;
-}
-
-- (chrome::LayoutOutput)computeLayout {
-  memset(&output_, 0, sizeof(chrome::LayoutOutput));
-
-  [self computeFullscreenYOffset];
-  [self computeTabStripLayout];
-  [self computeContentViewLayout];
-
-  return output_;
-}
-
-- (void)setContentViewSize:(NSSize)size {
-  parameters_.contentViewSize = size;
-}
-
-- (void)setWindowSize:(NSSize)size {
-  parameters_.windowSize = size;
-}
-
-- (void)setInAnyFullscreen:(BOOL)inAnyFullscreen {
-  parameters_.inAnyFullscreen = inAnyFullscreen;
-}
-
-- (void)setFullscreenMenubarOffset:(CGFloat)menubarOffset {
-  parameters_.menubarOffset = menubarOffset;
-}
-
-- (void)setFullscreenToolbarFraction:(CGFloat)toolbarFraction {
-  parameters_.toolbarFraction = toolbarFraction;
-}
-
-- (void)setHasTabStrip:(BOOL)hasTabStrip {
-  parameters_.hasTabStrip = hasTabStrip;
-}
-
-- (void)setFullscreenButtonFrame:(NSRect)frame {
-  parameters_.fullscreenButtonFrame = frame;
-}
-
-- (void)setShouldShowAvatar:(BOOL)shouldShowAvatar {
-  parameters_.shouldShowAvatar = shouldShowAvatar;
-}
-
-- (void)setShouldUseNewAvatar:(BOOL)shouldUseNewAvatar {
-  parameters_.shouldUseNewAvatar = shouldUseNewAvatar;
-}
-
-- (void)setIsGenericAvatar:(BOOL)isGenericAvatar {
-  parameters_.isGenericAvatar = isGenericAvatar;
-}
-
-- (void)setAvatarSize:(NSSize)avatarSize {
-  parameters_.avatarSize = avatarSize;
-}
-
-- (void)setAvatarLineWidth:(CGFloat)avatarLineWidth {
-  parameters_.avatarLineWidth = avatarLineWidth;
-}
-
-- (void)setHasToolbar:(BOOL)hasToolbar {
-  parameters_.hasToolbar = hasToolbar;
-}
-
-- (void)setHasLocationBar:(BOOL)hasLocationBar {
-  parameters_.hasLocationBar = hasLocationBar;
-}
-
-- (void)setToolbarHeight:(CGFloat)toolbarHeight {
-  parameters_.toolbarHeight = toolbarHeight;
-}
-
-- (void)setBookmarkBarHidden:(BOOL)bookmarkBarHidden {
-  parameters_.bookmarkBarHidden = bookmarkBarHidden;
-}
-
-- (void)setPlaceBookmarkBarBelowInfoBar:(BOOL)placeBookmarkBarBelowInfoBar {
-  parameters_.placeBookmarkBarBelowInfoBar = placeBookmarkBarBelowInfoBar;
-}
-
-- (void)setBookmarkBarHeight:(CGFloat)bookmarkBarHeight {
-  parameters_.bookmarkBarHeight = bookmarkBarHeight;
-}
-
-- (void)setInfoBarHeight:(CGFloat)infoBarHeight {
-  parameters_.infoBarHeight = infoBarHeight;
-}
-
-- (void)setHasDownloadShelf:(BOOL)hasDownloadShelf {
-  parameters_.hasDownloadShelf = hasDownloadShelf;
-}
-
-- (void)setDownloadShelfHeight:(CGFloat)downloadShelfHeight {
-  parameters_.downloadShelfHeight = downloadShelfHeight;
-}
-
-- (void)computeFullscreenYOffset {
-  CGFloat yOffset = 0;
-  if (parameters_.inAnyFullscreen) {
-    yOffset += parameters_.menubarOffset;
-    yOffset += std::floor((1 - parameters_.toolbarFraction) *
-                          [self fullscreenBackingBarHeight]);
-  }
-  fullscreenYOffset_ = yOffset;
-}
-
-- (void)computeTabStripLayout {
-}
-
-- (void)computeContentViewLayout {
-  chrome::LayoutParameters parameters = parameters_;
-  CGFloat maxY = maxY_;
-
-  // Sanity-check |maxY|.
-  DCHECK_GE(maxY, 0);
-  DCHECK_LE(maxY, parameters_.contentViewSize.height + fullscreenYOffset_);
-
-  CGFloat width = parameters_.contentViewSize.width;
-
-  // Lay out the toolbar.
-  if (parameters.hasToolbar) {
-    CGFloat toolbarY = maxY;
-    output_.toolbarFrame = NSMakeRect(0, toolbarY - parameters_.toolbarHeight,
-                                      width, parameters_.toolbarHeight);
-    maxY = NSMinY(output_.toolbarFrame);
-  } else if (parameters_.hasLocationBar) {
-    CGFloat toolbarX = kLocBarLeftRightInset;
-    CGFloat toolbarY = maxY - parameters_.toolbarHeight - kLocBarTopInset;
-    CGFloat toolbarWidth = width - 2 * kLocBarLeftRightInset;
-    output_.toolbarFrame =
-        NSMakeRect(toolbarX, toolbarY, toolbarWidth, parameters_.toolbarHeight);
-    maxY = NSMinY(output_.toolbarFrame) - kLocBarBottomInset;
-  }
-
-  // Lay out the bookmark bar, if it's above the info bar.
-  if (!parameters.bookmarkBarHidden &&
-      !parameters.placeBookmarkBarBelowInfoBar) {
-    output_.bookmarkFrame = NSMakeRect(0,
-                                       maxY - parameters.bookmarkBarHeight,
-                                       width,
-                                       parameters.bookmarkBarHeight);
-    maxY = NSMinY(output_.bookmarkFrame);
-  }
-
-  // Lay out the backing bar in fullscreen mode.
-  if (parameters_.inAnyFullscreen) {
-    output_.fullscreenBackingBarFrame =
-        NSMakeRect(0, maxY, width, [self fullscreenBackingBarHeight]);
-  }
-
-  // Place the find bar immediately below the toolbar/attached bookmark bar.
-  output_.findBarMaxY = maxY;
-
-  // Lay out the info bar. It is never hidden.
-  if (parameters_.infoBarHeight != 0) {
-    CGFloat infoBarMaxY = maxY;
-    CGFloat infoBarMinY = maxY - parameters_.infoBarHeight;
-
-    output_.infoBarFrame =
-        NSMakeRect(0, infoBarMinY, width, infoBarMaxY - infoBarMinY);
-    maxY = NSMinY(output_.infoBarFrame);
-  } else {
-    // The info bar has 0 height, but tests still expect it in the right
-    // location.
-    output_.infoBarFrame = NSMakeRect(0, maxY, width, 0);
-  }
-
-  // Lay out the bookmark bar when it is below the info bar.
-  if (!parameters.bookmarkBarHidden &&
-      parameters.placeBookmarkBarBelowInfoBar) {
-    output_.bookmarkFrame = NSMakeRect(0,
-                                       maxY - parameters.bookmarkBarHeight,
-                                       width,
-                                       parameters.bookmarkBarHeight);
-    maxY = NSMinY(output_.bookmarkFrame);
-  }
-
-  // Layout the download shelf at the bottom of the content view.
-  CGFloat minY = 0;
-  if (parameters.hasDownloadShelf) {
-    output_.downloadShelfFrame =
-        NSMakeRect(0, 0, width, parameters.downloadShelfHeight);
-    minY = NSMaxY(output_.downloadShelfFrame);
-  }
-
-  // All the remaining space becomes the frame of the content area.
-  output_.contentAreaFrame = NSMakeRect(0, minY, width, maxY - minY);
-}
-
-- (CGFloat)fullscreenBackingBarHeight {
-  if (!parameters_.inAnyFullscreen)
-    return 0;
-
-  CGFloat totalHeight = 0;
-  if (parameters_.hasTabStrip)
-    totalHeight += chrome::kTabStripHeight;
-
-  if (parameters_.hasToolbar) {
-    totalHeight += parameters_.toolbarHeight;
-  } else if (parameters_.hasLocationBar) {
-    totalHeight +=
-        parameters_.toolbarHeight + kLocBarTopInset + kLocBarBottomInset;
-  }
-
-  if (!parameters_.bookmarkBarHidden &&
-      !parameters_.placeBookmarkBarBelowInfoBar)
-    totalHeight += parameters_.bookmarkBarHeight;
-
-  return totalHeight;
-}
-
-@end
-
-@implementation BrowserWindowLayout (ExposedForTesting)
-
-- (void)setOSYosemiteOrLater:(BOOL)osYosemiteOrLater {
-  parameters_.isOSYosemiteOrLater = osYosemiteOrLater;
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/browser_window_utils.h b/chrome/browser/ui/cocoa/browser_window_utils.h
deleted file mode 100644
index 210ecc2d..0000000
--- a/chrome/browser/ui/cocoa/browser_window_utils.h
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright (c) 2011 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 CHROME_BROWSER_UI_COCOA_BROWSER_WINDOW_UTILS_H_
-#define CHROME_BROWSER_UI_COCOA_BROWSER_WINDOW_UTILS_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "chrome/browser/ui/cocoa/themed_window.h"
-
-namespace content {
-struct NativeWebKeyboardEvent;
-}
-
-@interface BrowserWindowUtils : NSObject
-
-// Returns YES if keyboard event should be handled.
-+ (BOOL)shouldHandleKeyboardEvent:(const content::NativeWebKeyboardEvent&)event;
-
-// Returns YES if keyboard event is a text editing command such as Copy or Paste
-+ (BOOL)isTextEditingEvent:(const content::NativeWebKeyboardEvent&)event;
-
-// Determines the command associated with the keyboard event.
-// Returns -1 if no command found.
-+ (int)getCommandId:(const content::NativeWebKeyboardEvent&)event;
-
-// NSWindow must be a ChromeEventProcessingWindow.
-+ (BOOL)handleKeyboardEvent:(NSEvent*)event
-                   inWindow:(NSWindow*)window;
-
-// Schedule a window title change in the next run loop iteration. This works
-// around a Cocoa bug: if a window changes title during the tracking of the
-// Window menu it doesn't display well and the constant re-sorting of the list
-// makes it difficult for the user to pick the desired window.
-// Passing in a non-nil oldTitle will also cancel any pending title changes with
-// a matching window and title. This function returns a NSString* that can be
-// passed in future calls as oldTitle.
-+ (NSString*)scheduleReplaceOldTitle:(NSString*)oldTitle
-                        withNewTitle:(NSString*)newTitle
-                           forWindow:(NSWindow*)window;
-
-// Returns the position in the coordinates of |windowView| that the top left of
-// a theme image should be painted at. See
-// [BrowserWindowController themeImagePositionForAlignment:] for more details.
-+ (NSPoint)themeImagePositionFor:(NSView*)windowView
-                    withTabStrip:(NSView*)tabStripView
-                       alignment:(ThemeImageAlignment)alignment;
-
-// Returns the position in the coordinates of |tabStripView| that the top left
-// of a theme image should be painted at. This method exists so that the
-// position can be queried by the new tab button before the tab strip is layed
-// out.
-+ (NSPoint)themeImagePositionInTabStripCoords:(NSView*)tabStripView
-                                    alignment:(ThemeImageAlignment)alignment;
-
-+ (void)activateWindowForController:(NSWindowController*)controller;
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_BROWSER_WINDOW_UTILS_H_
diff --git a/chrome/browser/ui/cocoa/browser_window_utils.mm b/chrome/browser/ui/cocoa/browser_window_utils.mm
deleted file mode 100644
index 9034459..0000000
--- a/chrome/browser/ui/cocoa/browser_window_utils.mm
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright (c) 2011 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.
-
-#import "chrome/browser/ui/cocoa/browser_window_utils.h"
-
-#include "base/logging.h"
-#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/global_keyboard_shortcuts_mac.h"
-#include "chrome/browser/ui/browser.h"
-#import "chrome/browser/ui/cocoa/chrome_event_processing_window.h"
-#include "content/public/browser/native_web_keyboard_event.h"
-#include "ui/base/material_design/material_design_controller.h"
-#include "ui/events/keycodes/keyboard_codes.h"
-
-using content::NativeWebKeyboardEvent;
-
-namespace {
-
-CGFloat GetPatternVerticalOffsetWithTabStrip(bool tabStripVisible) {
-  // Without tab strip, offset an extra pixel (determined by experimentation).
-  return tabStripVisible ? -1 : 0;
-}
-
-}  // namespace
-
-
-@implementation BrowserWindowUtils
-+ (BOOL)shouldHandleKeyboardEvent:(const NativeWebKeyboardEvent&)event {
-  if (event.skip_in_browser || event.GetType() == NativeWebKeyboardEvent::kChar)
-    return NO;
-  DCHECK(event.os_event != NULL);
-  return YES;
-}
-
-+ (BOOL)isTextEditingEvent:(const content::NativeWebKeyboardEvent&)event {
-  return (event.GetModifiers() & blink::WebInputEvent::kMetaKey) &&
-         (event.windows_key_code == ui::VKEY_A ||
-          event.windows_key_code == ui::VKEY_V ||
-          event.windows_key_code == ui::VKEY_C ||
-          event.windows_key_code == ui::VKEY_X ||
-          event.windows_key_code == ui::VKEY_Z);
-}
-
-+ (int)getCommandId:(const NativeWebKeyboardEvent&)event {
-  return CommandForKeyEvent(event.os_event).chrome_command;
-}
-
-+ (BOOL)handleKeyboardEvent:(NSEvent*)event
-                   inWindow:(NSWindow*)window {
-  ChromeEventProcessingWindow* event_window =
-      static_cast<ChromeEventProcessingWindow*>(window);
-  DCHECK([event_window isKindOfClass:[ChromeEventProcessingWindow class]]);
-
-  return [[event_window commandDispatcher] redispatchKeyEvent:event];
-}
-
-+ (NSString*)scheduleReplaceOldTitle:(NSString*)oldTitle
-                        withNewTitle:(NSString*)newTitle
-                           forWindow:(NSWindow*)window {
-  if (oldTitle)
-    [[NSRunLoop currentRunLoop]
-        cancelPerformSelector:@selector(setTitle:)
-                       target:window
-                     argument:oldTitle];
-
-  [[NSRunLoop currentRunLoop]
-      performSelector:@selector(setTitle:)
-               target:window
-             argument:newTitle
-                order:0
-                modes:[NSArray arrayWithObject:NSDefaultRunLoopMode]];
-  return [newTitle copy];
-}
-
-// The titlebar/tabstrip header on the mac is slightly smaller than on Windows.
-// There is also no window frame to the left and right of the web contents on
-// mac.
-// To keep:
-// - the window background pattern (IDR_THEME_FRAME.*) lined up vertically with
-// the tab and toolbar patterns
-// - the toolbar pattern lined up horizontally with the NTP background.
-// we have to shift the pattern slightly, rather than drawing from the top left
-// corner of the frame / tabstrip. The offsets below were empirically determined
-// in order to line these patterns up.
-//
-// This will make the themes look slightly different than in Windows/Linux
-// because of the differing heights between window top and tab top, but this has
-// been approved by UI.
-const CGFloat kPatternHorizontalOffset = -5;
-
-+ (NSPoint)themeImagePositionFor:(NSView*)windowView
-                    withTabStrip:(NSView*)tabStripView
-                       alignment:(ThemeImageAlignment)alignment {
-  return NSMakePoint(kPatternHorizontalOffset,
-                     NSHeight([windowView bounds]) +
-                         GetPatternVerticalOffsetWithTabStrip(false));
-}
-
-+ (NSPoint)themeImagePositionInTabStripCoords:(NSView*)tabStripView
-                                    alignment:(ThemeImageAlignment)alignment {
-  return NSZeroPoint;
-}
-
-+ (void)activateWindowForController:(NSWindowController*)controller {
-  // Per http://crbug.com/73779 and http://crbug.com/75223, we need this to
-  // properly activate windows if Chrome is not the active application.
-  [[controller window] makeKeyAndOrderFront:controller];
-  [NSApp activateIgnoringOtherApps:YES];
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/browser_window_utils_unittest.mm b/chrome/browser/ui/cocoa/browser_window_utils_unittest.mm
deleted file mode 100644
index 7d0ed4fb..0000000
--- a/chrome/browser/ui/cocoa/browser_window_utils_unittest.mm
+++ /dev/null
@@ -1,44 +0,0 @@
-// 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 "base/strings/stringprintf.h"
-#import "chrome/browser/ui/cocoa/browser_window_utils.h"
-#include "content/public/browser/native_web_keyboard_event.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/events/keycodes/keyboard_codes.h"
-
-using blink::WebInputEvent;
-
-const struct {
-  ui::KeyboardCode key_code;
-  int modifiers;
-  bool is_text_editing_event;
-} kTextEditingEventTestCases[] = {
-    {ui::VKEY_A, WebInputEvent::kMetaKey, true},
-    {ui::VKEY_V, WebInputEvent::kMetaKey, true},
-    {ui::VKEY_C, WebInputEvent::kMetaKey, true},
-    {ui::VKEY_X, WebInputEvent::kMetaKey, true},
-    {ui::VKEY_Z, WebInputEvent::kMetaKey, true},
-
-    {ui::VKEY_A, WebInputEvent::kShiftKey, false},
-    {ui::VKEY_G, WebInputEvent::kMetaKey, false},
-};
-
-TEST(BrowserWindowUtilsTest, TestIsTextEditingEvent) {
-  content::NativeWebKeyboardEvent event(
-      WebInputEvent::kChar, WebInputEvent::kNoModifiers,
-      WebInputEvent::GetStaticTimeStampForTests());
-  EXPECT_FALSE([BrowserWindowUtils isTextEditingEvent:event]);
-
-  for (const auto& test : kTextEditingEventTestCases) {
-    SCOPED_TRACE(base::StringPrintf("key = %c, modifiers = %d",
-                 test.key_code, test.modifiers));
-    content::NativeWebKeyboardEvent event(
-        WebInputEvent::kChar, test.modifiers,
-        WebInputEvent::GetStaticTimeStampForTests());
-    event.windows_key_code = test.key_code;
-    EXPECT_EQ(test.is_text_editing_event,
-              [BrowserWindowUtils isTextEditingEvent:event]);
-  }
-}
diff --git a/chrome/browser/ui/cocoa/chrome_browser_window.h b/chrome/browser/ui/cocoa/chrome_browser_window.h
deleted file mode 100644
index 2974f34d..0000000
--- a/chrome/browser/ui/cocoa/chrome_browser_window.h
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) 2012 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 CHROME_BROWSER_UI_COCOA_CHROME_BROWSER_WINDOW_H_
-#define CHROME_BROWSER_UI_COCOA_CHROME_BROWSER_WINDOW_H_
-
-#import "chrome/browser/ui/cocoa/chrome_event_processing_window.h"
-
-// Common base class for chrome browser windows.
-@interface ChromeBrowserWindow : ChromeEventProcessingWindow
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_CHROME_BROWSER_WINDOW_H_
diff --git a/chrome/browser/ui/cocoa/chrome_browser_window.mm b/chrome/browser/ui/cocoa/chrome_browser_window.mm
deleted file mode 100644
index a644b43..0000000
--- a/chrome/browser/ui/cocoa/chrome_browser_window.mm
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright (c) 2012 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.
-
-#import "chrome/browser/ui/cocoa/chrome_browser_window.h"
-
-#include "base/logging.h"
-#include "chrome/browser/themes/theme_properties.h"
-#import "chrome/browser/ui/cocoa/tabs/tab_window_controller.h"
-#import "chrome/browser/ui/cocoa/themed_window.h"
-#include "ui/base/theme_provider.h"
-
-namespace {
-
-// Upper and lower bounds for determining if a theme's colors indicate that
-// it's a "dark" theme. In Material Design, dark themes have controls that are
-// drawn using transparent white instead of a transparent shade of gray.
-const CGFloat kDarkThemeToolbarColorUpperBound = 0.55;
-const CGFloat kDarkThemeTabTextColorLowerBound = 0.7;
-
-}  // namespace
-
-@interface NSWindow (Private)
-- (BOOL)hasKeyAppearance;
-@end
-
-@implementation ChromeBrowserWindow
-
-- (const ui::ThemeProvider*)themeProvider {
-  id tabWindowController =
-      [TabWindowController tabWindowControllerForWindow:self];
-  if (![tabWindowController respondsToSelector:@selector(themeProvider)])
-    return NULL;
-  return [tabWindowController themeProvider];
-}
-
-- (ThemedWindowStyle)themedWindowStyle {
-  id tabWindowController =
-      [TabWindowController tabWindowControllerForWindow:self];
-  if (![tabWindowController respondsToSelector:@selector(themedWindowStyle)])
-    return THEMED_NORMAL;
-  return [tabWindowController themedWindowStyle];
-}
-
-- (NSPoint)themeImagePositionForAlignment:(ThemeImageAlignment)alignment {
-  id tabWindowController =
-      [TabWindowController tabWindowControllerForWindow:self];
-  if (![tabWindowController
-          respondsToSelector:@selector(themeImagePositionForAlignment:)])
-    return NSZeroPoint;
-  return [tabWindowController themeImagePositionForAlignment:alignment];
-}
-
-- (BOOL)inIncognitoMode {
-  const ui::ThemeProvider* themeProvider = [self themeProvider];
-  return themeProvider && themeProvider->InIncognitoMode();
-}
-
-- (BOOL)inIncognitoModeWithSystemTheme {
-  const ui::ThemeProvider* themeProvider = [self themeProvider];
-  return themeProvider && themeProvider->InIncognitoMode() &&
-      themeProvider->UsingSystemTheme();
-}
-
-- (BOOL)hasDarkTheme {
-  // If a system theme, return YES if Incognito.
-  const ui::ThemeProvider* themeProvider = [self themeProvider];
-  if (!themeProvider) {
-    return NO;
-  } else if (themeProvider->UsingSystemTheme()) {
-    return themeProvider->InIncognitoMode();
-  }
-
-  // If the custom theme has a custom toolbar color, return YES if it's
-  // dark.
-  if (themeProvider->HasCustomColor(ThemeProperties::COLOR_TOOLBAR)) {
-    NSColor* theColor =
-        themeProvider->GetNSColor(ThemeProperties::COLOR_TOOLBAR);
-    theColor =
-        [theColor colorUsingColorSpaceName:NSCalibratedWhiteColorSpace];
-    if (theColor != nil) {
-      // The white componement cutoff is an empirical value.
-      return [theColor whiteComponent] < kDarkThemeToolbarColorUpperBound;
-    }
-  }
-
-  // If the custom theme has a custom tab text color, assume that a light
-  // color means a dark tab background image, and therefore a dark theme.
-  if (themeProvider->HasCustomColor(ThemeProperties::COLOR_TAB_TEXT)) {
-    NSColor* theColor =
-        themeProvider->GetNSColor(ThemeProperties::COLOR_TAB_TEXT);
-    theColor =
-        [theColor colorUsingColorSpaceName:NSCalibratedWhiteColorSpace];
-    if (theColor != nil) {
-      return [theColor whiteComponent] >= kDarkThemeTabTextColorLowerBound;
-    }
-  }
-
-  return NO;
-}
-
-- (BOOL)hasKeyAppearance {
-  // If not key, but a non-main child window without its own traffic lights _is_
-  // key, then show this window with key appearance to keep the traffic lights
-  // lit. This does not currently handle WebModal dialogs, since they are
-  // children of an overlay window. But WebModals also temporarily lose key
-  // status while animating closed, so extra logic is needed to avoid flicker.
-  // Start with an early exit, since this is called for every mouseMove and
-  // every cursor blink in an NSTextField.
-  if (![self isKeyWindow]) {
-    for (NSWindow* child in [self childWindows]) {
-      if ([child isKeyWindow] && ![child isMainWindow] &&
-          ([child styleMask] & NSClosableWindowMask) == 0)
-        return YES;
-    }
-  }
-  return [super hasKeyAppearance];
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/chrome_browser_window_unittest.mm b/chrome/browser/ui/cocoa/chrome_browser_window_unittest.mm
deleted file mode 100644
index 6f13830..0000000
--- a/chrome/browser/ui/cocoa/chrome_browser_window_unittest.mm
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2012 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.
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/debug/debugger.h"
-#include "chrome/app/chrome_command_ids.h"
-#import "chrome/browser/ui/cocoa/chrome_browser_window.h"
-#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-
-class ChromeBrowserWindowTest : public CocoaTest {
- public:
-  void SetUp() override {
-    CocoaTest::SetUp();
-    // Create a window.
-    const NSUInteger mask = NSTitledWindowMask | NSClosableWindowMask |
-        NSMiniaturizableWindowMask | NSResizableWindowMask;
-    window_ = [[ChromeBrowserWindow alloc]
-               initWithContentRect:NSMakeRect(0, 0, 800, 600)
-               styleMask:mask
-               backing:NSBackingStoreBuffered
-               defer:NO];
-    if (base::debug::BeingDebugged()) {
-      [window_ orderFront:nil];
-    } else {
-      [window_ orderBack:nil];
-    }
-  }
-
-  void TearDown() override {
-    [window_ close];
-    CocoaTest::TearDown();
-  }
-
-  ChromeBrowserWindow* window_;
-};
-
-// Baseline test that the window creates, displays, closes, and
-// releases.
-TEST_F(ChromeBrowserWindowTest, ShowAndClose) {
-  [window_ display];
-}
-
diff --git a/chrome/browser/ui/cocoa/chrome_event_processing_window.h b/chrome/browser/ui/cocoa/chrome_event_processing_window.h
deleted file mode 100644
index f68ee77..0000000
--- a/chrome/browser/ui/cocoa/chrome_event_processing_window.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) 2012 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 CHROME_BROWSER_UI_COCOA_CHROME_EVENT_PROCESSING_WINDOW_H_
-#define CHROME_BROWSER_UI_COCOA_CHROME_EVENT_PROCESSING_WINDOW_H_
-
-#import <Cocoa/Cocoa.h>
-
-#import "base/mac/scoped_nsobject.h"
-#import "ui/base/cocoa/command_dispatcher.h"
-#import "ui/base/cocoa/underlay_opengl_hosting_window.h"
-
-@class ChromeCommandDispatcherDelegate;
-
-// Override NSWindow to access unhandled keyboard events (for command
-// processing); subclassing NSWindow is the only method to do
-// this.
-@interface ChromeEventProcessingWindow
-    : UnderlayOpenGLHostingWindow<CommandDispatchingWindow>
-
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_CHROME_EVENT_PROCESSING_WINDOW_H_
diff --git a/chrome/browser/ui/cocoa/chrome_event_processing_window.mm b/chrome/browser/ui/cocoa/chrome_event_processing_window.mm
deleted file mode 100644
index ff69168..0000000
--- a/chrome/browser/ui/cocoa/chrome_event_processing_window.mm
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright (c) 2012 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.
-
-#import "chrome/browser/ui/cocoa/chrome_event_processing_window.h"
-
-#include "base/logging.h"
-#import "base/mac/foundation_util.h"
-#import "chrome/browser/app_controller_mac.h"
-#import "chrome/browser/ui/cocoa/chrome_command_dispatcher_delegate.h"
-#import "ui/base/cocoa/user_interface_item_command_handler.h"
-
-@implementation ChromeEventProcessingWindow {
- @private
-  base::scoped_nsobject<CommandDispatcher> commandDispatcher_;
-  base::scoped_nsobject<ChromeCommandDispatcherDelegate>
-      commandDispatcherDelegate_;
-  base::scoped_nsprotocol<id<UserInterfaceItemCommandHandler>> commandHandler_;
-}
-
-- (instancetype)initWithContentRect:(NSRect)contentRect
-                          styleMask:(NSUInteger)windowStyle
-                            backing:(NSBackingStoreType)bufferingType
-                              defer:(BOOL)deferCreation {
-  if ((self = [super initWithContentRect:contentRect
-                               styleMask:windowStyle
-                                 backing:bufferingType
-                                   defer:deferCreation])) {
-    commandDispatcher_.reset([[CommandDispatcher alloc] initWithOwner:self]);
-    commandDispatcherDelegate_.reset(
-        [[ChromeCommandDispatcherDelegate alloc] init]);
-    [commandDispatcher_ setDelegate:commandDispatcherDelegate_];
-  }
-  return self;
-}
-
-// CommandDispatchingWindow implementation.
-
-- (void)setCommandHandler:(id<UserInterfaceItemCommandHandler>)commandHandler {
-  commandHandler_.reset([commandHandler retain]);
-}
-
-- (CommandDispatcher*)commandDispatcher {
-  return commandDispatcher_.get();
-}
-
-- (BOOL)defaultPerformKeyEquivalent:(NSEvent*)event {
-  return [super performKeyEquivalent:event];
-}
-
-- (BOOL)defaultValidateUserInterfaceItem:
-    (id<NSValidatedUserInterfaceItem>)item {
-  return [super validateUserInterfaceItem:item];
-}
-
-- (void)commandDispatch:(id)sender {
-  [commandDispatcher_ dispatch:sender forHandler:commandHandler_];
-}
-
-- (void)commandDispatchUsingKeyModifiers:(id)sender {
-  [commandDispatcher_ dispatchUsingKeyModifiers:sender
-                                     forHandler:commandHandler_];
-}
-
-// NSWindow overrides.
-
-- (BOOL)performKeyEquivalent:(NSEvent*)event {
-  return [commandDispatcher_ performKeyEquivalent:event];
-}
-
-- (void)sendEvent:(NSEvent*)event {
-  if (![commandDispatcher_ preSendEvent:event])
-    [super sendEvent:event];
-}
-
-// NSWindow overrides (NSUserInterfaceValidations implementation).
-
-- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
-  return [commandDispatcher_ validateUserInterfaceItem:item
-                                            forHandler:commandHandler_];
-}
-
-@end  // ChromeEventProcessingWindow
diff --git a/chrome/browser/ui/cocoa/chrome_style.cc b/chrome/browser/ui/cocoa/chrome_style.cc
deleted file mode 100644
index 19d65b3..0000000
--- a/chrome/browser/ui/cocoa/chrome_style.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2011 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 "chrome/browser/ui/cocoa/chrome_style.h"
-
-#include "chrome/browser/themes/theme_properties.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/gfx/image/image.h"
-#include "ui/resources/grit/ui_resources.h"
-
-namespace chrome_style {
-
-int GetCloseButtonSize() {
-  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-  const SkBitmap* image = rb.GetNativeImageNamed(IDR_CLOSE_DIALOG).ToSkBitmap();
-  DCHECK_EQ(image->width(), image->height());
-  return image->width();
-}
-
-SkColor GetBackgroundColor() {
-  return ThemeProperties::GetDefaultColor(
-      ThemeProperties::COLOR_CONTROL_BACKGROUND, false);
-}
-
-SkColor GetLinkColor() {
-  return SkColorSetRGB(0x11, 0x55, 0xCC);
-}
-
-}  // namespace chrome_style
diff --git a/chrome/browser/ui/cocoa/chrome_style.h b/chrome/browser/ui/cocoa/chrome_style.h
deleted file mode 100644
index 3e20b5c..0000000
--- a/chrome/browser/ui/cocoa/chrome_style.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (c) 2012 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 CHROME_BROWSER_UI_COCOA_CHROME_STYLE_H_
-#define CHROME_BROWSER_UI_COCOA_CHROME_STYLE_H_
-
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/base/resource/resource_bundle.h"
-
-// This file contains constants and functions specifying appearance properties
-// of the new "Chrome-style" UI.
-
-// TODO(wittman): These functions and constants should be moved under src/ui,
-// possibly src/ui/base, as the "Chrome-style" UI will become the default
-// styling for Views.
-
-namespace chrome_style {
-
-int GetCloseButtonSize();  // Size of close button.
-SkColor GetBackgroundColor();  // Dialog background color.
-SkColor GetLinkColor();  // Dialog link color.
-
-const int kTitleTopPadding = 15; // Padding above the title.
-const int kHorizontalPadding = 20; // Left and right padding.
-const int kClientBottomPadding = 20; // Padding below the client view.
-const int kCloseButtonPadding = 7; // Padding around the close button.
-const int kBorderRadius = 2; // Border radius for dialog corners.
-const int kRowPadding = 20; // Padding between rows of text.
-
-// Font style for dialog text.
-const ui::ResourceBundle::FontStyle kTextFontStyle =
-    ui::ResourceBundle::BaseFont;
-// Font style for dialog title.
-const ui::ResourceBundle::FontStyle kTitleFontStyle =
-    ui::ResourceBundle::MediumFont;
-
-}  // namespace chrome_style
-
-#endif  // CHROME_BROWSER_UI_COCOA_CHROME_STYLE_H_
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window.h b/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window.h
deleted file mode 100644
index 5f8772a..0000000
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (c) 2012 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 CHROME_BROWSER_UI_COCOA_CONSTRAINED_WINDOW_CONSTRAINED_WINDOW_CUSTOM_WINDOW_H_
-#define CHROME_BROWSER_UI_COCOA_CONSTRAINED_WINDOW_CONSTRAINED_WINDOW_CUSTOM_WINDOW_H_
-
-#import <Cocoa/Cocoa.h>
-
-#import "chrome/browser/ui/cocoa/chrome_event_processing_window.h"
-
-// A NSWindow subclass that gives a custom look (rounded corners and white
-// background).
-//
-// Note that ConstrainedWindowMac is the web contents modal dialog
-// controller. ConstrainedWindowCustomWindow is the custom NSWindow that gives
-// us the new look (rounded corners and white background).
-//
-// If a ConstrainedWindowMac is using ConstrainedWindowAlert to display its UI
-// then it doesn't have to use this class. On the other hand, if it has some
-// custom UI (say from a nib) then it should use this class.
-@interface ConstrainedWindowCustomWindow : ChromeEventProcessingWindow
-
-// Initializes the window with the given content rect.
-- (id)initWithContentRect:(NSRect)contentRect;
-
-// Initializes the window with the given content rect and style mask.
-- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle;
-
-@end
-
-// The content view for the custom window.
-@interface ConstrainedWindowCustomWindowContentView : NSView
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_CONSTRAINED_WINDOW_CONSTRAINED_WINDOW_CUSTOM_WINDOW_H_
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window.mm
deleted file mode 100644
index b0af90f..0000000
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window.mm
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright (c) 2012 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.
-
-#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window.h"
-
-#include "base/command_line.h"
-#import "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/chrome_style.h"
-#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.h"
-#include "content/public/common/content_switches.h"
-#include "skia/ext/skia_utils_mac.h"
-#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
-
-@implementation ConstrainedWindowCustomWindow
-
-- (id)initWithContentRect:(NSRect)contentRect {
-  return [self initWithContentRect:contentRect
-                         styleMask:NSBorderlessWindowMask];
-}
-
-- (id)initWithContentRect:(NSRect)contentRect
-                styleMask:(NSUInteger)windowStyle {
-  if ((self = [self initWithContentRect:contentRect
-                              styleMask:windowStyle
-                                backing:NSBackingStoreBuffered
-                                  defer:NO])) {
-    base::scoped_nsobject<NSView> contentView(
-        [[ConstrainedWindowCustomWindowContentView alloc]
-            initWithFrame:NSZeroRect]);
-    [self setContentView:contentView];
-  }
-  return self;
-}
-
-- (id)initWithContentRect:(NSRect)contentRect
-                styleMask:(NSUInteger)windowStyle
-                  backing:(NSBackingStoreType)bufferingType
-                    defer:(BOOL)deferCreation {
-  if ((self = [super initWithContentRect:contentRect
-                               styleMask:windowStyle
-                                 backing:bufferingType
-                                   defer:NO])) {
-    // Don't draw shadows in tests, as that causes Window Server crashes on VMs.
-    // https://crbug.com/515627
-    base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-    if (!command_line->HasSwitch(switches::kTestType))
-      [self setHasShadow:YES];
-    [self setBackgroundColor:skia::SkColorToCalibratedNSColor(
-        chrome_style::GetBackgroundColor())];
-    [self setOpaque:NO];
-    [self setReleasedWhenClosed:NO];
-  }
-  return self;
-}
-
-- (BOOL)canBecomeKeyWindow {
-  return YES;
-}
-
-- (NSRect)frameRectForContentRect:(NSRect)windowContent {
-  id<ConstrainedWindowSheet> sheet = [ConstrainedWindowSheetController
-      sheetForOverlayWindow:[self parentWindow]];
-  ConstrainedWindowSheetController* sheetController =
-      [ConstrainedWindowSheetController controllerForSheet:sheet];
-
-  // Sheet controller may be nil if this window hasn't been shown yet.
-  if (!sheetController)
-    return windowContent;
-
-  NSRect frame;
-  frame.origin = [sheetController originForSheet:sheet
-                                  withWindowSize:windowContent.size];
-  frame.size = windowContent.size;
-  return frame;
-}
-
-@end
-
-@implementation ConstrainedWindowCustomWindowContentView
-
-- (void)drawRect:(NSRect)rect {
-  gfx::ScopedNSGraphicsContextSaveGState state;
-
-  // Draw symmetric difference between rect path and oval path as "clear".
-  NSBezierPath* ovalPath = [NSBezierPath
-      bezierPathWithRoundedRect:[self bounds]
-                        xRadius:chrome_style::kBorderRadius
-                        yRadius:chrome_style::kBorderRadius];
-  NSBezierPath* path = [NSBezierPath bezierPathWithRect:[self bounds]];
-  [path appendBezierPath:ovalPath];
-  [path setWindingRule:NSEvenOddWindingRule];
-  [[NSGraphicsContext currentContext] setCompositingOperation:
-      NSCompositeCopy];
-  [[NSColor clearColor] set];
-  [path fill];
-
-  [[self window] invalidateShadow];
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window_unittest.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window_unittest.mm
deleted file mode 100644
index 6123ce2..0000000
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window_unittest.mm
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2012 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.
-
-#import "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window.h"
-#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
-
-class ConstrainedWindowCustomWindowTest : public CocoaTest {
-};
-
-// Simply test creating and drawing the window.
-TEST_F(ConstrainedWindowCustomWindowTest, Basic) {
-  base::scoped_nsobject<ConstrainedWindowCustomWindow> window(
-      [[ConstrainedWindowCustomWindow alloc]
-          initWithContentRect:NSMakeRect(0, 0, 10, 10)]);
-  EXPECT_TRUE([window canBecomeKeyWindow]);
-  EXPECT_FALSE([window canBecomeMainWindow]);
-
-  [window makeKeyAndOrderFront:nil];
-  [window display];
-  [window close];
-}
diff --git a/chrome/browser/ui/cocoa/fast_resize_view.h b/chrome/browser/ui/cocoa/fast_resize_view.h
deleted file mode 100644
index d6a34b46..0000000
--- a/chrome/browser/ui/cocoa/fast_resize_view.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_FAST_RESIZE_VIEW_H_
-#define CHROME_BROWSER_UI_COCOA_FAST_RESIZE_VIEW_H_
-
-#import <Cocoa/Cocoa.h>
-
-// A Cocoa view originally created to support fast re-painting to white on
-// resize. This is done by CoreAnimation now, so this view remains only as the
-// first opaque ancestor of accelerated web contents views.
-@interface FastResizeView : NSView
-
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_FAST_RESIZE_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/fast_resize_view.mm b/chrome/browser/ui/cocoa/fast_resize_view.mm
deleted file mode 100644
index b21e7e5a..0000000
--- a/chrome/browser/ui/cocoa/fast_resize_view.mm
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) 2009 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.
-
-#import "chrome/browser/ui/cocoa/fast_resize_view.h"
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/logging.h"
-#include "base/mac/scoped_nsobject.h"
-#include "ui/base/cocoa/animation_utils.h"
-
-@implementation FastResizeView
-
-- (id)initWithFrame:(NSRect)frameRect {
-  if ((self = [super initWithFrame:frameRect])) {
-    ScopedCAActionDisabler disabler;
-    base::scoped_nsobject<CALayer> layer([[CALayer alloc] init]);
-    [self setLayer:layer];
-    [self setWantsLayer:YES];
-  }
-  return self;
-}
-
-- (BOOL)isOpaque {
-  return YES;
-}
-
-// Override -[NSView hitTest:] to prevent mouse events reaching subviews while
-// the window is displaying a modal sheet. Without this, context menus can be
-// shown on a right-click and trigger all kinds of things (e.g. Print).
-- (NSView*)hitTest:(NSPoint)aPoint {
-  if ([[self window] attachedSheet])
-    return self;
-  return [super hitTest:aPoint];
-}
-
-@end
-
diff --git a/chrome/browser/ui/cocoa/framed_browser_window.h b/chrome/browser/ui/cocoa/framed_browser_window.h
deleted file mode 100644
index 2488946..0000000
--- a/chrome/browser/ui/cocoa/framed_browser_window.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright (c) 2012 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 CHROME_BROWSER_UI_COCOA_FRAMED_BROWSER_WINDOW_H_
-#define CHROME_BROWSER_UI_COCOA_FRAMED_BROWSER_WINDOW_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "chrome/browser/ui/cocoa/chrome_browser_window.h"
-
-// Cocoa class representing a framed browser window.
-// We need to override NSWindow with our own class since we need access to all
-// unhandled keyboard events and subclassing NSWindow is the only method to do
-// this. We also handle our own window controls and custom window frame drawing.
-@interface FramedBrowserWindow : ChromeBrowserWindow {
- @private
-  BOOL shouldHideTitle_;
-
-  // Locks the window's frame and style mask. If it's set to YES, then the
-  // frame and the style mask cannot be changed.
-  BOOL styleMaskLock_;
-}
-
-// The amount of window background image that is painted at the top of the
-// window, so that it shows behind the tap strip area.
-+ (CGFloat)browserFrameViewPaintHeight;
-
-// The style mask which -initWithContentRect: will use to create the window.
-// May be overridden by subclasses.
-+ (NSUInteger)defaultStyleMask;
-
-- (id)initWithContentRect:(NSRect)contentRect NS_DESIGNATED_INITIALIZER;
-
-- (instancetype)initWithContentRect:(NSRect)contentRect
-                          styleMask:(NSWindowStyleMask)style
-                            backing:(NSBackingStoreType)bufferingType
-                              defer:(BOOL)flag NS_UNAVAILABLE;
-
-// Tells the window to suppress title drawing.
-- (void)setShouldHideTitle:(BOOL)flag;
-
-// When the lock is set to YES, the frame and style mask of the Window cannot be
-// changed. This is used to prevent AppKit from making these unwanted changes
-// to the window during exit fullscreen transition. It is very important to
-// release this lock after the transition is completed.
-- (void)setStyleMaskLock:(BOOL)lock;
-
-// This method is overridden to prevent AppKit from  setting the style mask
-// when frameAndStyleMaskLock_ is set to true.
-- (void)setStyleMask:(NSUInteger)styleMask;
-
-// Draws the window theme into the specified rect. Returns whether a theme was
-// drawn (whether incognito or full pattern theme; an overlay image doesn't
-// count).
-+ (BOOL)drawWindowThemeInDirtyRect:(NSRect)dirtyRect
-                           forView:(NSView*)view
-                            bounds:(NSRect)bounds
-              forceBlackBackground:(BOOL)forceBlackBackground;
-
-// Gets the color to draw title text.
-- (NSColor*)titleColor;
-
-@end
-
-@interface NSWindow (UndocumentedAPI)
-
-// Undocumented Cocoa API to suppress drawing of the window's title.
-// -setTitle: still works, but the title set only applies to the
-// miniwindow and menus (and, importantly, Expose).  Overridden to
-// return |shouldHideTitle_|.
--(BOOL)_isTitleHidden;
-
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_FRAMED_BROWSER_WINDOW_H_
diff --git a/chrome/browser/ui/cocoa/framed_browser_window.mm b/chrome/browser/ui/cocoa/framed_browser_window.mm
deleted file mode 100644
index 3823484..0000000
--- a/chrome/browser/ui/cocoa/framed_browser_window.mm
+++ /dev/null
@@ -1,194 +0,0 @@
-// Copyright (c) 2012 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.
-
-#import "chrome/browser/ui/cocoa/framed_browser_window.h"
-
-#include <math.h>
-#include <objc/runtime.h>
-#include <stddef.h>
-
-#include "base/logging.h"
-#include "base/mac/foundation_util.h"
-#include "base/mac/sdk_forward_declarations.h"
-#include "chrome/browser/global_keyboard_shortcuts_mac.h"
-#include "chrome/browser/profiles/profile_avatar_icon_util.h"
-#include "chrome/browser/themes/theme_properties.h"
-#include "chrome/browser/themes/theme_service.h"
-#import "chrome/browser/ui/cocoa/browser_window_layout.h"
-#import "chrome/browser/ui/cocoa/browser_window_utils.h"
-#include "chrome/browser/ui/cocoa/l10n_util.h"
-#include "chrome/browser/ui/cocoa/tabs/tab_window_controller.h"
-#import "chrome/browser/ui/cocoa/themed_window.h"
-#import "chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.h"
-#include "chrome/grit/theme_resources.h"
-#include "ui/base/cocoa/cocoa_base_utils.h"
-#include "ui/base/cocoa/nsgraphics_context_additions.h"
-#import "ui/base/cocoa/nsview_additions.h"
-#import "ui/base/cocoa/touch_bar_forward_declarations.h"
-
-@implementation FramedBrowserWindow
-
-+ (CGFloat)browserFrameViewPaintHeight {
-  return chrome::kTabStripHeight;
-}
-
-+ (NSUInteger)defaultStyleMask {
-  return NSTitledWindowMask | NSClosableWindowMask |
-         NSMiniaturizableWindowMask | NSResizableWindowMask |
-         NSTexturedBackgroundWindowMask;
-}
-
-- (void)setStyleMask:(NSUInteger)styleMask {
-  if (styleMaskLock_)
-    return;
-  [super setStyleMask:styleMask];
-}
-
-- (id)initWithContentRect:(NSRect)contentRect {
-  if ((self = [super initWithContentRect:contentRect
-                               styleMask:[[self class] defaultStyleMask]
-                                 backing:NSBackingStoreBuffered
-                                   defer:YES])) {
-    // The 10.6 fullscreen code copies the title to a different window, which
-    // will assert if it's nil.
-    [self setTitle:@""];
-  }
-
-  return self;
-}
-
-- (void)dealloc {
-  [[NSNotificationCenter defaultCenter] removeObserver:self];
-  [super dealloc];
-}
-
-- (NSUserInterfaceLayoutDirection)windowTitlebarLayoutDirection
-    NS_AVAILABLE_MAC(10_12) {
-  if (!cocoa_l10n_util::ShouldFlipWindowControlsInRTL())
-    return NSUserInterfaceLayoutDirectionLeftToRight;
-  return [super windowTitlebarLayoutDirection];
-}
-
-- (void)setShouldHideTitle:(BOOL)flag {
-  shouldHideTitle_ = flag;
-}
-
-- (void)setStyleMaskLock:(BOOL)lock {
-  styleMaskLock_ = lock;
-}
-
-- (BOOL)_isTitleHidden {
-  return shouldHideTitle_;
-}
-
-// This method is called whenever a window is moved in order to ensure it fits
-// on the screen.  We cannot always handle resizes without breaking, so we
-// prevent frame constraining in those cases.
-- (NSRect)constrainFrameRect:(NSRect)frame toScreen:(NSScreen*)screen {
-  // Do not constrain the frame rect if our delegate says no.  In this case,
-  // return the original (unconstrained) frame.
-  id delegate = [self delegate];
-  if ([delegate respondsToSelector:@selector(shouldConstrainFrameRect)] &&
-      ![delegate shouldConstrainFrameRect])
-    return frame;
-
-  return [super constrainFrameRect:frame toScreen:screen];
-}
-
-+ (BOOL)drawWindowThemeInDirtyRect:(NSRect)dirtyRect
-                           forView:(NSView*)view
-                            bounds:(NSRect)bounds
-              forceBlackBackground:(BOOL)forceBlackBackground {
-  const ui::ThemeProvider* themeProvider = [[view window] themeProvider];
-  if (!themeProvider)
-    return NO;
-
-  ThemedWindowStyle windowStyle = [[view window] themedWindowStyle];
-
-  // Devtools windows don't get themed.
-  if (windowStyle & THEMED_DEVTOOLS)
-    return NO;
-
-  BOOL active = [[view window] isMainWindow];
-  BOOL incognito = windowStyle & THEMED_INCOGNITO;
-  BOOL popup = windowStyle & THEMED_POPUP;
-
-  // Find a theme image.
-  NSColor* themeImageColor = nil;
-  if (!popup) {
-    int themeImageID;
-    if (active && incognito)
-      themeImageID = IDR_THEME_FRAME_INCOGNITO;
-    else if (active && !incognito)
-      themeImageID = IDR_THEME_FRAME;
-    else if (!active && incognito)
-      themeImageID = IDR_THEME_FRAME_INCOGNITO_INACTIVE;
-    else
-      themeImageID = IDR_THEME_FRAME_INACTIVE;
-    if (themeProvider->HasCustomImage(IDR_THEME_FRAME))
-      themeImageColor = themeProvider->GetNSImageColorNamed(themeImageID);
-  }
-
-  BOOL themed = NO;
-  if (themeImageColor) {
-    // Default to replacing any existing pixels with the theme image, but if
-    // asked paint black first and blend the theme with black.
-    NSCompositingOperation operation = NSCompositeCopy;
-    if (forceBlackBackground) {
-      [[NSColor blackColor] set];
-      NSRectFill(dirtyRect);
-      operation = NSCompositeSourceOver;
-    }
-
-    NSPoint position = [[view window] themeImagePositionForAlignment:
-        THEME_IMAGE_ALIGN_WITH_FRAME];
-    [[NSGraphicsContext currentContext] cr_setPatternPhase:position
-                                                   forView:view];
-
-    [themeImageColor set];
-    NSRectFillUsingOperation(dirtyRect, operation);
-    themed = YES;
-  }
-
-  // Check to see if we have an overlay image.
-  NSImage* overlayImage = nil;
-  if (themeProvider->HasCustomImage(IDR_THEME_FRAME_OVERLAY) && !incognito &&
-      !popup) {
-    overlayImage = themeProvider->
-        GetNSImageNamed(active ? IDR_THEME_FRAME_OVERLAY :
-                                 IDR_THEME_FRAME_OVERLAY_INACTIVE);
-  }
-
-  if (overlayImage) {
-    // Anchor to top-left and don't scale.
-    NSPoint position = [[view window] themeImagePositionForAlignment:
-        THEME_IMAGE_ALIGN_WITH_FRAME];
-    position = [view convertPoint:position fromView:nil];
-    NSSize overlaySize = [overlayImage size];
-    NSRect imageFrame = NSMakeRect(0, 0, overlaySize.width, overlaySize.height);
-    [overlayImage drawAtPoint:NSMakePoint(position.x,
-                                          position.y - overlaySize.height)
-                     fromRect:imageFrame
-                    operation:NSCompositeSourceOver
-                     fraction:1.0];
-  }
-
-  return themed;
-}
-
-- (NSColor*)titleColor {
-  const ui::ThemeProvider* themeProvider = [self themeProvider];
-  if (!themeProvider)
-    return [NSColor windowFrameTextColor];
-
-  ThemedWindowStyle windowStyle = [self themedWindowStyle];
-  BOOL incognito = windowStyle & THEMED_INCOGNITO;
-
-  if (incognito)
-    return [NSColor whiteColor];
-  else
-    return [NSColor windowFrameTextColor];
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/framed_browser_window_unittest.mm b/chrome/browser/ui/cocoa/framed_browser_window_unittest.mm
deleted file mode 100644
index 7cac331..0000000
--- a/chrome/browser/ui/cocoa/framed_browser_window_unittest.mm
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright (c) 2012 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.
-
-#import <Cocoa/Cocoa.h>
-#import <QuartzCore/QuartzCore.h>
-
-#include "base/debug/debugger.h"
-#include "base/mac/scoped_cftyperef.h"
-#include "base/mac/scoped_nsobject.h"
-#include "chrome/app/chrome_command_ids.h"
-#import "chrome/browser/ui/cocoa/framed_browser_window.h"
-#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-
-class FramedBrowserWindowTest : public CocoaTest {
- public:
-  void SetUp() override {
-    CocoaTest::SetUp();
-    // Create a window.
-    window_ = [[FramedBrowserWindow alloc]
-        initWithContentRect:NSMakeRect(0, 0, 800, 600)];
-    if (base::debug::BeingDebugged()) {
-      [window_ orderFront:nil];
-    } else {
-      [window_ orderBack:nil];
-    }
-  }
-
-  void TearDown() override {
-    [window_ close];
-    CocoaTest::TearDown();
-  }
-
-  // Returns a canonical snapshot of the window.
-  NSData* WindowContentsAsTIFF() {
-    [CATransaction flush];
-
-    base::ScopedCFTypeRef<CGImageRef> cgImage(CGWindowListCreateImage(
-        CGRectNull, kCGWindowListOptionIncludingWindow, [window_ windowNumber],
-        kCGWindowImageBoundsIgnoreFraming));
-    base::scoped_nsobject<NSImage> bitmap(
-        [[NSImage alloc] initWithCGImage:cgImage size:NSZeroSize]);
-    return [bitmap TIFFRepresentation];
-  }
-
-  FramedBrowserWindow* window_;
-};
-
-// Baseline test that the window creates, displays, closes, and
-// releases.
-TEST_F(FramedBrowserWindowTest, ShowAndClose) {
-  [window_ display];
-}
-
-// Test that undocumented title-hiding API we're using does the job.
-TEST_F(FramedBrowserWindowTest, DoesHideTitle) {
-  // The -display calls are not strictly necessary, but they do
-  // make it easier to see what's happening when debugging (without
-  // them the changes are never flushed to the screen).
-
-  [window_ setTitle:@""];
-  [window_ display];
-  NSData* emptyTitleData = WindowContentsAsTIFF();
-
-  [window_ setTitle:@"This is a title"];
-  [window_ display];
-  NSData* thisTitleData = WindowContentsAsTIFF();
-
-  // The default window with a title should look different from the
-  // window with an empty title.
-  EXPECT_FALSE([emptyTitleData isEqualToData:thisTitleData]);
-
-  [window_ setShouldHideTitle:YES];
-  [window_ setTitle:@""];
-  [window_ display];
-  [window_ setTitle:@"This is a title"];
-  [window_ display];
-  NSData* hiddenTitleData = WindowContentsAsTIFF();
-
-  // With our magic setting, the window with a title should look the
-  // same as the window with an empty title.
-  EXPECT_TRUE([window_ _isTitleHidden]);
-  EXPECT_TRUE([emptyTitleData isEqualToData:hiddenTitleData]);
-}
diff --git a/chrome/browser/ui/cocoa/has_weak_browser_pointer.h b/chrome/browser/ui/cocoa/has_weak_browser_pointer.h
deleted file mode 100644
index 39fd312..0000000
--- a/chrome/browser/ui/cocoa/has_weak_browser_pointer.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2015 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 CHROME_BROWSER_UI_COCOA_HAS_WEAK_BROWSER_POINTER_H_
-#define CHROME_BROWSER_UI_COCOA_HAS_WEAK_BROWSER_POINTER_H_
-
-// This allows reference counted objects holding a Browser* to be
-// notified that the Browser will be destroyed so they can invalidate their
-// Browser*, perform any necessary cleanup, and pass the notification onto any
-// objects they retain that also implement this protocol. This helps to prevent
-// use-after-free of Browser*, or anything else tied to the Browser's lifetime,
-// by objects that may be retained beyond the lifetime of their associated
-// Browser (e.g. NSViewControllers).
-@protocol HasWeakBrowserPointer
-@required
-// This is usually called by BrowserWindowController but can be called by any
-// object that's certain of Browser's destruction.
-- (void)browserWillBeDestroyed;
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_HAS_WEAK_BROWSER_POINTER_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h
deleted file mode 100644
index 4d60858..0000000
--- a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright (c) 2012 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 CHROME_BROWSER_UI_COCOA_LOCATION_BAR_LOCATION_BAR_VIEW_MAC_H_
-#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_LOCATION_BAR_VIEW_MAC_H_
-
-#import <Cocoa/Cocoa.h>
-#include <stddef.h>
-
-#include <memory>
-#include <string>
-
-#include "base/macros.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/location_bar/location_bar.h"
-#include "chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.h"
-#include "components/prefs/pref_member.h"
-#include "components/security_state/core/security_state.h"
-
-class CommandUpdater;
-class Profile;
-
-// A C++ bridge class that represents the location bar UI element to
-// the portable code.  Wires up an OmniboxViewMac instance to
-// the location bar text field, which handles most of the work.
-
-class LocationBarViewMac : public LocationBar,
-                           public LocationBarTesting,
-                           public ChromeOmniboxEditController {
- public:
-  LocationBarViewMac(CommandUpdater* command_updater,
-                     Profile* profile,
-                     Browser* browser);
-  ~LocationBarViewMac() override;
-
-  // Overridden from LocationBar:
-  GURL GetDestinationURL() const override;
-  WindowOpenDisposition GetWindowOpenDisposition() const override;
-  ui::PageTransition GetPageTransition() const override;
-  base::TimeTicks GetMatchSelectionTimestamp() const override;
-  void AcceptInput() override;
-  void AcceptInput(base::TimeTicks match_selection_timestamp) override;
-  void FocusLocation(bool select_all) override;
-  void FocusSearch() override;
-  void UpdateContentSettingsIcons() override;
-  void UpdateManagePasswordsIconAndBubble() override;
-  void UpdateSaveCreditCardIcon() override;
-  void UpdateLocalCardMigrationIcon() override;
-  void UpdateBookmarkStarVisibility() override;
-  void UpdateLocationBarVisibility(bool visible, bool animate) override;
-  void SaveStateToContents(content::WebContents* contents) override;
-  void Revert() override;
-  const OmniboxView* GetOmniboxView() const override;
-  OmniboxView* GetOmniboxView() override;
-  LocationBarTesting* GetLocationBarForTesting() override;
-
-  // Overridden from LocationBarTesting:
-  bool GetBookmarkStarVisibility() override;
-  bool TestContentSettingImagePressed(size_t index) override;
-  bool IsContentSettingBubbleShowing(size_t index) override;
-
-  // ChromeOmniboxEditController:
-  ToolbarModel* GetToolbarModel() override;
-  const ToolbarModel* GetToolbarModel() const override;
-
- private:
-  Browser* browser_;
-
-  DISALLOW_COPY_AND_ASSIGN(LocationBarViewMac);
-};
-
-#endif  // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_LOCATION_BAR_VIEW_MAC_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
deleted file mode 100644
index 5611e018..0000000
--- a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2012 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.
-
-#import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
-
-LocationBarViewMac::LocationBarViewMac(CommandUpdater* command_updater,
-                                       Profile* profile,
-                                       Browser* browser)
-    : LocationBar(profile),
-      ChromeOmniboxEditController(command_updater),
-      browser_(browser) {}
-
-LocationBarViewMac::~LocationBarViewMac() {
-}
-
-GURL LocationBarViewMac::GetDestinationURL() const {
-  return destination_url();
-}
-
-WindowOpenDisposition LocationBarViewMac::GetWindowOpenDisposition() const {
-  return disposition();
-}
-
-ui::PageTransition LocationBarViewMac::GetPageTransition() const {
-  return transition();
-}
-
-base::TimeTicks LocationBarViewMac::GetMatchSelectionTimestamp() const {
-  return match_selection_timestamp();
-}
-
-void LocationBarViewMac::AcceptInput() {
-}
-
-void LocationBarViewMac::AcceptInput(
-    base::TimeTicks match_selection_timestamp) {
-}
-
-void LocationBarViewMac::FocusLocation(bool select_all) {
-}
-
-void LocationBarViewMac::FocusSearch() {
-}
-
-void LocationBarViewMac::UpdateContentSettingsIcons() {
-}
-
-void LocationBarViewMac::UpdateManagePasswordsIconAndBubble() {
-}
-
-void LocationBarViewMac::UpdateSaveCreditCardIcon() {
-}
-
-void LocationBarViewMac::UpdateLocalCardMigrationIcon() {
-}
-
-void LocationBarViewMac::UpdateBookmarkStarVisibility() {
-}
-
-void LocationBarViewMac::UpdateLocationBarVisibility(bool visible,
-                                                     bool animate) {
-}
-
-void LocationBarViewMac::SaveStateToContents(content::WebContents* contents) {}
-
-void LocationBarViewMac::Revert() {
-}
-
-const OmniboxView* LocationBarViewMac::GetOmniboxView() const {
-  return nullptr;
-}
-
-OmniboxView* LocationBarViewMac::GetOmniboxView() {
-  return nullptr;
-}
-
-LocationBarTesting* LocationBarViewMac::GetLocationBarForTesting() {
-  return this;
-}
-
-bool LocationBarViewMac::GetBookmarkStarVisibility() {
-  return false;
-}
-
-bool LocationBarViewMac::TestContentSettingImagePressed(size_t index) {
-  return false;
-}
-
-bool LocationBarViewMac::IsContentSettingBubbleShowing(size_t index) {
-  return false;
-}
-
-ToolbarModel* LocationBarViewMac::GetToolbarModel() {
-  return browser_->toolbar_model();
-}
-
-const ToolbarModel* LocationBarViewMac::GetToolbarModel() const {
-  return browser_->toolbar_model();
-}
diff --git a/chrome/browser/ui/cocoa/md_util.h b/chrome/browser/ui/cocoa/md_util.h
deleted file mode 100644
index b8a564a..0000000
--- a/chrome/browser/ui/cocoa/md_util.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2017 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 CHROME_BROWSER_UI_COCOA_MD_UTIL_H_
-#define CHROME_BROWSER_UI_COCOA_MD_UTIL_H_
-
-#import <QuartzCore/QuartzCore.h>
-
-@interface CAMediaTimingFunction (ChromeBrowserMDUtil)
-@property(class, readonly)
-    CAMediaTimingFunction* cr_materialEaseInTimingFunction;
-@property(class, readonly)
-    CAMediaTimingFunction* cr_materialEaseOutTimingFunction;
-@property(class, readonly)
-    CAMediaTimingFunction* cr_materialEaseInOutTimingFunction;
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_MD_UTIL_H_
diff --git a/chrome/browser/ui/cocoa/md_util.mm b/chrome/browser/ui/cocoa/md_util.mm
deleted file mode 100644
index c4874df..0000000
--- a/chrome/browser/ui/cocoa/md_util.mm
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2017 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.
-
-#import "chrome/browser/ui/cocoa/md_util.h"
-
-@implementation CAMediaTimingFunction (ChromeBrowserMDUtil)
-+ (CAMediaTimingFunction*)cr_materialEaseInTimingFunction {
-  return [[[CAMediaTimingFunction alloc] initWithControlPoints:0.4:0.0:1.0:1]
-      autorelease];
-}
-
-+ (CAMediaTimingFunction*)cr_materialEaseOutTimingFunction {
-  return [[[CAMediaTimingFunction alloc] initWithControlPoints:0.0:0.0:0.2:1]
-      autorelease];
-}
-
-+ (CAMediaTimingFunction*)cr_materialEaseInOutTimingFunction {
-  return [[[CAMediaTimingFunction alloc] initWithControlPoints:0.4:0.0:0.2:1]
-      autorelease];
-}
-@end
diff --git a/chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.h b/chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.h
deleted file mode 100644
index 8f9781ef..0000000
--- a/chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2012 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 CHROME_BROWSER_UI_COCOA_TAB_CONTENTS_OVERLAYABLE_CONTENTS_CONTROLLER_H_
-#define CHROME_BROWSER_UI_COCOA_TAB_CONTENTS_OVERLAYABLE_CONTENTS_CONTROLLER_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/mac/scoped_nsobject.h"
-
-// OverlayableContentsController is an obsolete wrapper holding the view where a
-// tab's WebContents is displayed. In the old Chrome Instant implementation it
-// multiplexed between the tab's contents and an overlay's contents. Now there
-// is no overlay, but ripping this class out entirely is hard.
-//
-// TODO(sail): Remove this class and replace it with something saner.
-@interface OverlayableContentsController : NSViewController {
- @private
-  // Container view for the "active" contents.
-  base::scoped_nsobject<NSView> activeContainer_;
-}
-
-@property(readonly, nonatomic) NSView* activeContainer;
-
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_TAB_CONTENTS_OVERLAYABLE_CONTENTS_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.mm b/chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.mm
deleted file mode 100644
index d3bf3a71..0000000
--- a/chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.mm
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2011 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.
-
-#import "chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.h"
-
-@implementation OverlayableContentsController
-
-- (id)init {
-  if ((self = [super init])) {
-    base::scoped_nsobject<NSView> view(
-        [[NSView alloc] initWithFrame:NSZeroRect]);
-    [view setAutoresizingMask:NSViewHeightSizable | NSViewWidthSizable];
-    [self setView:view];
-
-    activeContainer_.reset([[NSView alloc] initWithFrame:NSZeroRect]);
-    [activeContainer_ setAutoresizingMask:NSViewHeightSizable |
-                                          NSViewWidthSizable];
-    [view addSubview:activeContainer_];
-  }
-  return self;
-}
-
-- (NSView*)activeContainer {
-  return activeContainer_.get();
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h b/chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h
deleted file mode 100644
index a4f3abd..0000000
--- a/chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright (c) 2012 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 CHROME_BROWSER_UI_COCOA_TAB_CONTENTS_TAB_CONTENTS_CONTROLLER_H_
-#define CHROME_BROWSER_UI_COCOA_TAB_CONTENTS_TAB_CONTENTS_CONTROLLER_H_
-
-#include <Cocoa/Cocoa.h>
-
-#include <memory>
-
-#include "base/mac/scoped_nsobject.h"
-
-namespace content {
-class WebContents;
-}
-
-// A class that controls the WebContents view. It internally creates a container
-// view (the NSView accessed by calling |-view|) which manages the layout and
-// display of the WebContents view.
-//
-// Client code that inserts [controller view] into the view hierarchy needs to
-// call -ensureContentsVisibleInSuperview:(NSView*)superview to match the
-// container to the [superview bounds] and avoid multiple resize messages being
-// sent to the renderer, which triggers redundant and costly layouts.
-//
-// AutoEmbedFullscreen mode: When enabled, TabContentsController will observe
-// for WebContents fullscreen changes and automatically swap the normal
-// WebContents view with the fullscreen view (if different). In addition, if a
-// WebContents is being screen-captured, the view will be centered within the
-// container view, sized to the aspect ratio of the capture video resolution,
-// and scaling will be avoided whenever possible.
-@interface TabContentsController : NSViewController {
- @private
-   content::WebContents* contents_;  // weak
-   // Set to true while TabContentsController is embedding a fullscreen widget
-   // view as a subview instead of the normal WebContentsView render view.
-   // Note: This will be false in the case of non-Flash fullscreen.
-   BOOL isEmbeddingFullscreenWidget_;
-
-   // Set to true if the window is a popup.
-   BOOL isPopup_;
-}
-@property(readonly, nonatomic) content::WebContents* webContents;
-
-// This flag is set to true when we don't want the fullscreen widget to
-// resize. This is done so that we can avoid resizing the fullscreen widget
-// to intermediate sizes during the fullscreen transition.
-// As a result, we would prevent janky movements during the transition and
-// Pepper Fullscreen from blowing up.
-@property(assign, nonatomic) BOOL blockFullscreenResize;
-
-// Create the contents of a tab represented by |contents|.
-- (id)initWithContents:(content::WebContents*)contents isPopup:(BOOL)popup;
-
-// Call to insert the container view into the view hierarchy, sizing it to match
-// |superview|. Then, this method will select either the WebContents view or
-// the fullscreen view and swap it into the container for display.
-- (void)ensureContentsVisibleInSuperview:(NSView*)superview;
-
-// Called after we enter fullscreen to ensure that the fullscreen widget will
-// have the right frame.
-- (void)updateFullscreenWidgetFrame;
-
-// Call to change the underlying web contents object. View is not changed,
-// call |-ensureContentsVisible| to display the |newContents|'s render widget
-// host view.
-- (void)changeWebContents:(content::WebContents*)newContents;
-
-// Called when the tab contents is the currently selected tab and is about to be
-// removed from the view hierarchy.
-- (void)willBecomeUnselectedTab;
-
-// Called when the tab contents is about to be put into the view hierarchy as
-// the selected tab. Handles things such as ensuring the toolbar is correctly
-// enabled.
-- (void)willBecomeSelectedTab;
-
-// Called when the tab contents is updated in some non-descript way (the
-// notification from the model isn't specific). |updatedContents| could reflect
-// an entirely new tab contents object.
-- (void)tabDidChange:(content::WebContents*)updatedContents;
-
-// Called to switch the container's subview to the WebContents-owned fullscreen
-// widget or back to WebContentsView's widget.
-- (void)toggleFullscreenWidget:(BOOL)enterFullscreen;
-
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_TAB_CONTENTS_TAB_CONTENTS_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.mm b/chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.mm
deleted file mode 100644
index 5134d50..0000000
--- a/chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.mm
+++ /dev/null
@@ -1,303 +0,0 @@
-// Copyright (c) 2012 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.
-
-#import "chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h"
-
-#include <stdint.h>
-
-#include <utility>
-
-#include "base/feature_list.h"
-#include "base/mac/scoped_cftyperef.h"
-#include "base/mac/scoped_nsobject.h"
-#include "base/macros.h"
-#include "chrome/browser/devtools/devtools_window.h"
-#import "chrome/browser/themes/theme_properties.h"
-#import "chrome/browser/themes/theme_service.h"
-#import "chrome/browser/ui/cocoa/themed_window.h"
-#include "chrome/browser/ui/exclusive_access/fullscreen_within_tab_helper.h"
-#include "chrome/browser/ui/view_ids.h"
-#include "chrome/common/chrome_features.h"
-#include "chrome/grit/theme_resources.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/render_widget_host.h"
-#include "content/public/browser/render_widget_host_view.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "skia/ext/skia_utils_mac.h"
-#include "ui/base/cocoa/animation_utils.h"
-#import "ui/base/cocoa/touch_bar_forward_declarations.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/scrollbar_size.h"
-
-using content::WebContents;
-using content::WebContentsObserver;
-
-@interface TabContentsController (TabContentsContainerViewDelegate)
-// Computes and returns the frame to use for the contents view using the size of
-// |container| as the target size.
-- (NSRect)frameForContentsViewIn:(NSView*)container;
-
-// Returns YES if the content view should be resized.
-- (BOOL)shouldResizeContentView;
-
-// Returns YES if the content view is inside a popup.
-- (BOOL)isPopup;
-
-@end
-
-// An NSView with special-case handling for when the contents view does not
-// expand to fill the entire tab contents area. See 'AutoEmbedFullscreen mode'
-// in header file comments.
-@interface TabContentsContainerView : NSView {
- @private
-  TabContentsController* delegate_;  // weak
-}
-
-- (void)updateBackgroundColorFromWindowTheme:(NSWindow*)window;
-@end
-
-@implementation TabContentsContainerView
-
-- (id)initWithDelegate:(TabContentsController*)delegate {
-  if ((self = [super initWithFrame:NSZeroRect])) {
-    delegate_ = delegate;
-    ScopedCAActionDisabler disabler;
-    base::scoped_nsobject<CALayer> layer([[CALayer alloc] init]);
-    [self setLayer:layer];
-    [self setWantsLayer:YES];
-  }
-  return self;
-}
-
-// Called by the delegate during dealloc to invalidate the pointer held by this
-// view.
-- (void)delegateDestroyed {
-  delegate_ = nil;
-}
-
-// Override auto-resizing logic to query the delegate for the exact frame to
-// use for the contents view.
-// TODO(spqchan): The popup check is a temporary solution to fix the regression
-// issue described in crbug.com/604288. This method doesn't really affect
-// fullscreen if the content is inside a normal browser window, but would
-// cause a flash fullscreen widget to blow up if it's inside a popup.
-- (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize {
-  NSView* const contentsView =
-      [[self subviews] count] > 0 ? [[self subviews] objectAtIndex:0] : nil;
-  if (!contentsView || [contentsView autoresizingMask] == NSViewNotSizable ||
-      !delegate_ ||
-      (![delegate_ shouldResizeContentView] && [delegate_ isPopup])) {
-    return;
-  }
-
-  ScopedCAActionDisabler disabler;
-  [contentsView setFrame:[delegate_ frameForContentsViewIn:self]];
-}
-
-// Update the background layer's color whenever the view needs to repaint.
-- (void)setNeedsDisplayInRect:(NSRect)rect {
-  [super setNeedsDisplayInRect:rect];
-  [self updateBackgroundColorFromWindowTheme:[self window]];
-}
-
-- (void)updateBackgroundColorFromWindowTheme:(NSWindow*)window {
-  // This view is sometimes flashed into visibility (e.g, when closing
-  // windows or opening new tabs), so ensure that the flash be the theme
-  // background color in those cases.
-  const ThemeProvider* theme = [window themeProvider];
-  if (!theme)
-    return;
-
-  SkColor skBackgroundColor =
-      theme->GetColor(ThemeProperties::COLOR_NTP_BACKGROUND);
-
-  ScopedCAActionDisabler disabler;
-  base::ScopedCFTypeRef<CGColorRef> cgBackgroundColor(
-      skia::CGColorCreateFromSkColor(skBackgroundColor));
-  [[self layer] setBackgroundColor:cgBackgroundColor];
-}
-
-- (void)viewWillMoveToWindow:(NSWindow*)newWindow {
-  [self updateBackgroundColorFromWindowTheme:newWindow];
-}
-
-- (ViewID)viewID {
-  return VIEW_ID_TAB_CONTAINER;
-}
-
-- (BOOL)acceptsFirstResponder {
-  return [[self subviews] count] > 0 &&
-      [[[self subviews] objectAtIndex:0] acceptsFirstResponder];
-}
-
-// When receiving a click-to-focus in the solid color area surrounding the
-// WebContents' native view, immediately transfer focus to WebContents' native
-// view.
-- (BOOL)becomeFirstResponder {
-  if (![self acceptsFirstResponder])
-    return NO;
-  return [[self window] makeFirstResponder:[[self subviews] objectAtIndex:0]];
-}
-
-- (BOOL)canBecomeKeyView {
-  return NO;  // Tab/Shift-Tab should focus the subview, not this view.
-}
-
-@end  // @implementation TabContentsContainerView
-
-@interface TabContentsController (
-    SeparateFullscreenWindowDelegate)<NSWindowDelegate>
-
-- (NSView*)createScreenshotView;
-
-- (NSWindow*)createSeparateWindowForTab:(content::WebContents*)separatedTab;
-
-@end
-
-@implementation TabContentsController
-@synthesize webContents = contents_;
-@synthesize blockFullscreenResize = blockFullscreenResize_;
-
-- (id)initWithContents:(WebContents*)contents isPopup:(BOOL)popup {
-  if ((self = [super initWithNibName:nil bundle:nil])) {
-    [self changeWebContents:contents];
-    isPopup_ = popup;
-  }
-  return self;
-}
-
-- (void)dealloc {
-  [static_cast<TabContentsContainerView*>([self view]) delegateDestroyed];
-  // Make sure the contents view has been removed from the container view to
-  // allow objects to be released.
-  [[self view] removeFromSuperview];
-  [super dealloc];
-}
-
-- (void)loadView {
-  base::scoped_nsobject<NSView> view(
-      [[TabContentsContainerView alloc] initWithDelegate:self]);
-  [view setAutoresizingMask:NSViewHeightSizable|NSViewWidthSizable];
-  [self setView:view];
-}
-
-- (void)ensureContentsVisibleInSuperview:(NSView*)superview {
-  if (!contents_)
-    return;
-
-  ScopedCAActionDisabler disabler;
-  NSView* contentsContainer = [self view];
-  NSArray* subviews = [contentsContainer subviews];
-  NSView* contentsNativeView = nil;
-
-  if ([self shouldResizeContentView])
-    [contentsNativeView setFrame:[self frameForContentsViewIn:superview]];
-
-  if ([subviews count] == 0) {
-    [contentsContainer addSubview:contentsNativeView];
-  } else if ([subviews objectAtIndex:0] != contentsNativeView) {
-    [contentsContainer replaceSubview:[subviews objectAtIndex:0]
-                                 with:contentsNativeView];
-  }
-
-  [contentsNativeView setAutoresizingMask:NSViewNotSizable];
-  [contentsContainer setFrame:[superview bounds]];
-  [superview addSubview:contentsContainer];
-  [contentsNativeView setAutoresizingMask:NSViewWidthSizable|
-                                          NSViewHeightSizable];
-
-  [contentsContainer setNeedsDisplay:YES];
-}
-
-- (void)updateFullscreenWidgetFrame {
-}
-
-- (void)changeWebContents:(WebContents*)newContents {
-}
-
-// Returns YES if the tab represented by this controller is the front-most.
-- (BOOL)isCurrentTab {
-  // We're the current tab if we're in the view hierarchy, otherwise some other
-  // tab is.
-  return [[self view] superview] ? YES : NO;
-}
-
-- (void)willBecomeUnselectedTab {
-  // The RWHV is ripped out of the view hierarchy on tab switches, so it never
-  // formally resigns first responder status.  Handle this by explicitly sending
-  // a Blur() message to the renderer, but only if the RWHV currently has focus.
-  content::RenderViewHost* rvh = [self webContents]->GetRenderViewHost();
-  if (rvh) {
-    if (rvh->GetWidget()->GetView() &&
-        rvh->GetWidget()->GetView()->HasFocus()) {
-      rvh->GetWidget()->Blur();
-      return;
-    }
-    WebContents* devtools = DevToolsWindow::GetInTabWebContents(
-        [self webContents], NULL);
-    if (devtools) {
-      content::RenderViewHost* devtoolsView = devtools->GetRenderViewHost();
-      if (devtoolsView && devtoolsView->GetWidget()->GetView() &&
-          devtoolsView->GetWidget()->GetView()->HasFocus()) {
-        devtoolsView->GetWidget()->Blur();
-      }
-    }
-  }
-}
-
-- (void)willBecomeSelectedTab {
-  // Do not explicitly call Focus() here, as the RWHV may not actually have
-  // focus (for example, if the omnibox has focus instead).  The WebContents
-  // logic will restore focus to the appropriate view.
-}
-
-- (void)tabDidChange:(WebContents*)updatedContents {
-  // Calling setContentView: here removes any first responder status
-  // the view may have, so avoid changing the view hierarchy unless
-  // the view is different.
-  if ([self webContents] != updatedContents) {
-    [self changeWebContents:updatedContents];
-    [self ensureContentsVisibleInSuperview:[[self view] superview]];
-  }
-}
-
-- (void)toggleFullscreenWidget:(BOOL)enterFullscreen {
-}
-
-- (BOOL)contentsInFullscreenCaptureMode {
-  return NO;
-}
-
-- (NSRect)frameForContentsViewIn:(NSView*)container {
-  gfx::Rect rect([container bounds]);
-
-  // In most cases, the contents view is simply sized to fill the container
-  // view's bounds. Only WebContentses that are in fullscreen mode and being
-  // screen-captured will engage the special layout/sizing behavior.
-  return NSRectFromCGRect(rect.ToCGRect());
-}
-
-- (BOOL)shouldResizeContentView {
-  return YES;
-}
-
-- (BOOL)isPopup {
-  return isPopup_;
-}
-
-@end
-
-@implementation TabContentsController (SeparateFullscreenWindowDelegate)
-
-- (NSView*)createScreenshotView {
-  return nil;
-}
-
-// Creates a new window with the tab without detaching it from its source
-// window.
-- (NSWindow*)createSeparateWindowForTab:(WebContents*)separatedTab {
-  return nil;
-}
-@end
diff --git a/chrome/browser/ui/cocoa/tabbed_browser_window.h b/chrome/browser/ui/cocoa/tabbed_browser_window.h
deleted file mode 100644
index f1d11b2..0000000
--- a/chrome/browser/ui/cocoa/tabbed_browser_window.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2017 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 CHROME_BROWSER_UI_COCOA_TABBED_BROWSER_WINDOW_H_
-#define CHROME_BROWSER_UI_COCOA_TABBED_BROWSER_WINDOW_H_
-
-#import <AppKit/AppKit.h>
-
-#include "chrome/browser/ui/cocoa/framed_browser_window.h"
-
-// Represents a browser window with tabs and customized window controls.
-@interface TabbedBrowserWindow : FramedBrowserWindow
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_TABBED_BROWSER_WINDOW_H_
diff --git a/chrome/browser/ui/cocoa/tabbed_browser_window.mm b/chrome/browser/ui/cocoa/tabbed_browser_window.mm
deleted file mode 100644
index 1e35c97..0000000
--- a/chrome/browser/ui/cocoa/tabbed_browser_window.mm
+++ /dev/null
@@ -1,167 +0,0 @@
-// Copyright 2017 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.
-
-#import "chrome/browser/ui/cocoa/tabbed_browser_window.h"
-
-#import "chrome/browser/ui/cocoa/browser_window_layout.h"
-#include "ui/views/widget/util_mac.h"
-
-// Implementer's note: Moving the window controls is tricky. When altering the
-// code, ensure that:
-// - accessibility hit testing works
-// - the accessibility hierarchy is correct
-// - close/min in the background don't bring the window forward
-// - rollover effects work correctly
-
-namespace {
-// Size of the gradient. Empirically determined so that the gradient looks
-// like what the heuristic does when there are just a few tabs.
-constexpr CGFloat kWindowGradientHeight = 24.0;
-
-// Offsets from the bottom/left of the titlebar to the bottom/left of the
-// window buttons (zoom, close, miniaturize).
-constexpr NSInteger kWindowButtonsOffsetFromBottom = 9;
-constexpr NSInteger kWindowButtonsOffsetFromLeft = 11;
-}  // namespace
-
-@interface TabbedBrowserWindow ()
-- (CGFloat)fullScreenButtonOriginAdjustment;
-@end
-
-@interface NSThemeFrame (PrivateTabbedBrowserWindowAPI)
-- (NSView*)fullScreenButton
-    __attribute__((availability(macos, obsoleted = 10.10)));
-@end
-
-@interface NSWindow (PrivateTabbedBrowserWindowAPI)
-+ (Class)frameViewClassForStyleMask:(NSUInteger)windowStyle;
-@end
-
-@interface NSWindow (TenTwelveSDK)
-@property(readonly)
-    NSUserInterfaceLayoutDirection windowTitlebarLayoutDirection;
-@end
-
-@interface TabbedBrowserWindowFrame : NSThemeFrame
-@end
-
-@implementation TabbedBrowserWindowFrame
-
-// NSThemeFrame overrides.
-
-- (CGFloat)_minXTitlebarWidgetInset {
-  return kWindowButtonsOffsetFromLeft;
-}
-
-- (CGFloat)_minYTitlebarButtonsOffset {
-  return -kWindowButtonsOffsetFromBottom;
-}
-
-- (CGFloat)_titlebarHeight {
-  return chrome::kTabStripHeight;
-}
-
-// AppKit's implementation only returns YES if [self class] == [NSThemeFrame
-// class]. TabbedBrowserWindowFrame could override -class to return that, but
-// then -[NSWindow setStyleMask:] would recreate the frame view each time the
-// style mask is touched because it wouldn't match the return value of
-// +[TabbedBrowserWindow frameViewClassForStyleMask:].
-- (BOOL)_shouldFlipTrafficLightsForRTL API_AVAILABLE(macos(10.12)) {
-  return [[self window] windowTitlebarLayoutDirection] ==
-         NSUserInterfaceLayoutDirectionRightToLeft;
-}
-
-@end
-
-// By default, contentView does not occupy the full size of a titled window,
-// and Chrome wants to draw in the title bar. Historically, Chrome did this by
-// adding subviews directly to the root view. This causes several problems. The
-// most egregious is related to layer ordering when the root view does not have
-// a layer. By giving the contentView the same size as the window, there is no
-// need to add subviews to the root view.
-//
-// TODO(sdy): This can be deleted once ShouldUseFullSizeContentView is
-// perma-on. See https://crbug.com/605219.
-@interface FullSizeTabbedBrowserWindowFrame : TabbedBrowserWindowFrame
-@end
-
-@implementation FullSizeTabbedBrowserWindowFrame
-
-+ (CGRect)contentRectForFrameRect:(CGRect)frameRect
-                        styleMask:(NSUInteger)style {
-  return frameRect;
-}
-
-+ (CGRect)frameRectForContentRect:(CGRect)contentRect
-                        styleMask:(NSUInteger)style {
-  return contentRect;
-}
-
-- (CGRect)contentRectForFrameRect:(CGRect)frameRect
-                        styleMask:(NSUInteger)style {
-  return frameRect;
-}
-
-- (CGRect)frameRectForContentRect:(CGRect)contentRect
-                        styleMask:(NSUInteger)style {
-  return contentRect;
-}
-
-@end
-
-@implementation TabbedBrowserWindow
-
-// FramedBrowserWindow overrides.
-
-+ (NSUInteger)defaultStyleMask {
-  NSUInteger styleMask = [super defaultStyleMask];
-  if (chrome::ShouldUseFullSizeContentView()) {
-    if (@available(macOS 10.10, *))
-      styleMask |= NSFullSizeContentViewWindowMask;
-  }
-  return styleMask;
-}
-
-// NSWindow (PrivateTabbedBrowserWindowAPI) overrides.
-
-+ (Class)frameViewClassForStyleMask:(NSUInteger)windowStyle {
-  // Because NSThemeFrame is imported weakly, if it's not present at runtime
-  // then it and its subclasses will be nil.
-  if ([TabbedBrowserWindowFrame class]) {
-    return chrome::ShouldUseFullSizeContentView()
-               ? [TabbedBrowserWindowFrame class]
-               : [FullSizeTabbedBrowserWindowFrame class];
-  }
-  return [super frameViewClassForStyleMask:windowStyle];
-}
-
-// NSWindow's implementation of _usesCustomDrawing returns YES when the window
-// has a custom frame view class, which causes several undesirable changes in
-// AppKit's behavior. NSWindow subclasses in AppKit override it and return NO.
-- (BOOL)_usesCustomDrawing {
-  return NO;
-}
-
-// FramedBrowserWindow overrides.
-
-- (id)initWithContentRect:(NSRect)contentRect {
-  if ((self = [super initWithContentRect:contentRect])) {
-    // The following two calls fix http://crbug.com/25684 by preventing the
-    // window from recalculating the border thickness as the window is
-    // resized.
-    // This was causing the window tint to change for the default system theme
-    // when the window was being resized.
-    [self setAutorecalculatesContentBorderThickness:NO forEdge:NSMaxYEdge];
-    [self setContentBorderThickness:kWindowGradientHeight forEdge:NSMaxYEdge];
-  }
-  return self;
-}
-
-// TabbedBrowserWindow () implementation.
-
-- (CGFloat)fullScreenButtonOriginAdjustment {
-  return 0;
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/tabbed_browser_window_unittest.mm b/chrome/browser/ui/cocoa/tabbed_browser_window_unittest.mm
deleted file mode 100644
index e889127..0000000
--- a/chrome/browser/ui/cocoa/tabbed_browser_window_unittest.mm
+++ /dev/null
@@ -1,138 +0,0 @@
-// Copyright 2017 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.
-
-#import <AppKit/AppKit.h>
-
-#import "chrome/browser/ui/cocoa/tabbed_browser_window.h"
-#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
-
-namespace {
-NSString* const kAppleTextDirectionDefaultsKey = @"AppleTextDirection";
-NSString* const kForceRTLWritingDirectionDefaultsKey =
-    @"NSForceRightToLeftWritingDirection";
-constexpr CGFloat kWindowButtonInset = 11;
-}  // namespace
-
-class TabbedBrowserWindowTest : public CocoaTest {
- protected:
-  TabbedBrowserWindowTest() = default;
-
-  void SetUp() override {
-    CocoaTest::SetUp();
-    window_ = [[TabbedBrowserWindow alloc]
-        initWithContentRect:NSMakeRect(0, 0, 800, 600)];
-    [window() orderBack:nil];
-  }
-
-  void TearDown() override {
-    [window() close];
-    CocoaTest::TearDown();
-  }
-
-  TabbedBrowserWindow* window() { return window_; };
-
- private:
-  TabbedBrowserWindow* window_;
-
-  DISALLOW_COPY_AND_ASSIGN(TabbedBrowserWindowTest);
-};
-
-// Test to make sure that our window widgets are in the right place.
-TEST_F(TabbedBrowserWindowTest, WindowWidgetLocation) {
-  NSView* closeBoxControl = [window() standardWindowButton:NSWindowCloseButton];
-  EXPECT_TRUE(closeBoxControl);
-  NSRect closeBoxFrame =
-      [closeBoxControl convertRect:[closeBoxControl bounds] toView:nil];
-  NSRect windowBounds = [window() frame];
-  windowBounds = [[window() contentView] convertRect:windowBounds fromView:nil];
-  windowBounds.origin = NSZeroPoint;
-  EXPECT_EQ(NSMaxY(closeBoxFrame), NSMaxY(windowBounds) - kWindowButtonInset);
-  EXPECT_EQ(NSMinX(closeBoxFrame), kWindowButtonInset);
-}
-
-class TabbedBrowserWindowRTLTest : public TabbedBrowserWindowTest {
- public:
-  TabbedBrowserWindowRTLTest() = default;
-
-  void SetUp() override {
-    NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
-    originalAppleTextDirection_ =
-        [defaults boolForKey:kAppleTextDirectionDefaultsKey];
-    originalRTLWritingDirection_ =
-        [defaults boolForKey:kForceRTLWritingDirectionDefaultsKey];
-    [defaults setBool:YES forKey:kAppleTextDirectionDefaultsKey];
-    [defaults setBool:YES forKey:kForceRTLWritingDirectionDefaultsKey];
-    TabbedBrowserWindowTest::SetUp();
-  }
-
-  void TearDown() override {
-    TabbedBrowserWindowTest::TearDown();
-    NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
-    [defaults setBool:originalAppleTextDirection_
-               forKey:kAppleTextDirectionDefaultsKey];
-    [defaults setBool:originalRTLWritingDirection_
-               forKey:kForceRTLWritingDirectionDefaultsKey];
-  }
-
- private:
-  BOOL originalAppleTextDirection_;
-  BOOL originalRTLWritingDirection_;
-
-  DISALLOW_COPY_AND_ASSIGN(TabbedBrowserWindowRTLTest);
-};
-
-// Test to make sure that our window widgets are in the right place.
-// Currently, this is the same exact test as above, since RTL button
-// layout is behind the ExperimentalMacRTL flag. However, this ensures
-// that our calculations are correct for Sierra RTL, which lays out
-// the window buttons in reverse by default. See crbug/662079.
-TEST_F(TabbedBrowserWindowRTLTest, WindowWidgetLocation) {
-  NSView* closeBoxControl = [window() standardWindowButton:NSWindowCloseButton];
-  EXPECT_TRUE(closeBoxControl);
-  NSRect closeBoxFrame =
-      [closeBoxControl convertRect:[closeBoxControl bounds] toView:nil];
-  NSRect windowBounds = [window() frame];
-  windowBounds = [[window() contentView] convertRect:windowBounds fromView:nil];
-  windowBounds.origin = NSZeroPoint;
-  EXPECT_EQ(NSMaxY(closeBoxFrame), NSMaxY(windowBounds) - kWindowButtonInset);
-  EXPECT_EQ(NSMinX(closeBoxFrame), kWindowButtonInset);
-}
-
-WEAK_IMPORT_ATTRIBUTE
-@interface NSThemeFrame : NSView
-@end
-
-// Test that NSThemeFrame and NSWindow respond to the undocumented methods
-// which TabbedBrowserWindowFrame and TabbedBrowserWindow override.
-TEST(TabbedBrowserWindowOverrideTest, UndocumentedMethods) {
-  EXPECT_TRUE([NSThemeFrame
-      respondsToSelector:@selector(contentRectForFrameRect:styleMask:)]);
-  EXPECT_TRUE([NSThemeFrame
-      respondsToSelector:@selector(frameRectForContentRect:styleMask:)]);
-  EXPECT_TRUE([NSThemeFrame
-      instancesRespondToSelector:@selector(_minXTitlebarWidgetInset)]);
-  EXPECT_TRUE([NSThemeFrame
-      instancesRespondToSelector:@selector(_minYTitlebarButtonsOffset)]);
-  EXPECT_TRUE(
-      [NSThemeFrame instancesRespondToSelector:@selector(_titlebarHeight)]);
-  EXPECT_TRUE([NSThemeFrame instancesRespondToSelector:@selector
-                            (contentRectForFrameRect:styleMask:)]);
-  EXPECT_TRUE([NSThemeFrame instancesRespondToSelector:@selector
-                            (frameRectForContentRect:styleMask:)]);
-  if (@available(macOS 10.12, *)) {
-    EXPECT_TRUE([NSThemeFrame
-        instancesRespondToSelector:@selector(_shouldFlipTrafficLightsForRTL)]);
-  } else if (@available(macOS 10.10, *)) {
-  } else {
-    EXPECT_TRUE([NSThemeFrame
-        instancesRespondToSelector:@selector(_fullScreenButtonOrigin)]);
-    EXPECT_TRUE(
-        [NSThemeFrame instancesRespondToSelector:@selector(_setContentView:)]);
-  }
-
-  EXPECT_TRUE(
-      [NSWindow respondsToSelector:@selector(frameViewClassForStyleMask:)]);
-  EXPECT_TRUE(
-      [NSWindow instancesRespondToSelector:@selector(_usesCustomDrawing)]);
-}
diff --git a/chrome/browser/ui/cocoa/tabs/OWNERS b/chrome/browser/ui/cocoa/tabs/OWNERS
deleted file mode 100644
index 5edf558..0000000
--- a/chrome/browser/ui/cocoa/tabs/OWNERS
+++ /dev/null
@@ -1,7 +0,0 @@
-avi@chromium.org
-rohitrao@chromium.org
-
-# For changes related to the tab alert indicator/button.
-miu@chromium.org
-
-# COMPONENT: UI>Browser>TabStrip
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_controller_unittest.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_controller_unittest.mm
deleted file mode 100644
index 2437d52d..0000000
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_controller_unittest.mm
+++ /dev/null
@@ -1,490 +0,0 @@
-// Copyright (c) 2012 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.
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/bind_helpers.h"
-#include "base/mac/scoped_nsautorelease_pool.h"
-#include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
-#include "chrome/browser/media/webrtc/media_stream_capture_indicator.h"
-#include "chrome/browser/ui/browser_window.h"
-#import "chrome/browser/ui/cocoa/browser_window_controller.h"
-#import "chrome/browser/ui/cocoa/tabs/tab_controller.h"
-#import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h"
-#import "chrome/browser/ui/cocoa/tabs/tab_strip_view.h"
-#import "chrome/browser/ui/cocoa/tabs/tab_view.h"
-#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
-#include "chrome/browser/ui/tabs/tab_utils.h"
-#include "chrome/browser/ui/tabs/test_tab_strip_model_delegate.h"
-#include "chrome/test/base/testing_profile.h"
-#include "content/public/browser/site_instance.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/common/media_stream_request.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-#include "ui/events/test/cocoa_test_event_utils.h"
-
-using content::SiteInstance;
-using content::WebContents;
-
-@interface TabStripControllerForAlertTesting : TabStripControllerCocoa {
-  // Keeps alert state of tabs in browser for testing purpose.
-  std::map<content::WebContents*, TabAlertState> contentsAlertStateMaps_;
-}
-@end
-
-@implementation TabStripControllerForAlertTesting
-// Returns the alert state of each tab from the map we are keeping.
-- (TabAlertState)alertStateForContents:(content::WebContents*)contents {
-  return contentsAlertStateMaps_[contents];
-}
-
-- (void)setAlertStateForContents:(content::WebContents*)contents
-                  withAlertState:(TabAlertState)alert_state {
-  contentsAlertStateMaps_[contents] = alert_state;
-}
-
-@end
-
-@interface TestTabStripControllerDelegate
-    : NSObject<TabStripControllerDelegate> {
-}
-@end
-
-@implementation TestTabStripControllerDelegate
-- (void)onActivateTabWithContents:(WebContents*)contents {
-}
-- (void)onTabChanged:(TabChangeType)change withContents:(WebContents*)contents {
-}
-- (void)onTabDetachedWithContents:(WebContents*)contents {
-}
-- (void)onTabInsertedWithContents:(WebContents*)contents
-                     inForeground:(BOOL)inForeground {
-}
-@end
-
-
-// Helper class for invoking a base::Closure via
-// -performSelector:withObject:afterDelay:.
-@interface TestClosureRunner : NSObject {
- @private
-  base::Closure closure_;
-}
-- (id)initWithClosure:(const base::Closure&)closure;
-- (void)scheduleDelayedRun;
-- (void)run;
-@end
-
-@implementation TestClosureRunner
-- (id)initWithClosure:(const base::Closure&)closure {
-  if (self) {
-    closure_ = closure;
-  }
-  return self;
-}
-- (void)scheduleDelayedRun {
-  [self performSelector:@selector(run) withObject:nil afterDelay:0];
-}
-- (void)run {
-  closure_.Run();
-}
-@end
-
-@interface TabStripControllerCocoa (Test)
-
-- (void)mouseMoved:(NSEvent*)event;
-
-@end
-
-@implementation TabViewCocoa (Test)
-
-- (TabControllerCocoa*)controller {
-  return controller_;
-}
-
-@end
-
-namespace {
-
-class TabStripControllerTest : public CocoaProfileTest {
- public:
-  void SetUp() override {
-    CocoaProfileTest::SetUp();
-    ASSERT_TRUE(browser());
-
-    NSWindow* window = browser()->window()->GetNativeWindow();
-    NSView* parent = [window contentView];
-    NSRect content_frame = [parent frame];
-
-    // Create the "switch view" (view that gets changed out when a tab
-    // switches).
-    NSRect switch_frame = NSMakeRect(0, 0, content_frame.size.width, 500);
-    base::scoped_nsobject<NSView> switch_view(
-        [[NSView alloc] initWithFrame:switch_frame]);
-    switch_view_ = switch_view;
-    [parent addSubview:switch_view_.get()];
-
-    // Create the tab strip view. It's expected to have a child button in it
-    // already as the "new tab" button so create that too.
-    NSRect strip_frame = NSMakeRect(0, NSMaxY(switch_frame),
-                                    content_frame.size.width, 30);
-    tab_strip_.reset(
-        [[TabStripView alloc] initWithFrame:strip_frame]);
-    [parent addSubview:tab_strip_.get()];
-
-    delegate_.reset(new TestTabStripModelDelegate());
-    model_ = browser()->tab_strip_model();
-    controller_delegate_.reset([TestTabStripControllerDelegate alloc]);
-    controller_.reset([[TabStripControllerCocoa alloc]
-        initWithView:static_cast<TabStripView*>(tab_strip_.get())
-          switchView:switch_view.get()
-             browser:browser()
-            delegate:controller_delegate_.get()]);
-  }
-
-  void TearDown() override {
-    // The call to CocoaTest::TearDown() deletes the Browser and TabStripModel
-    // objects, so we first have to delete the controller, which refers to them.
-    controller_.reset();
-    model_ = NULL;
-    CocoaProfileTest::TearDown();
-  }
-
-  // Return a derived TabStripControllerCocoa.
-  TabStripControllerForAlertTesting* InitTabStripControllerForAlertTesting() {
-    TabStripControllerForAlertTesting* c =
-        [[TabStripControllerForAlertTesting alloc]
-            initWithView:static_cast<TabStripView*>(tab_strip_.get())
-              switchView:switch_view_.get()
-                 browser:browser()
-                delegate:controller_delegate_.get()];
-    return c;
-  }
-
-  TabViewCocoa* CreateTab() {
-    std::unique_ptr<WebContents> web_contents =
-        WebContents::Create(content::WebContents::CreateParams(
-            profile(), SiteInstance::Create(profile())));
-    model_->AppendWebContents(std::move(web_contents), true);
-    const NSUInteger tab_count = [controller_.get() viewsCount];
-    return static_cast<TabViewCocoa*>(
-        [controller_.get() viewAtIndex:tab_count - 1]);
-  }
-
-  // Closes all tabs and unrefs the tabstrip and then posts a NSLeftMouseUp
-  // event which should end the nested drag event loop.
-  void CloseTabsAndEndDrag() {
-    // Simulate a close of the browser window.
-    model_->CloseAllTabs();
-    controller_.reset();
-    tab_strip_.reset();
-    // Schedule a NSLeftMouseUp to end the nested drag event loop.
-    NSEvent* event =
-        cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp, 0);
-    [NSApp postEvent:event atStart:NO];
-  }
-
-  std::unique_ptr<TestTabStripModelDelegate> delegate_;
-  TabStripModel* model_;
-  base::scoped_nsobject<TestTabStripControllerDelegate> controller_delegate_;
-  base::scoped_nsobject<TabStripControllerCocoa> controller_;
-  base::scoped_nsobject<TabStripView> tab_strip_;
-  base::scoped_nsobject<NSView> switch_view_;
-};
-
-// Test adding and removing tabs and making sure that views get added to
-// the tab strip.
-TEST_F(TabStripControllerTest, AddRemoveTabs) {
-  EXPECT_TRUE(model_->empty());
-  CreateTab();
-  EXPECT_EQ(model_->count(), 1);
-}
-
-// Clicking a selected (but inactive) tab should activate it.
-TEST_F(TabStripControllerTest, ActivateSelectedButInactiveTab) {
-  TabViewCocoa* tab0 = CreateTab();
-  TabViewCocoa* tab1 = CreateTab();
-  model_->ToggleSelectionAt(0);
-  EXPECT_TRUE([[tab0 controller] selected]);
-  EXPECT_TRUE([[tab1 controller] selected]);
-
-  [controller_ selectTab:tab1];
-  EXPECT_EQ(1, model_->active_index());
-}
-
-// Toggling (cmd-click) a selected (but inactive) tab should deselect it.
-TEST_F(TabStripControllerTest, DeselectInactiveTab) {
-  TabViewCocoa* tab0 = CreateTab();
-  TabViewCocoa* tab1 = CreateTab();
-  model_->ToggleSelectionAt(0);
-  EXPECT_TRUE([[tab0 controller] selected]);
-  EXPECT_TRUE([[tab1 controller] selected]);
-
-  model_->ToggleSelectionAt(1);
-  EXPECT_TRUE([[tab0 controller] selected]);
-  EXPECT_FALSE([[tab1 controller] selected]);
-}
-
-TEST_F(TabStripControllerTest, SelectTab) {
-  // TODO(pinkerton): Implement http://crbug.com/10899
-}
-
-TEST_F(TabStripControllerTest, RearrangeTabs) {
-  // TODO(pinkerton): Implement http://crbug.com/10899
-}
-
-TEST_F(TabStripControllerTest, CorrectMouseHoverBehavior) {
-  TabViewCocoa* tab1 = CreateTab();
-  TabViewCocoa* tab2 = CreateTab();
-
-  EXPECT_FALSE([tab1 controller].selected);
-  EXPECT_TRUE([tab2 controller].selected);
-
-  // Check that there's no hovered tab yet.
-  EXPECT_FALSE([controller_ hoveredTab]);
-
-  // Set up mouse event on overlap of tab1 + tab2.
-  const CGFloat min_y = NSMinY([tab_strip_.get() frame]) + 1;
-  const CGFloat tab_overlap = [TabStripControllerCocoa tabOverlap];
-
-  // Hover over overlap between tab 1 and 2.
-  NSRect tab1_frame = [tab1 frame];
-  NSPoint tab_overlap_point =
-      NSMakePoint(NSMaxX(tab1_frame) - tab_overlap / 2, min_y);
-
-  NSEvent* event = cocoa_test_event_utils::MouseEventAtPoint(tab_overlap_point,
-                                                             NSMouseMoved,
-                                                             0);
-  [controller_.get() mouseMoved:event];
-  EXPECT_EQ(tab2, [controller_ hoveredTab]);
-
-  // Hover over tab 1.
-  NSPoint hover_point = NSMakePoint(NSMidX(tab1_frame), min_y);
-  event =
-      cocoa_test_event_utils::MouseEventAtPoint(hover_point, NSMouseMoved, 0);
-  [controller_.get() mouseMoved:event];
-  EXPECT_EQ(tab1, [controller_ hoveredTab]);
-
-  // Hover over tab 2.
-  NSRect tab2_frame = [tab2 frame];
-  hover_point = NSMakePoint(NSMidX(tab2_frame), min_y);
-  event =
-      cocoa_test_event_utils::MouseEventAtPoint(hover_point, NSMouseMoved, 0);
-  [controller_.get() mouseMoved:event];
-  EXPECT_EQ(tab2, [controller_ hoveredTab]);
-}
-
-TEST_F(TabStripControllerTest, CorrectTitleAndToolTipTextFromSetTabTitle) {
-  using content::MediaStreamDevice;
-  using content::MediaStreamDevices;
-  using content::MediaStreamUI;
-
-  TabViewCocoa* const tab = CreateTab();
-  TabControllerCocoa* const tabController = [tab controller];
-  WebContents* const contents = model_->GetActiveWebContents();
-
-  // For the duration of the test, assume the tab has been hovered. This adds a
-  // subview containing the actual source of the tooltip.
-  [controller_ setHoveredTab:tab];
-  // Note -[NSView hitTest:] takes superview coordinates. Then, find a spot that
-  // is outside the mask image, but inside the tab.
-  NSPoint centerPoint = NSMakePoint(5, NSMidY([tab bounds]));
-  NSPoint hitPoint = [tab convertPoint:centerPoint
-                                toView:[tab_strip_ superview]];
-  NSView* toolTipView = [tab_strip_ hitTest:hitPoint];
-  EXPECT_TRUE(toolTipView);
-  EXPECT_NE(toolTipView, tab);
-
-  // Initially, tab title and tooltip text are equivalent.
-  EXPECT_EQ(TabAlertState::NONE,
-            chrome::GetTabAlertStateForContents(contents));
-  [controller_ setTabTitle:tabController withContents:contents];
-  NSString* const baseTitle = [tabController title];
-  EXPECT_NSEQ(baseTitle, [tabController toolTip]);
-  EXPECT_NSEQ([tabController toolTip], [toolTipView toolTip]);
-
-  // Simulate the start of tab video capture.  Tab title remains the same, but
-  // the tooltip text should include the following appended: 1) a line break;
-  // 2) a non-empty string with a localized description of the alert state.
-  scoped_refptr<MediaStreamCaptureIndicator> indicator =
-      MediaCaptureDevicesDispatcher::GetInstance()->
-          GetMediaStreamCaptureIndicator();
-  const MediaStreamDevice dummyVideoCaptureDevice(
-      content::MEDIA_GUM_TAB_VIDEO_CAPTURE, "dummy_id", "dummy name");
-  std::unique_ptr<MediaStreamUI> streamUi(indicator->RegisterMediaStream(
-      contents, MediaStreamDevices(1, dummyVideoCaptureDevice)));
-  streamUi->OnStarted(base::DoNothing());
-  EXPECT_EQ(TabAlertState::TAB_CAPTURING,
-            chrome::GetTabAlertStateForContents(contents));
-  [controller_ setTabTitle:tabController withContents:contents];
-  EXPECT_NSEQ(baseTitle, [tabController title]);
-  NSString* const toolTipText = [tabController toolTip];
-  EXPECT_NSEQ(toolTipText, [toolTipView toolTip]);
-  if ([baseTitle length] > 0) {
-    EXPECT_TRUE(NSEqualRanges(NSMakeRange(0, [baseTitle length]),
-                              [toolTipText rangeOfString:baseTitle]));
-    EXPECT_TRUE(NSEqualRanges(NSMakeRange([baseTitle length], 1),
-                              [toolTipText rangeOfString:@"\n"]));
-    EXPECT_LT([baseTitle length] + 1, [toolTipText length]);
-  } else {
-    EXPECT_LT(0u, [toolTipText length]);
-  }
-
-  // Simulate the end of tab video capture.  Tab title and tooltip should become
-  // equivalent again.
-  streamUi.reset();
-  EXPECT_EQ(TabAlertState::NONE,
-            chrome::GetTabAlertStateForContents(contents));
-  [controller_ setTabTitle:tabController withContents:contents];
-  EXPECT_NSEQ(baseTitle, [tabController title]);
-  EXPECT_NSEQ(baseTitle, [tabController toolTip]);
-  EXPECT_NSEQ(baseTitle, [toolTipView toolTip]);
-}
-
-TEST_F(TabStripControllerTest, TabCloseDuringDrag) {
-  TabControllerCocoa* tab;
-  // The TabControllerCocoa gets autoreleased when created, but is owned by the
-  // tab strip model. Use a ScopedNSAutoreleasePool to get a truly weak ref
-  // to it to test that -maybeStartDrag:forTab: can handle that properly.
-  {
-    base::mac::ScopedNSAutoreleasePool pool;
-    tab = [CreateTab() controller];
-  }
-
-  // Schedule a task to close all the tabs and stop the drag, before the call to
-  // -maybeStartDrag:forTab:, which starts a nested event loop. This task will
-  // run in that nested event loop, which shouldn't crash.
-  base::scoped_nsobject<TestClosureRunner> runner([[TestClosureRunner alloc]
-      initWithClosure:base::Bind(&TabStripControllerTest::CloseTabsAndEndDrag,
-                                 base::Unretained(this))]);
-  [runner scheduleDelayedRun];
-
-  NSEvent* event =
-      cocoa_test_event_utils::LeftMouseDownAtPoint(NSZeroPoint);
-  [[controller_ dragController] maybeStartDrag:event forTab:tab];
-}
-
-TEST_F(TabStripControllerTest, ViewAccessibility_Contents) {
-  NSArray* attrs = [tab_strip_ accessibilityAttributeNames];
-  ASSERT_TRUE([attrs containsObject:NSAccessibilityContentsAttribute]);
-
-  // Create two tabs and ensure they exist in the contents array.
-  TabViewCocoa* tab1 = CreateTab();
-  TabViewCocoa* tab2 = CreateTab();
-  NSObject* contents =
-      [tab_strip_ accessibilityAttributeValue:NSAccessibilityContentsAttribute];
-  DCHECK([contents isKindOfClass:[NSArray class]]);
-  NSArray* contentsArray = static_cast<NSArray*>(contents);
-  ASSERT_TRUE([contentsArray containsObject:tab1]);
-  ASSERT_TRUE([contentsArray containsObject:tab2]);
-}
-
-TEST_F(TabStripControllerTest, ViewAccessibility_Value) {
-  NSArray* attrs = [tab_strip_ accessibilityAttributeNames];
-  ASSERT_TRUE([attrs containsObject:NSAccessibilityValueAttribute]);
-
-  // Create two tabs and ensure the active one gets returned.
-  TabViewCocoa* tab1 = CreateTab();
-  TabViewCocoa* tab2 = CreateTab();
-  EXPECT_FALSE([tab1 controller].selected);
-  EXPECT_TRUE([tab2 controller].selected);
-  NSObject* value =
-      [tab_strip_ accessibilityAttributeValue:NSAccessibilityValueAttribute];
-  EXPECT_EQ(tab2, value);
-
-  model_->ActivateTabAt(0, false);
-  EXPECT_TRUE([tab1 controller].selected);
-  EXPECT_FALSE([tab2 controller].selected);
-  value =
-      [tab_strip_ accessibilityAttributeValue:NSAccessibilityValueAttribute];
-  EXPECT_EQ(tab1, value);
-}
-
-TEST_F(TabStripControllerTest, CorrectWindowFromUpdateWindowAlertState) {
-  controller_.reset(InitTabStripControllerForAlertTesting());
-  NSWindow* window = [tab_strip_ window];
-  BrowserWindowController* window_controller =
-      [BrowserWindowController browserWindowControllerForWindow:window];
-  TabStripControllerForAlertTesting* tabStripControllerForTesting =
-      static_cast<TabStripControllerForAlertTesting*>(controller_);
-
-  TabViewCocoa* const tab1 = CreateTab();
-  TabViewCocoa* const tab2 = CreateTab();
-
-  // tab2 should be the selected one.
-  EXPECT_FALSE([tab1 controller].selected);
-  EXPECT_TRUE([tab2 controller].selected);
-  WebContents* const contents_at_tab1 = model_->GetActiveWebContents();
-
-  [tabStripControllerForTesting
-      setAlertStateForContents:contents_at_tab1
-                withAlertState:TabAlertState::AUDIO_PLAYING];
-  // Make sure the overriden from base controller correctly handles alert
-  // status of tabs.
-  EXPECT_EQ(TabAlertState::AUDIO_PLAYING,
-            [controller_ alertStateForContents:contents_at_tab1]);
-  [controller_ updateWindowAlertState:TabAlertState::AUDIO_PLAYING
-                       forWebContents:contents_at_tab1];
-  // Because we have one tab playing, and the other one's alert state is none,
-  // window alert state should be AUDIO_PLAYING.
-  EXPECT_EQ(TabAlertState::AUDIO_PLAYING, [window_controller alertState]);
-
-  model_->ActivateTabAt(0, false);
-  // tab1 should be the selected one now.
-  EXPECT_TRUE([tab1 controller].selected);
-  EXPECT_FALSE([tab2 controller].selected);
-  WebContents* const contents_at_tab0 = model_->GetActiveWebContents();
-
-  [tabStripControllerForTesting
-      setAlertStateForContents:contents_at_tab0
-                withAlertState:TabAlertState::AUDIO_MUTING];
-  [controller_ updateWindowAlertState:TabAlertState::AUDIO_MUTING
-                       forWebContents:contents_at_tab0];
-  // We have two tabs. One is playing and the other one is muting. The window
-  // alert state should be still AUDIO_PLAYING.
-  EXPECT_EQ(TabAlertState::AUDIO_PLAYING, [window_controller alertState]);
-
-  [tabStripControllerForTesting
-      setAlertStateForContents:contents_at_tab1
-                withAlertState:TabAlertState::AUDIO_MUTING];
-  [controller_ updateWindowAlertState:TabAlertState::AUDIO_MUTING
-                       forWebContents:contents_at_tab1];
-  // Now both tabs are muting, the window alert state should be AUDIO_MUTING.
-  EXPECT_EQ(TabAlertState::AUDIO_MUTING, [window_controller alertState]);
-
-  [tabStripControllerForTesting
-      setAlertStateForContents:contents_at_tab0
-                withAlertState:TabAlertState::AUDIO_PLAYING];
-  [controller_ updateWindowAlertState:TabAlertState::AUDIO_PLAYING
-                       forWebContents:contents_at_tab0];
-  // Among those tabs which were muting, one is started playing, the window
-  // alert state should be playing.
-  EXPECT_EQ(TabAlertState::AUDIO_PLAYING, [window_controller alertState]);
-
-  // Mute it again for further testing.
-  [tabStripControllerForTesting
-      setAlertStateForContents:contents_at_tab0
-                withAlertState:TabAlertState::AUDIO_MUTING];
-  [controller_ updateWindowAlertState:TabAlertState::AUDIO_MUTING
-                       forWebContents:contents_at_tab0];
-
-  [tabStripControllerForTesting setAlertStateForContents:contents_at_tab1
-                                          withAlertState:TabAlertState::NONE];
-  [controller_ updateWindowAlertState:TabAlertState::NONE
-                       forWebContents:contents_at_tab1];
-  // One of the tabs is muting, the other one is none. So window alert state
-  // should be MUTING.
-  EXPECT_EQ(TabAlertState::AUDIO_MUTING, [window_controller alertState]);
-
-  [tabStripControllerForTesting setAlertStateForContents:contents_at_tab0
-                                          withAlertState:TabAlertState::NONE];
-  [controller_ updateWindowAlertState:TabAlertState::NONE
-                       forWebContents:contents_at_tab0];
-  // Neither of tabs playing nor muting, so the window alert state should be
-  // NONE.
-  EXPECT_EQ(TabAlertState::NONE, [window_controller alertState]);
-}
-
-}  // namespace
diff --git a/chrome/browser/ui/cocoa/tabs/tab_window_controller.h b/chrome/browser/ui/cocoa/tabs/tab_window_controller.h
deleted file mode 100644
index 2299924..0000000
--- a/chrome/browser/ui/cocoa/tabs/tab_window_controller.h
+++ /dev/null
@@ -1,195 +0,0 @@
-// Copyright (c) 2012 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 CHROME_BROWSER_UI_COCOA_TABS_TAB_WINDOW_CONTROLLER_H_
-#define CHROME_BROWSER_UI_COCOA_TABS_TAB_WINDOW_CONTROLLER_H_
-
-// A class acting as the Objective-C window controller for a window that has
-// tabs which can be dragged around. Tabs can be re-arranged within the same
-// window or dragged into other TabWindowController windows. This class doesn't
-// know anything about the actual tab implementation or model, as that is fairly
-// application-specific. It only provides an API to be overridden by subclasses
-// to fill in the details.
-// Note that under the hood the TabWindowController is neither an
-// NSWindowController nor its window's delegate, though it receives all
-// NSWindowDelegate methods as if it were. It also resides in the responder
-// chain.
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/mac/availability.h"
-#include "base/mac/scoped_nsobject.h"
-
-@class FastResizeView;
-@class FocusTracker;
-@class NSVisualEffectView;
-@class TabViewCocoa;
-
-@interface TabWindowController : NSResponder<NSWindowDelegate> {
- @private
-  // Wrapper view around web content, and the developer tools view.
-  base::scoped_nsobject<FastResizeView> tabContentArea_;
-  // No views should be added directly to the root view. Views that overlap
-  // the title bar should be added to the window's contentView. All other views
-  // should be added to chromeContentView_. This allows tab dragging and
-  // fullscreen logic to easily move the views that don't need special
-  // treatment.
-  base::scoped_nsobject<NSView> chromeContentView_;
-
-  base::scoped_nsobject<FocusTracker> focusBeforeOverlay_;
-  BOOL closeDeferred_;  // If YES, call performClose: in removeOverlay:.
-}
-
-// Returns the NSWindowController that manages the TabWindowController's
-// NSWindow. In the past the TabWindowController was also the window's
-// NSWindowController but they are now separate objects. Use
-// +tabWindowControllerForWindow: to retrieve a TabWindowController from a
-// given NSWindow.
-@property(readonly, nonatomic)
-    NSWindowController<NSWindowDelegate>* nsWindowController;
-@property(retain, nonatomic) NSWindow* window;
-@property(readonly, nonatomic) API_AVAILABLE(macos(10.10))
-    NSVisualEffectView* visualEffectView;
-@property(readonly, nonatomic) FastResizeView* tabContentArea;
-@property(readonly, nonatomic) NSView* chromeContentView;
-
-// A convenience class method which returns the |TabWindowController| for
-// |window|, or nil if neither |window| nor its parent or any other ancestor
-// has one.
-+ (TabWindowController*)tabWindowControllerForWindow:(NSWindow*)window;
-
-// This is the designated initializer for this class.
-- (id)initTabWindowControllerWithTabStrip:(BOOL)hasTabStrip
-                                 titleBar:(BOOL)hasTitleBar;
-
-// Used during tab dragging to turn on/off the overlay window when a tab
-// is torn off. If -deferPerformClose (below) is used, -removeOverlay will
-// cause the controller to be autoreleased before returning.
-- (void)showOverlay;
-- (void)removeOverlay;
-- (NSWindow*)overlayWindow;
-
-// Returns YES if it is ok to constrain the window's frame to fit the screen.
-- (BOOL)shouldConstrainFrameRect;
-
-// A collection of methods, stubbed out in this base class, that provide
-// the implementation of tab dragging based on whatever model is most
-// appropriate.
-
-// Layout the tabs based on the current ordering of the model.
-- (void)layoutTabs;
-
-// Creates a new window by pulling the given tabs out and placing it in
-// the new window. Returns the controller for the new window. The size of the
-// new window will be the same size as this window.
-- (TabWindowController*)detachTabsToNewWindow:(NSArray*)tabViews
-                                   draggedTab:(NSView*)draggedTab;
-
-// Make room in the tab strip for |tab| at the given x coordinate. Will hide the
-// new tab button while there's a placeholder. Subclasses need to call the
-// superclass implementation.
-- (void)insertPlaceholderForTab:(TabViewCocoa*)tab frame:(NSRect)frame;
-
-// Removes the placeholder installed by |-insertPlaceholderForTab:atLocation:|
-// and restores the new tab button. Subclasses need to call the superclass
-// implementation.
-- (void)removePlaceholder;
-
-// Returns whether one of the window's tabs is being dragged.
-- (BOOL)isDragSessionActive;
-
-// The follow return YES if tab dragging/tab tearing (off the tab strip)/window
-// movement is currently allowed. Any number of things can choose to disable it,
-// such as pending animations. The default implementations always return YES.
-// Subclasses should override as appropriate.
-- (BOOL)tabDraggingAllowed;
-- (BOOL)tabTearingAllowed;
-- (BOOL)windowMovementAllowed;
-
-// Show or hide the new tab button. The button is hidden immediately, but
-// waits until the next call to |-layoutTabs| to show it again.
-- (void)showNewTabButton:(BOOL)show;
-
-// Returns whether or not |tab| can still be fully seen in the tab strip or if
-// its current position would cause it be obscured by things such as the edge
-// of the window or the window decorations. Returns YES only if the entire tab
-// is visible. The default implementation always returns YES.
-- (BOOL)isTabFullyVisible:(TabViewCocoa*)tab;
-
-// Called to check if the receiver can receive dragged tabs from
-// source.  Return YES if so.  The default implementation returns NO.
-- (BOOL)canReceiveFrom:(TabWindowController*)source;
-
-// Move given tab views to the location of the current placeholder. If there is
-// no placeholder, it will go at the end. |controller| is the window controller
-// of a tab being dropped from a different window. It will be nil if the drag is
-// within the window, otherwise the tab is removed from that window before being
-// placed into this one. The implementation will call |-removePlaceholder| since
-// the drag is now complete.  This also calls |-layoutTabs| internally so
-// clients do not need to call it again.
-- (void)moveTabViews:(NSArray*)views
-      fromController:(TabWindowController*)controller;
-
-// Called if the tab is in a detached window and has finished dragging.
-// If the source window is in fullscreen, the detached window will also
-// enter fullscreen.
-- (void)detachedWindowEnterFullscreenIfNeeded:(TabWindowController*)source;
-
-// Number of tabs in the tab strip. Useful, for example, to know if we're
-// dragging the only tab in the window. This includes pinned tabs (both live
-// and not).
-- (NSInteger)numberOfTabs;
-
-// YES if there are tabs in the tab strip which have content, allowing for
-// the notion of tabs in the tab strip that are placeholders but currently have
-// no content.
-- (BOOL)hasLiveTabs;
-
-// Returns all tab views.
-- (NSArray*)tabViews;
-
-// Return the view of the active tab.
-- (NSView*)activeTabView;
-
-// The title of the active tab.
-- (NSString*)activeTabTitle;
-
-// Called to check whether or not this controller's window has a tab strip (YES
-// if it does, NO otherwise). The default implementation returns YES.
-- (BOOL)hasTabStrip;
-
-// Gets whether a particular tab is draggable between windows.
-- (BOOL)isTabDraggable:(NSView*)tabView;
-
-// In any fullscreen mode, the y offset to use for the content at the top of
-// the screen (tab strip, omnibox, bookmark bar, etc). Ranges from 0 to -22.
-- (CGFloat)menubarOffset;
-
-// The height of the menubar.
-- (CGFloat)menubarHeight;
-
-// Returns YES if the browser window is in or entering any fullscreen mode.
-- (BOOL)isInAnyFullscreenMode;
-
-// Returns the view of the avatar button.
-- (NSView*)avatarView;
-
-// Tell the window that it needs to call performClose: as soon as the current
-// drag is complete. This prevents a window (and its overlay) from going away
-// during a drag.
-- (void)deferPerformClose;
-
-@end
-
-@interface TabWindowController(ProtectedMethods)
-// Tells the tab strip to forget about this tab in preparation for it being
-// put into a different tab strip, such as during a drop on another window.
-- (void)detachTabView:(NSView*)view;
-
-// Called when the size of the window content area has changed. Override to
-// position specific views. Base class implementation does nothing.
-- (void)layoutSubviews;
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_TABS_TAB_WINDOW_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm b/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm
deleted file mode 100644
index a96af4a..0000000
--- a/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm
+++ /dev/null
@@ -1,445 +0,0 @@
-// Copyright (c) 2012 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.
-
-#import "chrome/browser/ui/cocoa/tabs/tab_window_controller.h"
-
-#import <objc/runtime.h>
-
-#include "base/logging.h"
-#import "base/mac/foundation_util.h"
-#import "base/mac/sdk_forward_declarations.h"
-#import "chrome/browser/ui/cocoa/browser_window_layout.h"
-#import "chrome/browser/ui/cocoa/fast_resize_view.h"
-#import "chrome/browser/ui/cocoa/framed_browser_window.h"
-#import "chrome/browser/ui/cocoa/tabbed_browser_window.h"
-#import "chrome/browser/ui/cocoa/themed_window.h"
-#include "chrome/browser/ui/window_sizer/window_sizer.h"
-#import "ui/base/cocoa/focus_tracker.h"
-#include "ui/base/material_design/material_design_controller.h"
-#include "ui/base/theme_provider.h"
-
-// As of macOS 10.13 NSWindow lifetimes after closing are unpredictable. Chrome
-// frees resources on window close so this new behavior created problems such as
-// browser tests failing to complete (see https://crbug.com/749196 ). To work
-// around this new behavior TabWindowController no longer acts as the NSWindow's
-// NSWindowController or NSWindowDelegate but instead uses a
-// TabWindowControllerProxy instance. The TabWindowController and its subclasses
-// still expect to receive NSWindowDelegate messages, which the
-// TabWindowControllerProxy forwards along.
-@interface TabWindowControllerProxy : NSWindowController<NSWindowDelegate>
-@property(assign, nonatomic) TabWindowController* tabWindowController;
-@end
-
-@implementation TabWindowControllerProxy
-
-@synthesize tabWindowController = tabWindowController_;
-
-- (void)dealloc {
-  // The TabWindowControllerProxy should outlive the TabWindowController.
-  DCHECK(!tabWindowController_);
-  [super dealloc];
-}
-
-- (BOOL)respondsToSelector:(SEL)aSelector {
-  if ([super respondsToSelector:aSelector]) {
-    return YES;
-  }
-  return [self.tabWindowController respondsToSelector:aSelector];
-}
-
-- (NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector {
-  NSMethodSignature* signature = [super methodSignatureForSelector:aSelector];
-
-  return signature
-             ? signature
-             : [self.tabWindowController methodSignatureForSelector:aSelector];
-}
-
-- (void)forwardInvocation:(NSInvocation*)anInvocation {
-  [anInvocation setTarget:self.tabWindowController];
-  [anInvocation invoke];
-}
-
-@end
-
-@interface TabWindowController () {
-  base::scoped_nsobject<TabWindowControllerProxy> nsWindowController_;
-}
-
-- (void)setUseOverlay:(BOOL)useOverlay;
-
-// The tab strip background view should always be inserted as the back-most
-// subview of the contentView.
-- (void)insertTabStripBackgroundViewIntoWindow:(NSWindow*)window
-                                      titleBar:(BOOL)hasTitleBar;
-
-// Called when NSWindowWillEnterFullScreenNotification notification received.
-// Makes visual effects view hidden as it should not be displayed in fullscreen.
-- (void)windowWillEnterFullScreenNotification:(NSNotification*)notification;
-
-// Called when NSWindowWillExitFullScreenNotification notification received.
-// Makes visual effects view visible since it was hidden in fullscreen.
-- (void)windowWillExitFullScreenNotification:(NSNotification*)notification;
-
-@end
-
-@interface TabWindowOverlayWindow : NSWindow
-@end
-
-@implementation TabWindowOverlayWindow
-
-- (const ui::ThemeProvider*)themeProvider {
-  return [[self parentWindow] themeProvider];
-}
-
-- (ThemedWindowStyle)themedWindowStyle {
-  return [[self parentWindow] themedWindowStyle];
-}
-
-- (NSPoint)themeImagePositionForAlignment:(ThemeImageAlignment)alignment {
-  return [[self parentWindow] themeImagePositionForAlignment:alignment];
-}
-
-- (BOOL)hasDarkTheme {
-  return [[self parentWindow] hasDarkTheme];
-}
-
-- (BOOL)inIncognitoModeWithSystemTheme {
-  return [[self parentWindow] inIncognitoModeWithSystemTheme];
-}
-
-@end
-
-// Subview of the window's contentView, contains everything but the tab strip.
-@interface ChromeContentView : NSView
-@end
-
-@implementation ChromeContentView
-
-// NSView overrides.
-
-// Since Auto Layout and frame-based layout behave differently in small but
-// important ways (e.g. Auto Layout can restrict window resizing, frame-based
-// layout doesn't log a warning when a view's autoresizing mask can't be
-// maintained), ensure that it's on instead of letting it depend on content.
-+ (BOOL)requiresConstraintBasedLayout {
-  // TODO(sdy): Turn back on (or remove) after investigating a performance
-  // regression: https://crbug.com/706931
-  return NO;
-}
-
-@end
-
-@implementation TabWindowController
-
-+ (TabWindowController*)tabWindowControllerForWindow:(NSWindow*)window {
-  while (window) {
-    TabWindowControllerProxy* nsWindowController =
-        base::mac::ObjCCast<TabWindowControllerProxy>(
-            [window windowController]);
-
-    if (nsWindowController) {
-      return [nsWindowController tabWindowController];
-    }
-    window = [window parentWindow];
-  }
-  return nil;
-}
-
-- (id)initTabWindowControllerWithTabStrip:(BOOL)hasTabStrip
-                                 titleBar:(BOOL)hasTitleBar {
-  const CGFloat kDefaultWidth = WindowSizer::kWindowMaxDefaultWidth;
-  const CGFloat kDefaultHeight = 600;
-
-  if (self = [self init]) {
-    NSRect contentRect = NSMakeRect(60, 229, kDefaultWidth, kDefaultHeight);
-    base::scoped_nsobject<FramedBrowserWindow> window(
-        [(hasTabStrip
-              ? [TabbedBrowserWindow alloc]
-              : [FramedBrowserWindow alloc]) initWithContentRect:contentRect]);
-    [window setReleasedWhenClosed:YES];
-    [window setAutorecalculatesKeyViewLoop:YES];
-
-    nsWindowController_.reset(
-        [[TabWindowControllerProxy alloc] initWithWindow:window]);
-    [nsWindowController_ setTabWindowController:self];
-
-    [[self window] setDelegate:nsWindowController_];
-
-    // Insert ourselves into the repsonder chain. First, find the responder
-    // that comes before nsWindowController_.
-    NSResponder* nextResponderToCheck = [self window];
-    while ([nextResponderToCheck nextResponder] &&
-           [nextResponderToCheck nextResponder] != nsWindowController_.get()) {
-      nextResponderToCheck = [nextResponderToCheck nextResponder];
-    }
-    // If nextResponder is nil, nsWindowController_ is not in the responder
-    // chain.
-    DCHECK([nextResponderToCheck nextResponder]);
-    // Insert before nsWindowController_.
-    [nextResponderToCheck setNextResponder:self];
-    [self setNextResponder:nsWindowController_];
-
-    chromeContentView_.reset([[ChromeContentView alloc]
-        initWithFrame:NSMakeRect(0, 0, kDefaultWidth, kDefaultHeight)]);
-    [chromeContentView_
-        setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
-    [chromeContentView_ setWantsLayer:YES];
-    [[[self window] contentView] addSubview:chromeContentView_];
-
-    tabContentArea_.reset(
-        [[FastResizeView alloc] initWithFrame:[chromeContentView_ bounds]]);
-    [tabContentArea_
-        setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
-    [chromeContentView_ addSubview:tabContentArea_];
-
-    [self insertTabStripBackgroundViewIntoWindow:window titleBar:hasTitleBar];
-
-    // |windowWillEnterFullScreen:| and |windowWillExitFullScreen:| are
-    // already called because self is a delegate for the window. However this
-    // class is designed for subclassing and can not implement
-    // NSWindowDelegate methods (because subclasses can do so as well and they
-    // should be able to). TODO(crbug.com/654656): Move |visualEffectView_| to
-    // subclass.
-    [[NSNotificationCenter defaultCenter]
-        addObserver:self
-           selector:@selector(windowWillEnterFullScreenNotification:)
-               name:NSWindowWillEnterFullScreenNotification
-             object:window];
-    [[NSNotificationCenter defaultCenter]
-        addObserver:self
-           selector:@selector(windowWillExitFullScreenNotification:)
-               name:NSWindowWillExitFullScreenNotification
-             object:window];
-  }
-
-  return self;
-}
-
-- (void)dealloc {
-  // Restore the reponder chain. Find the responder before us in the chain.
-  NSResponder* nextResponderToCheck = [self window];
-  while ([nextResponderToCheck nextResponder] &&
-         [nextResponderToCheck nextResponder] != self) {
-    nextResponderToCheck = [nextResponderToCheck nextResponder];
-  }
-  [nextResponderToCheck setNextResponder:[self nextResponder]];
-
-  [[NSNotificationCenter defaultCenter] removeObserver:self];
-  [[self window] setDelegate:nil];
-  [nsWindowController_ setTabWindowController:nil];
-  [nsWindowController_ setWindow:nil];
-  [super dealloc];
-}
-
-- (NSWindow*)window {
-  return [nsWindowController_ window];
-}
-
-- (void)setWindow:(NSWindow*)aWindow {
-  [nsWindowController_ setWindow:aWindow];
-}
-
-- (NSWindowController*)nsWindowController {
-  return nsWindowController_;
-}
-
-- (NSVisualEffectView*)visualEffectView {
-  return nil;
-}
-
-- (FastResizeView*)tabContentArea {
-  return tabContentArea_;
-}
-
-- (NSView*)chromeContentView {
-  return chromeContentView_;
-}
-
-- (void)removeOverlay {
-  [self setUseOverlay:NO];
-  if (closeDeferred_) {
-    // See comment in BrowserWindowCocoa::Close() about orderOut:.
-    [[self window] orderOut:self];
-    [[self window] performClose:self];  // Autoreleases the controller.
-  }
-}
-
-- (void)showOverlay {
-  [self setUseOverlay:YES];
-}
-
-// If |useOverlay| is YES, creates a new overlay window and puts the tab strip
-// and the content area inside of it. This allows it to have a different opacity
-// from the title bar. If NO, returns everything to the previous state and
-// destroys the overlay window until it's needed again. The tab strip and window
-// contents are returned to the original window.
-- (void)setUseOverlay:(BOOL)useOverlay {
-}
-
-- (NSWindow*)overlayWindow {
-  return nil;
-}
-
-- (BOOL)shouldConstrainFrameRect {
-  // If we currently have an overlay window, do not attempt to change the
-  // window's size, as our overlay window doesn't know how to resize properly.
-  return NO;
-}
-
-- (BOOL)canReceiveFrom:(TabWindowController*)source {
-  // subclass must implement
-  NOTIMPLEMENTED();
-  return NO;
-}
-
-- (void)moveTabViews:(NSArray*)views
-      fromController:(TabWindowController*)dragController {
-  NOTIMPLEMENTED();
-}
-
-- (NSArray*)tabViews {
-  NOTIMPLEMENTED();
-  return nil;
-}
-
-- (NSView*)activeTabView {
-  NOTIMPLEMENTED();
-  return nil;
-}
-
-- (void)layoutTabs {
-  // subclass must implement
-  NOTIMPLEMENTED();
-}
-
-- (TabWindowController*)detachTabsToNewWindow:(NSArray*)tabViews
-                                   draggedTab:(NSView*)draggedTab {
-  // subclass must implement
-  NOTIMPLEMENTED();
-  return NULL;
-}
-
-- (void)detachedWindowEnterFullscreenIfNeeded:(TabWindowController*)source {
-  // Subclasses should implement this.
-  NOTIMPLEMENTED();
-}
-
-- (void)insertPlaceholderForTab:(TabViewCocoa*)tab frame:(NSRect)frame {
-  [self showNewTabButton:NO];
-}
-
-- (void)removePlaceholder {
-  [self showNewTabButton:YES];
-}
-
-- (BOOL)isDragSessionActive {
-  NOTIMPLEMENTED();
-  return NO;
-}
-
-- (BOOL)tabDraggingAllowed {
-  return YES;
-}
-
-- (BOOL)tabTearingAllowed {
-  return YES;
-}
-
-- (BOOL)windowMovementAllowed {
-  return YES;
-}
-
-- (BOOL)isTabFullyVisible:(TabViewCocoa*)tab {
-  // Subclasses should implement this, but it's not necessary.
-  return YES;
-}
-
-- (void)showNewTabButton:(BOOL)show {
-  // subclass must implement
-  NOTIMPLEMENTED();
-}
-
-- (void)detachTabView:(NSView*)view {
-  // subclass must implement
-  NOTIMPLEMENTED();
-}
-
-- (NSInteger)numberOfTabs {
-  // subclass must implement
-  NOTIMPLEMENTED();
-  return 0;
-}
-
-- (BOOL)hasLiveTabs {
-  // subclass must implement
-  NOTIMPLEMENTED();
-  return NO;
-}
-
-- (CGFloat)menubarOffset {
-  // Subclasses should implement this.
-  NOTIMPLEMENTED();
-  return 0;
-}
-
-- (CGFloat)menubarHeight {
-  // The height of the menubar. We can't use |-[NSMenu menuBarHeight]| since it
-  // returns 0 when the menu bar is hidden.
-  const CGFloat kMenubarHeight = 22;
-  return kMenubarHeight;
-}
-
-- (BOOL)isInAnyFullscreenMode {
-  // Subclass must implement.
-  NOTIMPLEMENTED();
-  return NO;
-}
-
-- (NSView*)avatarView {
-  return nil;
-}
-
-- (NSString*)activeTabTitle {
-  // subclass must implement
-  NOTIMPLEMENTED();
-  return @"";
-}
-
-- (BOOL)hasTabStrip {
-  // Subclasses should implement this.
-  NOTIMPLEMENTED();
-  return YES;
-}
-
-- (BOOL)isTabDraggable:(NSView*)tabView {
-  // Subclasses should implement this.
-  NOTIMPLEMENTED();
-  return YES;
-}
-
-// Tell the window that it needs to call performClose: as soon as the current
-// drag is complete. This prevents a window (and its overlay) from going away
-// during a drag.
-- (void)deferPerformClose {
-  closeDeferred_ = YES;
-}
-
-- (void)insertTabStripBackgroundViewIntoWindow:(NSWindow*)window
-                                      titleBar:(BOOL)hasTitleBar {
-}
-
-// Called when the size of the window content area has changed. Override to
-// position specific views. Base class implementation does nothing.
-- (void)layoutSubviews {
-  NOTIMPLEMENTED();
-}
-
-- (void)windowWillEnterFullScreenNotification:(NSNotification*)notification {
-}
-
-- (void)windowWillExitFullScreenNotification:(NSNotification*)notification {
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/themed_window.h b/chrome/browser/ui/cocoa/themed_window.h
deleted file mode 100644
index 7c57d58..0000000
--- a/chrome/browser/ui/cocoa/themed_window.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright (c) 2010 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 CHROME_BROWSER_UI_COCOA_THEMED_WINDOW_H_
-#define CHROME_BROWSER_UI_COCOA_THEMED_WINDOW_H_
-
-#import <Cocoa/Cocoa.h>
-
-namespace ui {
-class ThemeProvider;
-}
-using ui::ThemeProvider;
-
-// Bit flags; mix-and-match as necessary.
-enum {
-  THEMED_NORMAL    = 0,
-  THEMED_INCOGNITO = 1 << 0,
-  THEMED_POPUP     = 1 << 1,
-  THEMED_DEVTOOLS  = 1 << 2
-};
-typedef NSUInteger ThemedWindowStyle;
-
-// Indicates how the theme image should be aligned.
-enum ThemeImageAlignment {
-  // Aligns the top of the theme image with the top of the frame. Use this
-  // for IDR_THEME_THEME_FRAME.*
-  THEME_IMAGE_ALIGN_WITH_FRAME,
-  // Aligns the top of the theme image with the top of the tabs.
-  // Use this for IDR_THEME_TAB_BACKGROUND and IDR_THEME_TOOLBAR.
-  THEME_IMAGE_ALIGN_WITH_TAB_STRIP
-};
-
-// Implemented by windows that support theming.
-@interface NSWindow (ThemeProvider)
-- (const ThemeProvider*)themeProvider;
-- (ThemedWindowStyle)themedWindowStyle;
-- (BOOL)inIncognitoMode;
-// Return YES if using the system (i.e. non-custom) theme and Incognito mode.
-- (BOOL)inIncognitoModeWithSystemTheme;
-// Return YES if Incongnito, or a custom theme with a dark toolbar color or
-// light tab text.
-- (BOOL)hasDarkTheme;
-
-// Returns the position in window coordinates that the top left of a theme
-// image with |alignment| should be painted at. The result of this method can
-// be used in conjunction with [NSGraphicsContext cr_setPatternPhase:] to set
-// the offset of pattern colors.
-- (NSPoint)themeImagePositionForAlignment:(ThemeImageAlignment)alignment;
-@end
-
-// Adopted by views that want to redraw when the theme changed, or when the
-// window's active status changed.
-@protocol ThemedWindowDrawing
-
-// Called by the window controller when the theme changed.
-- (void)windowDidChangeTheme;
-
-// Called by the window controller when the window gained or lost main window
-// status.
-- (void)windowDidChangeActive;
-
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_THEMED_WINDOW_H_
diff --git a/chrome/browser/ui/cocoa/themed_window.mm b/chrome/browser/ui/cocoa/themed_window.mm
deleted file mode 100644
index 408b2bf..0000000
--- a/chrome/browser/ui/cocoa/themed_window.mm
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) 2010 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.
-
-#import "chrome/browser/ui/cocoa/themed_window.h"
-
-// Default implementations; used mostly for tests so that the hosting windows
-// don't needs to know about the theming machinery.
-@implementation NSWindow (ThemeProvider)
-
-- (const ThemeProvider*)themeProvider {
-  return NULL;
-}
-
-- (ThemedWindowStyle)themedWindowStyle {
-  return THEMED_NORMAL;
-}
-
-- (NSPoint)themeImagePositionForAlignment:(ThemeImageAlignment)alignment {
-  return NSZeroPoint;
-}
-
-- (BOOL)inIncognitoMode {
-  return NO;
-}
-
-- (BOOL)inIncognitoModeWithSystemTheme {
-  return NO;
-}
-
-- (BOOL)hasDarkTheme {
-  return NO;
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.h b/chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.h
index 622cd75..7619b86d 100644
--- a/chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.h
+++ b/chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.h
@@ -15,7 +15,6 @@
 @class BrowserWindowTouchBarController;
 @class CreditCardAutofillTouchBarController;
 @class TextSuggestionsTouchBarController;
-@class TabContentsController;
 
 namespace autofill {
 class AutofillPopupController;
diff --git a/chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.mm b/chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.mm
index 487f778..c3a3d23f 100644
--- a/chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.mm
+++ b/chrome/browser/ui/cocoa/touchbar/web_textfield_touch_bar_controller.mm
@@ -8,7 +8,6 @@
 #include "base/mac/scoped_nsobject.h"
 #include "base/mac/sdk_forward_declarations.h"
 #include "chrome/browser/ui/autofill/autofill_popup_controller.h"
-#import "chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h"
 #import "chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.h"
 #import "chrome/browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller.h"
 #import "chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller.h"
diff --git a/chrome/browser/ui/cocoa/view_resizer.h b/chrome/browser/ui/cocoa/view_resizer.h
deleted file mode 100644
index 98fc983..0000000
--- a/chrome/browser/ui/cocoa/view_resizer.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2012 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 CHROME_BROWSER_UI_COCOA_VIEW_RESIZER_H_
-#define CHROME_BROWSER_UI_COCOA_VIEW_RESIZER_H_
-
-#import <Foundation/Foundation.h>
-
-@class NSView;
-
-// Defines a protocol that allows controllers to delegate resizing their views
-// to their parents.  When a controller needs to change a view's height, rather
-// than resizing it directly, it sends a message to its parent asking the parent
-// to perform the resize.  This allows the parent to do any re-layout that may
-// become necessary due to the resize.
-@protocol ViewResizer <NSObject>
-- (void)resizeView:(NSView*)view newHeight:(CGFloat)height;
-
-@optional
-// Optional method called when an animation is beginning or ending.  Resize
-// delegates can implement this method if they need to modify their behavior
-// while an animation is running.
-- (void)setAnimationInProgress:(BOOL)inProgress;
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_VIEW_RESIZER_H_
diff --git a/chrome/browser/ui/cocoa/view_resizer_pong.h b/chrome/browser/ui/cocoa/view_resizer_pong.h
deleted file mode 100644
index bfe07ff..0000000
--- a/chrome/browser/ui/cocoa/view_resizer_pong.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 2009 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 CHROME_BROWSER_UI_COCOA_VIEW_RESIZER_PONG_H_
-#define CHROME_BROWSER_UI_COCOA_VIEW_RESIZER_PONG_H_
-
-#import <Cocoa/Cocoa.h>
-
-#import "chrome/browser/ui/cocoa/view_resizer.h"
-
-@interface ViewResizerPong : NSObject<ViewResizer> {
- @private
-  CGFloat height_;
-}
-@property(nonatomic) CGFloat height;
-
-- (void)resizeView:(NSView*)view newHeight:(CGFloat)height;
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_VIEW_RESIZER_PONG_H_
diff --git a/chrome/browser/ui/cocoa/view_resizer_pong.mm b/chrome/browser/ui/cocoa/view_resizer_pong.mm
deleted file mode 100644
index f063dbff8..0000000
--- a/chrome/browser/ui/cocoa/view_resizer_pong.mm
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2009 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.
-
-#import <Cocoa/Cocoa.h>
-
-#import "chrome/browser/ui/cocoa/view_resizer_pong.h"
-
-@implementation ViewResizerPong
-
-@synthesize height = height_;
-
-- (void)resizeView:(NSView*)view newHeight:(CGFloat)height {
-  [self setHeight:height];
-
-  // Set the view's height and width, in case it uses that as important state.
-  [view setFrame:NSMakeRect(100, 50,
-                            NSWidth([[view superview] frame]) - 50, height)];
-}
-@end
diff --git a/chrome/browser/ui/content_settings/content_setting_media_menu_model.cc b/chrome/browser/ui/content_settings/content_setting_media_menu_model.cc
deleted file mode 100644
index 4ff676d..0000000
--- a/chrome/browser/ui/content_settings/content_setting_media_menu_model.cc
+++ /dev/null
@@ -1,56 +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 "chrome/browser/ui/content_settings/content_setting_media_menu_model.h"
-
-#include <stddef.h>
-
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
-#include "chrome/browser/ui/content_settings/content_setting_bubble_model.h"
-
-ContentSettingMediaMenuModel::ContentSettingMediaMenuModel(
-    content::MediaStreamType type,
-    ContentSettingBubbleModel* bubble_model,
-    const MenuLabelChangedCallback& callback)
-    : ui::SimpleMenuModel(this),
-      type_(type),
-      media_bubble_model_(bubble_model),
-      callback_(callback) {
-  DCHECK(type_ == content::MEDIA_DEVICE_AUDIO_CAPTURE ||
-         type_ == content::MEDIA_DEVICE_VIDEO_CAPTURE);
-  DCHECK(media_bubble_model_->AsMediaStreamBubbleModel());
-  MediaCaptureDevicesDispatcher* dispatcher =
-      MediaCaptureDevicesDispatcher::GetInstance();
-  const content::MediaStreamDevices& devices =
-      (type_ == content::MEDIA_DEVICE_AUDIO_CAPTURE) ?
-          dispatcher->GetAudioCaptureDevices() :
-          dispatcher->GetVideoCaptureDevices();
-
-  for (size_t i = 0; i < devices.size(); ++i) {
-    commands_.insert(std::make_pair(commands_.size(), devices[i]));
-    AddItem(i, base::UTF8ToUTF16(devices[i].name));
-  }
-}
-
-ContentSettingMediaMenuModel::~ContentSettingMediaMenuModel() {
-}
-
-bool ContentSettingMediaMenuModel::IsCommandIdChecked(int command_id) const {
-  return false;
-}
-
-bool ContentSettingMediaMenuModel::IsCommandIdEnabled(int command_id) const {
-  return true;
-}
-
-void ContentSettingMediaMenuModel::ExecuteCommand(int command_id,
-                                                  int event_flags) {
-  CommandMap::const_iterator it = commands_.find(command_id);
-  DCHECK(it != commands_.end());
-  media_bubble_model_->OnMediaMenuClicked(type_, it->second.id);
-
-  if (!callback_.is_null())
-    callback_.Run(type_, it->second.name);
-}
diff --git a/chrome/browser/ui/content_settings/content_setting_media_menu_model.h b/chrome/browser/ui/content_settings/content_setting_media_menu_model.h
deleted file mode 100644
index e0ef9a8..0000000
--- a/chrome/browser/ui/content_settings/content_setting_media_menu_model.h
+++ /dev/null
@@ -1,50 +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 CHROME_BROWSER_UI_CONTENT_SETTINGS_CONTENT_SETTING_MEDIA_MENU_MODEL_H_
-#define CHROME_BROWSER_UI_CONTENT_SETTINGS_CONTENT_SETTING_MEDIA_MENU_MODEL_H_
-
-#include <map>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "content/public/common/media_stream_request.h"
-#include "ui/base/models/simple_menu_model.h"
-
-class ContentSettingBubbleModel;
-
-// A menu model that builds the contents of the media capture devices menu in
-// the content setting bubble.
-// DEPRECATED: only used on OSX. Port OSX to
-// ContentSettingBubbleContents::MediaComboboxModel. See crbug.com/590850
-class ContentSettingMediaMenuModel : public ui::SimpleMenuModel,
-                                     public ui::SimpleMenuModel::Delegate {
- public:
-  // Callback to update the label of the menu in the UI.
-  typedef base::Callback<void(content::MediaStreamType, const std::string&)>
-      MenuLabelChangedCallback;
-
-  ContentSettingMediaMenuModel(
-      content::MediaStreamType type,
-      ContentSettingBubbleModel* bubble_model,
-      const MenuLabelChangedCallback& callback);
-  ~ContentSettingMediaMenuModel() override;
-
-  // ui::SimpleMenuModel::Delegate:
-  bool IsCommandIdChecked(int command_id) const override;
-  bool IsCommandIdEnabled(int command_id) const override;
-  void ExecuteCommand(int command_id, int event_flags) override;
-
- private:
-  typedef std::map<int, content::MediaStreamDevice> CommandMap;
-
-  content::MediaStreamType type_;
-  ContentSettingBubbleModel* media_bubble_model_;  // Weak.
-  MenuLabelChangedCallback callback_;
-  CommandMap commands_;
-
-  DISALLOW_COPY_AND_ASSIGN(ContentSettingMediaMenuModel);
-};
-
-#endif  // CHROME_BROWSER_UI_CONTENT_SETTINGS_CONTENT_SETTING_MEDIA_MENU_MODEL_H_
diff --git a/chrome/browser/ui/passwords/manage_passwords_icon.cc b/chrome/browser/ui/passwords/manage_passwords_icon.cc
deleted file mode 100644
index 5d400380..0000000
--- a/chrome/browser/ui/passwords/manage_passwords_icon.cc
+++ /dev/null
@@ -1,37 +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 "chrome/browser/ui/passwords/manage_passwords_icon.h"
-
-#include "chrome/grit/generated_resources.h"
-#include "chrome/grit/theme_resources.h"
-
-ManagePasswordsIcon::ManagePasswordsIcon()
-    : tooltip_text_id_(0), state_(password_manager::ui::INACTIVE_STATE) {}
-
-ManagePasswordsIcon::~ManagePasswordsIcon() {
-}
-
-void ManagePasswordsIcon::SetState(password_manager::ui::State state) {
-  if (state_ == state)
-    return;
-  OnChangingState();
-  state_ = state;
-  UpdateIDs();
-  UpdateVisibleUI();
-}
-
-void ManagePasswordsIcon::UpdateIDs() {
-  // If the icon is inactive: clear out its image and tooltip and exit early.
-  if (state() == password_manager::ui::INACTIVE_STATE) {
-    tooltip_text_id_ = 0;
-    return;
-  }
-
-  // Otherwise, start with the correct values for MANAGE_STATE, and adjust
-  // things accordingly if we're in PENDING_STATE.
-  tooltip_text_id_ = IDS_PASSWORD_MANAGER_TOOLTIP_MANAGE;
-  if (state() == password_manager::ui::PENDING_PASSWORD_STATE)
-    tooltip_text_id_ = IDS_PASSWORD_MANAGER_TOOLTIP_SAVE;
-}
diff --git a/chrome/browser/ui/passwords/manage_passwords_icon.h b/chrome/browser/ui/passwords/manage_passwords_icon.h
deleted file mode 100644
index 67edec2..0000000
--- a/chrome/browser/ui/passwords/manage_passwords_icon.h
+++ /dev/null
@@ -1,45 +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 CHROME_BROWSER_UI_PASSWORDS_MANAGE_PASSWORDS_ICON_H_
-#define CHROME_BROWSER_UI_PASSWORDS_MANAGE_PASSWORDS_ICON_H_
-
-#include "base/macros.h"
-#include "chrome/browser/ui/passwords/manage_passwords_icon_view.h"
-#include "components/password_manager/core/common/password_manager_ui.h"
-
-// Base class for platform-specific password management icon views.
-// TODO(estade): remove this class from Cocoa as it has been from Views.
-class ManagePasswordsIcon : public ManagePasswordsIconView {
- public:
-  // Get/set the icon's state. Implementations of this class must implement
-  // SetStateInternal to do reasonable platform-specific things to represent
-  // the icon's state to the user.
-  void SetState(password_manager::ui::State state) override;
-  password_manager::ui::State state() const { return state_; }
-
- protected:
-  // The ID of the text resource that is currently displayed.
-  int tooltip_text_id_;
-
-  ManagePasswordsIcon();
-  ~ManagePasswordsIcon();
-
-  // Called from SetState() and SetActive() in order to do whatever
-  // platform-specific UI work is necessary.
-  virtual void UpdateVisibleUI() = 0;
-
-  // Called from SetState() iff the icon's state has changed.
-  virtual void OnChangingState() = 0;
-
- private:
-  // Updates the resource IDs in response to state changes.
-  void UpdateIDs();
-
-  password_manager::ui::State state_;
-
-  DISALLOW_COPY_AND_ASSIGN(ManagePasswordsIcon);
-};
-
-#endif  // CHROME_BROWSER_UI_PASSWORDS_MANAGE_PASSWORDS_ICON_H_
diff --git a/chrome/browser/ui/views/certificate_viewer_win.cc b/chrome/browser/ui/views/certificate_viewer_win.cc
index 891d99ce..7c9d18c 100644
--- a/chrome/browser/ui/views/certificate_viewer_win.cc
+++ b/chrome/browser/ui/views/certificate_viewer_win.cc
@@ -41,7 +41,7 @@
     }
 
     RunState run_state = BeginRun(parent);
-    run_state.dialog_thread->task_runner()->PostTaskAndReply(
+    run_state.dialog_task_runner->PostTaskAndReply(
         FROM_HERE,
         base::Bind(&CertificateViewerDialog::ShowOnDialogThread,
                    base::Unretained(this), run_state,
diff --git a/chrome/browser/ui/views/color_chooser_dialog.cc b/chrome/browser/ui/views/color_chooser_dialog.cc
index 3b2cdb9..8fa13955 100644
--- a/chrome/browser/ui/views/color_chooser_dialog.cc
+++ b/chrome/browser/ui/views/color_chooser_dialog.cc
@@ -39,7 +39,7 @@
   HWND owning_hwnd = views::HWNDForNativeWindow(owning_window);
   ExecuteOpenParams execute_params(initial_color, BeginRun(owning_hwnd),
                                    owning_hwnd);
-  execute_params.run_state.dialog_thread->task_runner()->PostTask(
+  execute_params.run_state.dialog_task_runner->PostTask(
       FROM_HERE,
       base::Bind(&ColorChooserDialog::ExecuteOpen, this, execute_params));
 }
diff --git a/chrome/browser/ui/views/media_router/presentation_receiver_window_view.cc b/chrome/browser/ui/views/media_router/presentation_receiver_window_view.cc
index 1d88947..7fe04b7 100644
--- a/chrome/browser/ui/views/media_router/presentation_receiver_window_view.cc
+++ b/chrome/browser/ui/views/media_router/presentation_receiver_window_view.cc
@@ -43,8 +43,12 @@
 #if defined(OS_CHROMEOS)
 #include "ash/public/cpp/window_properties.h"
 #include "ash/public/interfaces/window_state_type.mojom.h"
+#include "base/callback.h"
+#include "base/scoped_observer.h"
+#include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_observer.h"
+#include "ui/base/ui_base_features.h"
 #include "ui/gfx/native_widget_types.h"
 #endif
 
@@ -54,79 +58,45 @@
 // Observes the NativeWindow hosting the receiver view to look for fullscreen
 // state changes.  This helps monitor fullscreen changes that don't go through
 // the normal key accelerator to display and hide the location bar.
-class PresentationReceiverWindowView::FullscreenWindowObserver final
-    : public aura::WindowObserver {
+class FullscreenWindowObserver : public aura::WindowObserver {
  public:
-  explicit FullscreenWindowObserver(
-      PresentationReceiverWindowView* presentation_receiver_window_view);
-  ~FullscreenWindowObserver() final;
+  FullscreenWindowObserver(aura::Window* observed_window,
+                           base::RepeatingClosure on_fullscreen_change)
+      : on_fullscreen_change_(on_fullscreen_change) {
+    if (features::IsUsingWindowService())
+      observed_window = observed_window->GetRootWindow();
+    observed_window_.Add(observed_window);
+  }
+
+  ~FullscreenWindowObserver() override = default;
 
  private:
   // aura::WindowObserver overrides.
   void OnWindowPropertyChanged(aura::Window* window,
                                const void* key,
-                               intptr_t old) final;
-  void OnWindowDestroying(aura::Window* window) final;
+                               intptr_t old) override {
+    if (key == aura::client::kShowStateKey) {
+      ui::WindowShowState new_state =
+          window->GetProperty(aura::client::kShowStateKey);
+      ui::WindowShowState old_state = static_cast<ui::WindowShowState>(old);
+      if (old_state == ui::SHOW_STATE_FULLSCREEN ||
+          new_state == ui::SHOW_STATE_FULLSCREEN) {
+        on_fullscreen_change_.Run();
+      }
+    }
+  }
 
-  PresentationReceiverWindowView* const presentation_receiver_window_view_;
+  void OnWindowDestroying(aura::Window* window) override {
+    observed_window_.Remove(window);
+  }
+
+  base::RepeatingClosure on_fullscreen_change_;
+
+  ScopedObserver<aura::Window, aura::WindowObserver> observed_window_{this};
 
   DISALLOW_COPY_AND_ASSIGN(FullscreenWindowObserver);
 };
 
-PresentationReceiverWindowView::FullscreenWindowObserver::
-    FullscreenWindowObserver(
-        PresentationReceiverWindowView* presentation_receiver_window_view)
-    : presentation_receiver_window_view_(presentation_receiver_window_view) {
-  DCHECK(presentation_receiver_window_view);
-  DCHECK(presentation_receiver_window_view->GetWidget());
-  DCHECK(presentation_receiver_window_view->GetWidget()->GetNativeWindow());
-  presentation_receiver_window_view_->GetWidget()
-      ->GetNativeWindow()
-      ->AddObserver(this);
-}
-
-PresentationReceiverWindowView::FullscreenWindowObserver::
-    ~FullscreenWindowObserver() = default;
-
-void PresentationReceiverWindowView::FullscreenWindowObserver::
-    OnWindowPropertyChanged(aura::Window* window,
-                            const void* key,
-                            intptr_t old) {
-  DCHECK(presentation_receiver_window_view_->GetWidget());
-  DCHECK(window ==
-         presentation_receiver_window_view_->GetWidget()->GetNativeWindow());
-  if (key == ash::kWindowStateTypeKey) {
-    ash::mojom::WindowStateType new_state =
-        window->GetProperty(ash::kWindowStateTypeKey);
-    ash::mojom::WindowStateType old_state(
-        static_cast<ash::mojom::WindowStateType>(old));
-
-    // Toggle fullscreen when the user toggles fullscreen without going through
-    // FullscreenController::ToggleBrowserFullscreenMode(). This is the case if
-    // the user uses a hardware window state toggle button.
-    if (new_state != ash::mojom::WindowStateType::FULLSCREEN &&
-        new_state != ash::mojom::WindowStateType::PINNED &&
-        new_state != ash::mojom::WindowStateType::TRUSTED_PINNED &&
-        new_state != ash::mojom::WindowStateType::MINIMIZED &&
-        old_state == ash::mojom::WindowStateType::FULLSCREEN) {
-      presentation_receiver_window_view_->ExitFullscreen();
-    } else if (new_state == ash::mojom::WindowStateType::FULLSCREEN &&
-               old_state != ash::mojom::WindowStateType::PINNED &&
-               old_state != ash::mojom::WindowStateType::TRUSTED_PINNED) {
-      presentation_receiver_window_view_->EnterFullscreen();
-    }
-  }
-}
-
-void PresentationReceiverWindowView::FullscreenWindowObserver::
-    OnWindowDestroying(aura::Window* window) {
-  DCHECK(presentation_receiver_window_view_->GetWidget());
-  DCHECK(window ==
-         presentation_receiver_window_view_->GetWidget()->GetNativeWindow());
-  presentation_receiver_window_view_->GetWidget()
-      ->GetNativeWindow()
-      ->RemoveObserver(this);
-}
 #endif
 
 PresentationReceiverWindowView::PresentationReceiverWindowView(
@@ -209,7 +179,10 @@
   location_bar_view_->Init();
 
 #if defined(OS_CHROMEOS)
-  window_observer_ = std::make_unique<FullscreenWindowObserver>(this);
+  window_observer_ = std::make_unique<FullscreenWindowObserver>(
+      GetWidget()->GetNativeWindow(),
+      base::BindRepeating(&PresentationReceiverWindowView::OnFullscreenChanged,
+                          base::Unretained(this)));
 #endif
 }
 
@@ -313,18 +286,20 @@
 void PresentationReceiverWindowView::EnterFullscreen(
     const GURL& url,
     ExclusiveAccessBubbleType bubble_type) {
-  EnterFullscreen();
+  frame_->SetFullscreen(true);
+#if !defined(OS_CHROMEOS)
+  OnFullscreenChanged();
+#endif
   UpdateExclusiveAccessExitBubbleContent(url, bubble_type,
                                          ExclusiveAccessBubbleHideCallback(),
                                          /*force_update=*/false);
 }
 
 void PresentationReceiverWindowView::ExitFullscreen() {
-  exclusive_access_bubble_.reset();
-  location_bar_view_->SetVisible(true);
   frame_->SetFullscreen(false);
-  if (location_bar_view_->height() <= 0)
-    Layout();
+#if !defined(OS_CHROMEOS)
+  OnFullscreenChanged();
+#endif
 }
 
 void PresentationReceiverWindowView::UpdateExclusiveAccessExitBubbleContent(
@@ -433,9 +408,11 @@
   return true;
 }
 
-void PresentationReceiverWindowView::EnterFullscreen() {
-  location_bar_view_->SetVisible(false);
-  frame_->SetFullscreen(true);
-  if (location_bar_view_->height() > 0)
+void PresentationReceiverWindowView::OnFullscreenChanged() {
+  const bool fullscreen = IsFullscreen();
+  if (!fullscreen)
+    exclusive_access_bubble_.reset();
+  location_bar_view_->SetVisible(!fullscreen);
+  if (fullscreen == (location_bar_view_->height() > 0))
     Layout();
 }
diff --git a/chrome/browser/ui/views/media_router/presentation_receiver_window_view.h b/chrome/browser/ui/views/media_router/presentation_receiver_window_view.h
index c3c675a..9afd1e90 100644
--- a/chrome/browser/ui/views/media_router/presentation_receiver_window_view.h
+++ b/chrome/browser/ui/views/media_router/presentation_receiver_window_view.h
@@ -25,6 +25,10 @@
 class PresentationReceiverWindowFrame;
 class ToolbarModelImpl;
 
+#if defined(OS_CHROMEOS)
+class FullscreenWindowObserver;
+#endif
+
 // This class implements the View portion of PresentationReceiverWindow.  It
 // contains a WebView for displaying the receiver page and a LocationBarView for
 // displaying the URL.
@@ -46,7 +50,6 @@
 
   LocationBarView* location_bar_view() { return location_bar_view_; }
 
- private:
   // PresentationReceiverWindow overrides.
   void Close() final;
   bool IsWindowActive() const final;
@@ -114,7 +117,9 @@
   bool GetAcceleratorForCommandId(int command_id,
                                   ui::Accelerator* accelerator) const final;
 
-  void EnterFullscreen();
+ private:
+  // Updates the UI in response to a change to fullscreen state.
+  void OnFullscreenChanged();
 
   PresentationReceiverWindowFrame* const frame_;
   PresentationReceiverWindowDelegate* const delegate_;
@@ -127,7 +132,6 @@
   std::unique_ptr<ExclusiveAccessBubbleViews> exclusive_access_bubble_;
 
 #if defined(OS_CHROMEOS)
-  class FullscreenWindowObserver;
   std::unique_ptr<FullscreenWindowObserver> window_observer_;
 #endif
 
diff --git a/chrome/browser/ui/views/media_router/presentation_receiver_window_view_browsertest.cc b/chrome/browser/ui/views/media_router/presentation_receiver_window_view_browsertest.cc
index 752d260..e89d18f 100644
--- a/chrome/browser/ui/views/media_router/presentation_receiver_window_view_browsertest.cc
+++ b/chrome/browser/ui/views/media_router/presentation_receiver_window_view_browsertest.cc
@@ -95,7 +95,7 @@
   void TearDownOnMainThread() override {
     base::RunLoop run_loop;
     fake_delegate_->set_window_closed_callback(run_loop.QuitClosure());
-    static_cast<PresentationReceiverWindow*>(receiver_view_)->Close();
+    receiver_view_->Close();
     run_loop.Run();
     fake_delegate_.reset();
 
@@ -112,22 +112,14 @@
 #if defined(OS_CHROMEOS)
 IN_PROC_BROWSER_TEST_F(PresentationReceiverWindowViewBrowserTest,
                        ChromeOSHardwareFullscreenButton) {
-  static_cast<PresentationReceiverWindow*>(receiver_view_)
-      ->ShowInactiveFullscreen();
-  ASSERT_TRUE(
-      static_cast<ExclusiveAccessContext*>(receiver_view_)->IsFullscreen());
-  EXPECT_FALSE(receiver_view_->location_bar_view()->visible());
   // Bypass ExclusiveAccessContext and default accelerator to simulate hardware
   // window state button, which sets the native aura window to a "normal" state.
 
-  // This class checks the receiver view's fullscreen state when it's native
-  // aura::Window's bounds change.  It calls |fullscreen_callback| when the
-  // desired fullscreen state is seen, set via |await_type|.  It automatically
-  // registers and unregisters itself as an observer of the receiver view's
-  // aura::Window.  This is necessary because Mus only schedules the fullscreen
-  // change during SetProperty  and because the fullscreen change takes place in
-  // another process, we can't simply call base::RunLoop().RunUntilIdle().
-  class FullscreenWaiter final : public aura::WindowObserver {
+  // Waits for the PresentationReceiverWindowView to enter or exit fullscreen.
+  // It waits for the location bar visibility to change rather than simply using
+  // RunLoop::RunUntilIdle because in Mash, the fullscreen change takes place in
+  // another process.
+  class FullscreenWaiter final : public views::ViewObserver {
    public:
     enum class AwaitType {
       kOutOfFullscreen,
@@ -140,29 +132,18 @@
         : receiver_view_(receiver_view),
           await_type_(await_type),
           fullscreen_callback_(std::move(fullscreen_callback)) {
-      static_cast<views::View*>(receiver_view_)
-          ->GetWidget()
-          ->GetNativeWindow()
-          ->AddObserver(this);
+      receiver_view_->location_bar_view()->AddObserver(this);
     }
     ~FullscreenWaiter() final {
-      static_cast<views::View*>(receiver_view_)
-          ->GetWidget()
-          ->GetNativeWindow()
-          ->RemoveObserver(this);
+      receiver_view_->location_bar_view()->RemoveObserver(this);
     }
 
    private:
-    // aura::WindowObserver overrides.
-    void OnWindowBoundsChanged(aura::Window* window,
-                               const gfx::Rect& old_bounds,
-                               const gfx::Rect& new_bounds,
-                               ui::PropertyChangeReason reason) final {
-      DCHECK(fullscreen_callback_);
-      if (static_cast<ExclusiveAccessContext*>(receiver_view_)
-              ->IsFullscreen() == (await_type_ == AwaitType::kIntoFullscreen)) {
+    void OnViewVisibilityChanged(views::View* observed_view) override {
+      bool fullscreen = !observed_view->visible();
+      EXPECT_EQ(fullscreen, receiver_view_->IsFullscreen());
+      if (fullscreen == (await_type_ == AwaitType::kIntoFullscreen))
         std::move(fullscreen_callback_).Run();
-      }
     }
 
     PresentationReceiverWindowView* const receiver_view_;
@@ -171,18 +152,27 @@
 
     DISALLOW_COPY_AND_ASSIGN(FullscreenWaiter);
   };
-  auto* native_window =
-      static_cast<views::View*>(receiver_view_)->GetWidget()->GetNativeWindow();
+
+  {
+    base::RunLoop fullscreen_loop;
+    FullscreenWaiter waiter(receiver_view_,
+                            FullscreenWaiter::AwaitType::kIntoFullscreen,
+                            fullscreen_loop.QuitClosure());
+    receiver_view_->ShowInactiveFullscreen();
+    fullscreen_loop.Run();
+
+    ASSERT_TRUE(receiver_view_->IsFullscreen());
+    EXPECT_FALSE(receiver_view_->location_bar_view()->visible());
+  }
+
   {
     base::RunLoop fullscreen_loop;
     FullscreenWaiter waiter(receiver_view_,
                             FullscreenWaiter::AwaitType::kOutOfFullscreen,
                             fullscreen_loop.QuitClosure());
-    native_window->SetProperty(aura::client::kShowStateKey,
-                               ui::SHOW_STATE_NORMAL);
+    receiver_view_->GetWidget()->SetFullscreen(false);
     fullscreen_loop.Run();
-    ASSERT_FALSE(
-        static_cast<ExclusiveAccessContext*>(receiver_view_)->IsFullscreen());
+    ASSERT_FALSE(receiver_view_->IsFullscreen());
     EXPECT_TRUE(receiver_view_->location_bar_view()->visible());
   }
 
@@ -192,29 +182,11 @@
     FullscreenWaiter waiter(receiver_view_,
                             FullscreenWaiter::AwaitType::kIntoFullscreen,
                             fullscreen_loop.QuitClosure());
-    native_window->SetProperty(aura::client::kShowStateKey,
-                               ui::SHOW_STATE_FULLSCREEN);
+    receiver_view_->GetWidget()->SetFullscreen(true);
     fullscreen_loop.Run();
-    ASSERT_TRUE(
-        static_cast<ExclusiveAccessContext*>(receiver_view_)->IsFullscreen());
+    ASSERT_TRUE(receiver_view_->IsFullscreen());
     EXPECT_FALSE(receiver_view_->location_bar_view()->visible());
   }
-  static_cast<views::View*>(receiver_view_)
-      ->GetWidget()
-      ->GetNativeWindow()
-      ->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
-  ASSERT_FALSE(
-      static_cast<ExclusiveAccessContext*>(receiver_view_)->IsFullscreen());
-  EXPECT_TRUE(receiver_view_->location_bar_view()->visible());
-
-  // Back to fullscreen with the hardware button.
-  static_cast<views::View*>(receiver_view_)
-      ->GetWidget()
-      ->GetNativeWindow()
-      ->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
-  ASSERT_TRUE(
-      static_cast<ExclusiveAccessContext*>(receiver_view_)->IsFullscreen());
-  EXPECT_FALSE(receiver_view_->location_bar_view()->visible());
 }
 #endif
 
@@ -227,11 +199,9 @@
 
 IN_PROC_BROWSER_TEST_F(PresentationReceiverWindowViewBrowserTest,
                        MAYBE_LocationBarViewShown) {
-  static_cast<PresentationReceiverWindow*>(receiver_view_)
-      ->ShowInactiveFullscreen();
-  static_cast<ExclusiveAccessContext*>(receiver_view_)->ExitFullscreen();
-  ASSERT_FALSE(
-      static_cast<ExclusiveAccessContext*>(receiver_view_)->IsFullscreen());
+  receiver_view_->ShowInactiveFullscreen();
+  receiver_view_->ExitFullscreen();
+  ASSERT_FALSE(receiver_view_->IsFullscreen());
 
   auto* location_bar_view = receiver_view_->location_bar_view();
   EXPECT_TRUE(location_bar_view->IsDrawn());
@@ -253,11 +223,9 @@
   content::NavigationController::LoadURLParams load_params(GURL("about:blank"));
   fake_delegate_->web_contents()->GetController().LoadURLWithParams(
       load_params);
-  static_cast<PresentationReceiverWindow*>(receiver_view_)
-      ->ShowInactiveFullscreen();
-  static_cast<ExclusiveAccessContext*>(receiver_view_)->ExitFullscreen();
-  ASSERT_FALSE(
-      static_cast<ExclusiveAccessContext*>(receiver_view_)->IsFullscreen());
+  receiver_view_->ShowInactiveFullscreen();
+  receiver_view_->ExitFullscreen();
+  ASSERT_FALSE(receiver_view_->IsFullscreen());
 
   auto* location_icon_view =
       receiver_view_->location_bar_view()->location_icon_view();
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_icon_view_interactive_uitest.cc b/chrome/browser/ui/views/passwords/manage_passwords_icon_view_interactive_uitest.cc
index a57fd4b2..a6a6555 100644
--- a/chrome/browser/ui/views/passwords/manage_passwords_icon_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/passwords/manage_passwords_icon_view_interactive_uitest.cc
@@ -4,7 +4,6 @@
 
 #include "base/macros.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/passwords/manage_passwords_icon.h"
 #include "chrome/browser/ui/passwords/manage_passwords_test.h"
 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller_mock.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
diff --git a/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc b/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc
index 0024cb5..20215e2 100644
--- a/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc
+++ b/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc
@@ -21,6 +21,7 @@
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
+#include "net/base/url_util.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/image/image_skia.h"
@@ -241,7 +242,9 @@
   DCHECK(source == web_contents());
   // IsSslCertificateValid checks security_state::SecurityInfo.security_level
   // which reflects security state.
-  if (!SslValidityChecker::IsSslCertificateValid(source)) {
+  // Allow localhost for test.
+  if (!SslValidityChecker::IsSslCertificateValid(source) &&
+      !net::IsLocalhost(source->GetLastCommittedURL())) {
     WarnIfPossible(
         "Opened payment handler window's visible security state changed for "
         "url " +
@@ -289,11 +292,14 @@
        !navigation_handle->GetURL().IsAboutBlank()) ||
       !SslValidityChecker::IsSslCertificateValid(
           navigation_handle->GetWebContents())) {
-    WarnIfPossible(
-        "Opened payment handler window has an insecure navigation to url " +
-        navigation_handle->GetURL().spec());
-    AbortPayment();
-    return;
+    // Allow localhost for test.
+    if (!net::IsLocalhost(navigation_handle->GetURL())) {
+      WarnIfPossible(
+          "Opened payment handler window has an insecure navigation to url " +
+          navigation_handle->GetURL().spec());
+      AbortPayment();
+      return;
+    }
   }
 
   if (first_navigation_complete_callback_) {
diff --git a/chrome/browser/ui/webui/certificates_handler.cc b/chrome/browser/ui/webui/certificates_handler.cc
index 57ccbca..58f6be7 100644
--- a/chrome/browser/ui/webui/certificates_handler.cc
+++ b/chrome/browser/ui/webui/certificates_handler.cc
@@ -976,8 +976,10 @@
       certificate_manager_model_->is_user_db_available());
   base::Value tpm_available_value(
       certificate_manager_model_->is_tpm_available());
-  FireWebUIListener("certificates-model-ready", user_db_available_value,
-                    tpm_available_value);
+  if (IsJavascriptAllowed()) {
+    FireWebUIListener("certificates-model-ready", user_db_available_value,
+                      tpm_available_value);
+  }
   certificate_manager_model_->Refresh();
 }
 
@@ -1070,8 +1072,10 @@
   }
   std::sort(nodes.GetList().begin(), nodes.GetList().end(), comparator);
 
-  FireWebUIListener("certificates-changed", base::Value(tab_name),
-                    std::move(nodes));
+  if (IsJavascriptAllowed()) {
+    FireWebUIListener("certificates-changed", base::Value(tab_name),
+                      std::move(nodes));
+  }
 }
 
 void CertificatesHandler::ResolveCallback(const base::Value& response) {
diff --git a/chrome/browser/ui/webui/settings_utils_win.cc b/chrome/browser/ui/webui/settings_utils_win.cc
index 46a7ca8..5261c2d 100644
--- a/chrome/browser/ui/webui/settings_utils_win.cc
+++ b/chrome/browser/ui/webui/settings_utils_win.cc
@@ -42,9 +42,10 @@
     }
 
     RunState run_state = BeginRun(parent);
-    run_state.dialog_thread->task_runner()->PostTaskAndReply(
-        FROM_HERE, base::Bind(&ManageCertificatesDialog::ShowOnDialogThread,
-                              base::Unretained(this), run_state),
+    run_state.dialog_task_runner->PostTaskAndReply(
+        FROM_HERE,
+        base::Bind(&ManageCertificatesDialog::ShowOnDialogThread,
+                   base::Unretained(this), run_state),
         base::Bind(&ManageCertificatesDialog::OnDialogClosed,
                    base::Unretained(this), run_state, callback));
   }
diff --git a/chrome/browser/usb/usb_chooser_context.cc b/chrome/browser/usb/usb_chooser_context.cc
index 7c9f5ec..bc2d076 100644
--- a/chrome/browser/usb/usb_chooser_context.cc
+++ b/chrome/browser/usb/usb_chooser_context.cc
@@ -87,7 +87,10 @@
                          CONTENT_SETTINGS_TYPE_USB_CHOOSER_DATA),
       is_incognito_(profile->IsOffTheRecord()),
       client_binding_(this),
-      weak_factory_(this) {}
+      weak_factory_(this) {
+  usb_policy_allowed_devices_.reset(
+      new UsbPolicyAllowedDevices(profile->GetPrefs()));
+}
 
 void UsbChooserContext::EnsureConnectionWithDeviceManager() {
   if (device_manager_)
@@ -207,6 +210,11 @@
   if (UsbBlocklist::Get().IsExcluded(device_info))
     return false;
 
+  if (usb_policy_allowed_devices_->IsDeviceAllowed(
+          requesting_origin, embedding_origin, device_info)) {
+    return true;
+  }
+
   if (!CanRequestObjectPermission(requesting_origin, embedding_origin))
     return false;
 
diff --git a/chrome/browser/usb/usb_chooser_context.h b/chrome/browser/usb/usb_chooser_context.h
index ef0654f2..47629d4 100644
--- a/chrome/browser/usb/usb_chooser_context.h
+++ b/chrome/browser/usb/usb_chooser_context.h
@@ -16,6 +16,7 @@
 #include "base/observer_list.h"
 #include "base/values.h"
 #include "chrome/browser/permissions/chooser_context_base.h"
+#include "chrome/browser/usb/usb_policy_allowed_devices.h"
 #include "device/usb/mojo/device_manager_impl.h"
 #include "device/usb/public/mojom/device_manager.mojom.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
@@ -88,6 +89,8 @@
   std::map<std::pair<GURL, GURL>, std::set<std::string>> ephemeral_devices_;
   std::map<std::string, base::DictionaryValue> ephemeral_dicts_;
 
+  std::unique_ptr<UsbPolicyAllowedDevices> usb_policy_allowed_devices_;
+
   // TODO(donna.wu@intel.com): Have the Device Service own this instance in the
   // near future.
   std::unique_ptr<device::usb::DeviceManagerImpl> device_manager_instance_;
diff --git a/chrome/browser/usb/usb_chooser_context_unittest.cc b/chrome/browser/usb/usb_chooser_context_unittest.cc
index 20930b6..094d7302 100644
--- a/chrome/browser/usb/usb_chooser_context_unittest.cc
+++ b/chrome/browser/usb/usb_chooser_context_unittest.cc
@@ -4,12 +4,15 @@
 
 #include <vector>
 
+#include "base/json/json_reader.h"
 #include "base/run_loop.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/usb/usb_chooser_context.h"
 #include "chrome/browser/usb/usb_chooser_context_factory.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/content_settings/core/common/pref_names.h"
+#include "components/prefs/pref_service.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "device/base/mock_device_client.h"
 #include "device/usb/mock_usb_device.h"
@@ -338,3 +341,206 @@
   EXPECT_TRUE(store->HasDevicePermission(kBarOrigin, kBarOrigin,
                                          *ephemeral_device_info));
 }
+
+namespace {
+
+constexpr char kPolicySetting[] = R"(
+    [
+      {
+        "devices": [{ "vendor_id": 1234, "product_id": 5678 }],
+        "url_patterns": ["https://product.vendor.com"]
+      }, {
+        "devices": [{ "vendor_id": 1234 }],
+        "url_patterns": ["https://vendor.com"]
+      }, {
+        "devices": [{}],
+        "url_patterns": ["https://[*.]anydevice.com"]
+      }, {
+        "devices": [{ "vendor_id": 2468, "product_id": 1357 }],
+        "url_patterns": ["https://gadget.com,https://cool.com"]
+      }
+    ])";
+
+const GURL kPolicyOrigins[] = {
+    GURL("https://product.vendor.com"), GURL("https://vendor.com"),
+    GURL("https://anydevice.com"),      GURL("https://sub.anydevice.com"),
+    GURL("https://gadget.com"),         GURL("https://cool.com")};
+
+void ExpectNoPermissions(UsbChooserContext* store,
+                         const device::mojom::UsbDeviceInfo& device_info) {
+  for (const auto& kRequestingOrigin : kPolicyOrigins) {
+    for (const auto& kEmbeddingOrigin : kPolicyOrigins) {
+      EXPECT_FALSE(store->HasDevicePermission(kRequestingOrigin,
+                                              kEmbeddingOrigin, device_info));
+    }
+  }
+}
+
+void ExpectCorrectPermissions(
+    UsbChooserContext* store,
+    const std::vector<GURL>& kValidRequestingOrigins,
+    const std::vector<GURL>& kInvalidRequestingOrigins,
+    const device::mojom::UsbDeviceInfo& device_info) {
+  // Ensure that only |kValidRequestingOrigin| as the requesting origin has
+  // permission to access the device described by |device_info|.
+  for (const auto& kEmbeddingOrigin : kPolicyOrigins) {
+    for (const auto& kValidRequestingOrigin : kValidRequestingOrigins) {
+      EXPECT_TRUE(store->HasDevicePermission(kValidRequestingOrigin,
+                                             kEmbeddingOrigin, device_info));
+    }
+
+    for (const auto& kInvalidRequestingOrigin : kInvalidRequestingOrigins) {
+      EXPECT_FALSE(store->HasDevicePermission(kInvalidRequestingOrigin,
+                                              kEmbeddingOrigin, device_info));
+    }
+  }
+}
+
+}  // namespace
+
+TEST_F(UsbChooserContextTest,
+       UsbAllowDevicesForUrlsPermissionForSpecificDevice) {
+  const std::vector<GURL> kValidRequestingOrigins = {
+      GURL("https://product.vendor.com"), GURL("https://vendor.com"),
+      GURL("https://sub.anydevice.com"), GURL("https://anydevice.com")};
+  const std::vector<GURL> kInvalidRequestingOrigins = {
+      GURL("https://gadget.com"), GURL("https://cool.com")};
+
+  auto* store = UsbChooserContextFactory::GetForProfile(profile());
+
+  scoped_refptr<UsbDevice> specific_device =
+      base::MakeRefCounted<MockUsbDevice>(1234, 5678, "Google", "Gizmo",
+                                          "ABC123");
+
+  auto specific_device_info =
+      device::mojom::UsbDeviceInfo::From(*specific_device);
+  DCHECK(specific_device_info);
+
+  ExpectNoPermissions(store, *specific_device_info);
+
+  profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls,
+                             *base::JSONReader::Read(kPolicySetting));
+
+  ExpectCorrectPermissions(store, kValidRequestingOrigins,
+                           kInvalidRequestingOrigins, *specific_device_info);
+}
+
+TEST_F(UsbChooserContextTest,
+       UsbAllowDevicesForUrlsPermissionForVendorRelatedDevice) {
+  const std::vector<GURL> kValidRequestingOrigins = {
+      GURL("https://vendor.com"), GURL("https://sub.anydevice.com"),
+      GURL("https://anydevice.com")};
+  const std::vector<GURL> kInvalidRequestingOrigins = {
+      GURL("https://product.vendor.com"), GURL("https://gadget.com"),
+      GURL("https://cool.com")};
+
+  auto* store = UsbChooserContextFactory::GetForProfile(profile());
+
+  scoped_refptr<UsbDevice> vendor_related_device =
+      base::MakeRefCounted<MockUsbDevice>(1234, 8765, "Google", "Widget",
+                                          "XYZ987");
+
+  auto vendor_related_device_info =
+      device::mojom::UsbDeviceInfo::From(*vendor_related_device);
+  DCHECK(vendor_related_device_info);
+
+  ExpectNoPermissions(store, *vendor_related_device_info);
+
+  profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls,
+                             *base::JSONReader::Read(kPolicySetting));
+
+  ExpectCorrectPermissions(store, kValidRequestingOrigins,
+                           kInvalidRequestingOrigins,
+                           *vendor_related_device_info);
+}
+
+TEST_F(UsbChooserContextTest,
+       UsbAllowDevicesForUrlsPermissionForUnrelatedDevice) {
+  const std::vector<GURL> kValidRequestingOrigins = {
+      GURL("https://sub.anydevice.com"), GURL("https://anydevice.com")};
+  const std::vector<GURL> kInvalidRequestingOrigins = {
+      GURL("https://product.vendor.com"), GURL("https://vendor.com"),
+      GURL("https://cool.com")};
+  const GURL kGadgetOrigin("https://gadget.com");
+  const GURL& kCoolOrigin = kInvalidRequestingOrigins[2];
+
+  auto* store = UsbChooserContextFactory::GetForProfile(profile());
+
+  scoped_refptr<UsbDevice> unrelated_device =
+      base::MakeRefCounted<MockUsbDevice>(2468, 1357, "Cool", "Gadget",
+                                          "4W350M3");
+
+  auto unrelated_device_info =
+      device::mojom::UsbDeviceInfo::From(*unrelated_device);
+  DCHECK(unrelated_device_info);
+
+  ExpectNoPermissions(store, *unrelated_device_info);
+
+  profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls,
+                             *base::JSONReader::Read(kPolicySetting));
+
+  EXPECT_TRUE(store->HasDevicePermission(kGadgetOrigin, kCoolOrigin,
+                                         *unrelated_device_info));
+  for (const auto& kEmbeddingOrigin : kPolicyOrigins) {
+    if (kEmbeddingOrigin != kCoolOrigin) {
+      EXPECT_FALSE(store->HasDevicePermission(kGadgetOrigin, kEmbeddingOrigin,
+                                              *unrelated_device_info));
+    }
+  }
+  ExpectCorrectPermissions(store, kValidRequestingOrigins,
+                           kInvalidRequestingOrigins, *unrelated_device_info);
+}
+
+TEST_F(UsbChooserContextTest,
+       UsbAllowDevicesForUrlsPermissionOverrulesUsbGuardPermission) {
+  const GURL kProductVendorOrigin("https://product.vendor.com");
+  const GURL kGadgetOrigin("https://gadget.com");
+  const GURL kCoolOrigin("https://cool.com");
+
+  auto* store = UsbChooserContextFactory::GetForProfile(profile());
+
+  scoped_refptr<UsbDevice> specific_device =
+      base::MakeRefCounted<MockUsbDevice>(1234, 5678, "Google", "Gizmo",
+                                          "ABC123");
+  scoped_refptr<UsbDevice> unrelated_device =
+      base::MakeRefCounted<MockUsbDevice>(2468, 1357, "Cool", "Gadget",
+                                          "4W350M3");
+
+  auto specific_device_info =
+      device::mojom::UsbDeviceInfo::From(*specific_device);
+  auto unrelated_device_info =
+      device::mojom::UsbDeviceInfo::From(*unrelated_device);
+  DCHECK(specific_device_info);
+  DCHECK(unrelated_device_info);
+
+  ExpectNoPermissions(store, *specific_device_info);
+  ExpectNoPermissions(store, *unrelated_device_info);
+
+  auto* map = HostContentSettingsMapFactory::GetForProfile(profile());
+  map->SetContentSettingDefaultScope(kProductVendorOrigin, kProductVendorOrigin,
+                                     CONTENT_SETTINGS_TYPE_USB_GUARD,
+                                     std::string(), CONTENT_SETTING_BLOCK);
+  map->SetContentSettingDefaultScope(kGadgetOrigin, kCoolOrigin,
+                                     CONTENT_SETTINGS_TYPE_USB_GUARD,
+                                     std::string(), CONTENT_SETTING_BLOCK);
+  EXPECT_FALSE(store->HasDevicePermission(
+      kProductVendorOrigin, kProductVendorOrigin, *specific_device_info));
+  EXPECT_FALSE(store->HasDevicePermission(
+      kProductVendorOrigin, kProductVendorOrigin, *unrelated_device_info));
+  EXPECT_FALSE(store->HasDevicePermission(kGadgetOrigin, kCoolOrigin,
+                                          *specific_device_info));
+  EXPECT_FALSE(store->HasDevicePermission(kGadgetOrigin, kCoolOrigin,
+                                          *unrelated_device_info));
+
+  profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls,
+                             *base::JSONReader::Read(kPolicySetting));
+
+  EXPECT_TRUE(store->HasDevicePermission(
+      kProductVendorOrigin, kProductVendorOrigin, *specific_device_info));
+  EXPECT_FALSE(store->HasDevicePermission(
+      kProductVendorOrigin, kProductVendorOrigin, *unrelated_device_info));
+  EXPECT_FALSE(store->HasDevicePermission(kGadgetOrigin, kCoolOrigin,
+                                          *specific_device_info));
+  EXPECT_TRUE(store->HasDevicePermission(kGadgetOrigin, kCoolOrigin,
+                                         *unrelated_device_info));
+}
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json
index 895aa3a..6228be0 100644
--- a/chrome/common/extensions/api/_api_features.json
+++ b/chrome/common/extensions/api/_api_features.json
@@ -698,10 +698,6 @@
     "dependencies": ["permission:signedInDevices"],
     "contexts": ["blessed_extension"]
   },
-  "streamsPrivate": {
-    "dependencies": ["permission:streamsPrivate"],
-    "contexts": ["blessed_extension"]
-  },
   "syncFileSystem": {
     "dependencies": ["permission:syncFileSystem"],
     "contexts": ["blessed_extension"]
diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json
index 4c419358..fb7f4912 100644
--- a/chrome/common/extensions/api/_permission_features.json
+++ b/chrome/common/extensions/api/_permission_features.json
@@ -729,18 +729,6 @@
     "channel": "dev",
     "extension_types": ["extension", "legacy_packaged_app", "platform_app"]
   },
-  "streamsPrivate": {
-    "channel": "stable",
-    "extension_types": ["extension", "legacy_packaged_app", "platform_app"],
-    "whitelist": [
-      "787000072C6FBB934AF5A42275CDE73FC977D995",  // browser_tests
-      "2FC374607C2DF285634B67C64A2E356C607091C3",  // QuickOffice
-      "5D3851BEFF680AB6D954B76678EFCCE834465C23",  // QuickOffice Dev
-      "12E618C3C6E97495AAECF2AC12DEB082353241C6",  // QO component extension
-      "3727DD3E564B6055387425027AD74C58784ACC15",  // Editor
-      "CBCC42ABED43A4B58FE3810E62AFFA010EB0349F"   // PDF
-    ]
-  },
   "syncFileSystem": {
     "channel": "stable",
     "extension_types": ["platform_app"]
diff --git a/chrome/common/extensions/api/api_sources.gni b/chrome/common/extensions/api/api_sources.gni
index 0e6f9be8..b0a5e5a0 100644
--- a/chrome/common/extensions/api/api_sources.gni
+++ b/chrome/common/extensions/api/api_sources.gni
@@ -59,7 +59,6 @@
   "sessions.json",
   "settings_private.idl",
   "signed_in_devices.idl",
-  "streams_private.idl",
   "sync_file_system.idl",
   "system_indicator.idl",
   "system_private.json",
diff --git a/chrome/common/extensions/api/streams_private.idl b/chrome/common/extensions/api/streams_private.idl
deleted file mode 100644
index ed24130..0000000
--- a/chrome/common/extensions/api/streams_private.idl
+++ /dev/null
@@ -1,57 +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.
-
-// Streams Private API.
-namespace streamsPrivate {
-  dictionary StreamInfo {
-    // The MIME type of the intercepted URL request.
-    DOMString mimeType;
-
-    // The original URL that was intercepted.
-    DOMString originalUrl;
-
-    // The URL that the stream can be read from.
-    DOMString streamUrl;
-
-    // The ID of the tab that opened the stream. If the stream is not opened in
-    // a tab, it will be -1.
-    long tabId;
-
-    // The ID of the view that will render the stream, if the viewer was opened
-    // in a plugin.
-    DOMString? viewId;
-
-    // The amount of data the Stream should contain, if known.  If there is no
-    // information on the size it will be -1.
-    long expectedContentSize;
-
-    // The HTTP response headers of the intercepted request stored as a
-    // dictionary mapping header name to header value. If a header name appears
-    // multiple times, the header values are merged in the dictionary and
-    // separated by a ", ".
-    object responseHeaders;
-
-    // Whether the stream is embedded within another document.
-    boolean embedded;
-  };
-
-  callback AbortCallback = void ();
-
-  interface Functions {
-    // Abort the URL request on the given stream.
-    // |streamUrl| : The URL of the stream to abort.
-    // |callback| : Called when the stream URL is guaranteed to be invalid. The
-    // underlying URL request may not yet have been aborted when this is run.
-    static void abort(DOMString streamUrl,
-                      optional AbortCallback callback);
-  };
-
-  interface Events {
-    // Fired when a resource is fetched which matches a mime type handled by
-    // this extension. The resource request is cancelled, and the extension is
-    // expected to handle the request. The event is restricted to a small number
-    // of white-listed extensions.
-    static void onExecuteMimeTypeHandler(StreamInfo streamInfo);
-  };
-};
diff --git a/chrome/common/extensions/permissions/chrome_api_permissions.cc b/chrome/common/extensions/permissions/chrome_api_permissions.cc
index b0398fd..216f83c3 100644
--- a/chrome/common/extensions/permissions/chrome_api_permissions.cc
+++ b/chrome/common/extensions/permissions/chrome_api_permissions.cc
@@ -147,8 +147,6 @@
      APIPermissionInfo::kFlagCannotBeOptional},
     {APIPermission::kWebstorePrivate, "webstorePrivate",
      APIPermissionInfo::kFlagCannotBeOptional},
-    {APIPermission::kStreamsPrivate, "streamsPrivate",
-     APIPermissionInfo::kFlagCannotBeOptional},
     {APIPermission::kEnterprisePlatformKeysPrivate,
      "enterprise.platformKeysPrivate",
      APIPermissionInfo::kFlagCannotBeOptional},
diff --git a/chrome/common/extensions/permissions/permission_set_unittest.cc b/chrome/common/extensions/permissions/permission_set_unittest.cc
index d0a0cb6..aab8362 100644
--- a/chrome/common/extensions/permissions/permission_set_unittest.cc
+++ b/chrome/common/extensions/permissions/permission_set_unittest.cc
@@ -857,7 +857,6 @@
   skip.insert(APIPermission::kResourcesPrivate);
   skip.insert(APIPermission::kRtcPrivate);
   skip.insert(APIPermission::kSafeBrowsingPrivate);
-  skip.insert(APIPermission::kStreamsPrivate);
   skip.insert(APIPermission::kSystemPrivate);
   skip.insert(APIPermission::kTabCaptureForTab);
   skip.insert(APIPermission::kTerminalPrivate);
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index b47c006..e0eb419 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1291,7 +1291,6 @@
         "../browser/extensions/api/settings_private/settings_private_apitest.cc",
         "../browser/extensions/api/socket/socket_apitest.cc",
         "../browser/extensions/api/storage/settings_apitest.cc",
-        "../browser/extensions/api/streams_private/streams_private_apitest.cc",
         "../browser/extensions/api/sync_file_system/sync_file_system_apitest.cc",
         "../browser/extensions/api/sync_file_system/sync_file_system_browsertest.cc",
         "../browser/extensions/api/system_indicator/system_indicator_apitest.cc",
@@ -4121,15 +4120,11 @@
       cocoa_test_sources = [
         "../browser/ui/cocoa/bookmarks/bookmark_menu_bridge_unittest.mm",
         "../browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller_unittest.mm",
-        "../browser/ui/cocoa/browser_window_utils_unittest.mm",
-        "../browser/ui/cocoa/chrome_browser_window_unittest.mm",
         "../browser/ui/cocoa/color_panel_cocoa_unittest.mm",
         "../browser/ui/cocoa/confirm_quit_panel_controller_unittest.mm",
-        "../browser/ui/cocoa/constrained_window/constrained_window_custom_window_unittest.mm",
         "../browser/ui/cocoa/constrained_window/constrained_window_sheet_controller_unittest.mm",
         "../browser/ui/cocoa/find_pasteboard_unittest.mm",
         "../browser/ui/cocoa/first_run_dialog_controller_unittest.mm",
-        "../browser/ui/cocoa/framed_browser_window_unittest.mm",
         "../browser/ui/cocoa/history_menu_bridge_unittest.mm",
         "../browser/ui/cocoa/history_menu_cocoa_controller_unittest.mm",
         "../browser/ui/cocoa/history_overlay_controller_unittest.mm",
@@ -4141,7 +4136,6 @@
         "../browser/ui/cocoa/profiles/profile_menu_controller_unittest.mm",
         "../browser/ui/cocoa/scoped_menu_bar_lock_unittest.mm",
         "../browser/ui/cocoa/status_icons/status_icon_mac_unittest.mm",
-        "../browser/ui/cocoa/tabbed_browser_window_unittest.mm",
         "../browser/ui/cocoa/test/cocoa_profile_test.h",
         "../browser/ui/cocoa/test/cocoa_profile_test.mm",
         "../browser/ui/cocoa/test/run_loop_testing_unittest.mm",
@@ -4149,8 +4143,6 @@
         "../browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller_unittest.mm",
         "../browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_unittest.mm",
         "../browser/ui/cocoa/url_drop_target_unittest.mm",
-        "../browser/ui/cocoa/view_resizer_pong.h",
-        "../browser/ui/cocoa/view_resizer_pong.mm",
         "../browser/ui/cocoa/window_size_autosaver_unittest.mm",
       ]
     }
diff --git a/chrome/test/data/extensions/api_test/debugger/background.js b/chrome/test/data/extensions/api_test/debugger/background.js
index 3cbd7cb6..44a2b9ee 100644
--- a/chrome/test/data/extensions/api_test/debugger/background.js
+++ b/chrome/test/data/extensions/api_test/debugger/background.js
@@ -15,6 +15,7 @@
 var SILENT_FLAG_REQUIRED = "Cannot attach to this target unless " +
     "'silent-debugger-extension-api' flag is enabled.";
 var DETACHED_WHILE_HANDLING = "Detached while handling command.";
+var NOT_ALLOWED = "Not allowed.";
 
 chrome.test.getConfig(config => chrome.test.runTests([
 
@@ -298,6 +299,32 @@
     });
   },
 
+  // https://crbug.com/866426
+  function setDownloadBehavior() {
+    chrome.tabs.create({url: 'inspected.html'}, function(tab) {
+      var debuggee = {tabId: tab.id};
+      chrome.debugger.attach(debuggee, protocolVersion, function() {
+        chrome.test.assertNoLastError();
+        chrome.debugger.sendCommand(debuggee, 'Page.setDownloadBehavior',
+            {behavior: 'allow'}, onResponse);
+
+        function onResponse() {
+          var message;
+          try {
+            message = JSON.parse(chrome.runtime.lastError.message).message;
+          } catch (e) {
+          }
+          chrome.debugger.detach(debuggee, () => {
+            if (message === NOT_ALLOWED)
+              chrome.test.succeed();
+            else
+              chrome.test.fail('' + message + ' instead of ' + NOT_ALLOWED);
+          });
+        }
+      });
+    });
+  },
+
   function offlineErrorPage() {
     const url = 'http://127.0.0.1//extensions/api_test/debugger/inspected.html';
     chrome.tabs.create({url: url}, function(tab) {
diff --git a/chrome/test/data/extensions/api_test/metrics/test.js b/chrome/test/data/extensions/api_test/metrics/test.js
index bbdb964..29527e3 100644
--- a/chrome/test/data/extensions/api_test/metrics/test.js
+++ b/chrome/test/data/extensions/api_test/metrics/test.js
@@ -145,16 +145,17 @@
     chrome.metricsPrivate.recordValue(linear1, 42);
     // This one should be rejected because the bucket count is different.
     // We check for sample count == 2 in metrics_apitest.cc
-    // chrome.metricsPrivate.recordValue(linear2, 42);  disabled for field test
+    chrome.metricsPrivate.recordValue(linear2, 42);
     chrome.metricsPrivate.recordValue(linear1, 42);
 
     chrome.metricsPrivate.recordValue(log1, 42);
     // This one should be rejected because the bucket count is different.
     // We check for sample count == 2 in metrics_apitest.cc
-    // chrome.metricsPrivate.recordValue(log2, 42);  disabled for field test
+    chrome.metricsPrivate.recordValue(log2, 42);
     chrome.metricsPrivate.recordValue(log1, 42);
 
     chrome.test.succeed();
   },
+
 ]);
 
diff --git a/components/autofill/core/browser/strike_database.cc b/components/autofill/core/browser/strike_database.cc
index e01ed95..badaef77 100644
--- a/components/autofill/core/browser/strike_database.cc
+++ b/components/autofill/core/browser/strike_database.cc
@@ -8,6 +8,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/metrics/histogram_functions.h"
 #include "base/task/post_task.h"
 #include "base/time/time.h"
 #include "components/autofill/core/browser/proto/strike_data.pb.h"
@@ -113,16 +114,22 @@
   SetStrikeData(
       key, data,
       base::BindRepeating(&StrikeDatabase::OnAddStrikeComplete,
-                          base::Unretained(this), callback, num_strikes));
+                          base::Unretained(this), callback, num_strikes, key));
 }
 
 void StrikeDatabase::OnAddStrikeComplete(StrikesCallback callback,
                                          int num_strikes,
+                                         std::string key,
                                          bool success) {
-  if (success)
+  if (success) {
     callback.Run(num_strikes);
-  else
+    if (GetPrefixFromKey(key) == kKeyPrefixForCreditCardSave) {
+      base::UmaHistogramCounts1000(
+          "Autofill.StrikeDatabase.NthStrikeAdded.CreditCardSave", num_strikes);
+    }
+  } else {
     callback.Run(0);
+  }
 }
 
 void StrikeDatabase::OnClearAllStrikesForKey(ClearStrikesCallback callback,
@@ -139,4 +146,8 @@
   return kKeyPrefixForCreditCardSave;
 }
 
+std::string StrikeDatabase::GetPrefixFromKey(const std::string& key) {
+  return key.substr(0, key.find(kKeyDeliminator));
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/browser/strike_database.h b/components/autofill/core/browser/strike_database.h
index cfb4b21..77537652 100644
--- a/components/autofill/core/browser/strike_database.h
+++ b/components/autofill/core/browser/strike_database.h
@@ -20,6 +20,17 @@
 // the user. Projects can earn strikes in a number of ways; for instance, if a
 // user ignores or declines a prompt, or if a user accepts a prompt but the task
 // fails.
+
+// Here's how to create a new project type:
+// 1) The keys used for this database are in form
+// <ProjectTypePrefixName>__<SomeIdentifierSuffix>. In strike_database.cc, add a
+// char[] variable called kKeyPrefixFor<ProjectType>.
+// 2) In strike_database.h/cc, create the functions
+//   GetKeyFor<ProjectType>(const std::string& identifier) and
+//   GetKeyPrefixFor<ProjectType>().
+// 3) Add new project type to the if block in
+// StrikeDatabase::OnAddStrikeComplete(~).
+
 class StrikeDatabase : public KeyedService {
  public:
   using ClearStrikesCallback = base::RepeatingCallback<void(bool success)>;
@@ -60,6 +71,9 @@
   std::unique_ptr<leveldb_proto::ProtoDatabase<StrikeData>> db_;
 
  private:
+  FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseTest, GetPrefixFromKey);
+  friend class StrikeDatabaseTest;
+
   void OnDatabaseInit(bool success);
 
   // Passes success status and StrikeData entry for |key| to |inner_callback|.
@@ -86,6 +100,7 @@
 
   void OnAddStrikeComplete(StrikesCallback outer_callback,
                            int num_strikes,
+                           std::string key,
                            bool success);
 
   void OnClearAllStrikesForKey(ClearStrikesCallback outer_callback,
@@ -97,6 +112,8 @@
 
   std::string GetKeyPrefixForCreditCardSave();
 
+  std::string GetPrefixFromKey(const std::string& key);
+
   base::WeakPtrFactory<StrikeDatabase> weak_ptr_factory_;
 };
 
diff --git a/components/autofill/core/browser/strike_database_unittest.cc b/components/autofill/core/browser/strike_database_unittest.cc
index a87e523..77731c67 100644
--- a/components/autofill/core/browser/strike_database_unittest.cc
+++ b/components/autofill/core/browser/strike_database_unittest.cc
@@ -9,6 +9,7 @@
 
 #include "base/files/scoped_temp_dir.h"
 #include "base/run_loop.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/autofill/core/browser/proto/strike_data.pb.h"
@@ -78,6 +79,7 @@
   }
 
  protected:
+  base::HistogramTester* GetHistogramTester() { return &histogram_tester_; }
   base::test::ScopedTaskEnvironment scoped_task_environment_;
   TestStrikeDatabase db_;
 
@@ -90,6 +92,7 @@
     return file_path;
   }
 
+  base::HistogramTester histogram_tester_;
   int num_strikes_;
   std::unique_ptr<StrikeData> strike_data_;
 };
@@ -174,4 +177,32 @@
   EXPECT_EQ("creditCardSave__1234", db_.GetKeyForCreditCardSave(last_four));
 }
 
+TEST_F(StrikeDatabaseTest, GetPrefixFromKey) {
+  const std::string key = "creditCardSave__1234";
+  EXPECT_EQ("creditCardSave", db_.GetPrefixFromKey(key));
+}
+
+TEST_F(StrikeDatabaseTest, CreditCardSaveNthStrikeAddedHistogram) {
+  const std::string last_four1 = "1234";
+  const std::string last_four2 = "9876";
+  const std::string key1 = "NotACreditCard";
+  // 1st strike added for |last_four1|.
+  AddStrike(db_.GetKeyForCreditCardSave(last_four1));
+  // 2nd strike added for |last_four1|.
+  AddStrike(db_.GetKeyForCreditCardSave(last_four1));
+  // 1st strike added for |last_four2|.
+  AddStrike(db_.GetKeyForCreditCardSave(last_four2));
+  // Shouldn't be counted in histogram since key doesn't have prefix for credit
+  // cards.
+  AddStrike(key1);
+  std::vector<base::Bucket> buckets = GetHistogramTester()->GetAllSamples(
+      "Autofill.StrikeDatabase.NthStrikeAdded.CreditCardSave");
+  // There should be two buckets, one for 1st strike, one for 2nd strike count.
+  ASSERT_EQ(2U, buckets.size());
+  // Both |last_four1| and |last_four2| have 1st strikes recorded.
+  EXPECT_EQ(2, buckets[0].count);
+  // Only |last_four1| has 2nd strike recorded.
+  EXPECT_EQ(1, buckets[1].count);
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc
index 76371dd..f059e2d 100644
--- a/components/autofill/core/common/autofill_features.cc
+++ b/components/autofill/core/common/autofill_features.cc
@@ -184,7 +184,7 @@
 // are sent.
 const base::Feature kAutofillSendOnlyCountryInGetUploadDetails{
     "AutofillSendOnlyCountryInGetUploadDetails",
-    base::FEATURE_DISABLED_BY_DEFAULT};
+    base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Enables or Disables (mostly for hermetic testing) autofill server
 // communication. The URL of the autofill server can further be controlled via
@@ -264,7 +264,7 @@
 // Controls whether the PaymentsCustomerData is used to make requests to
 // Google Payments.
 const base::Feature kAutofillUsePaymentsCustomerData{
-    "AutofillUsePaymentsCustomerData", base::FEATURE_DISABLED_BY_DEFAULT};
+    "AutofillUsePaymentsCustomerData", base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Controls whether password generation is offered automatically on fields
 // perceived as eligible for generation.
diff --git a/components/autofill_assistant/browser/BUILD.gn b/components/autofill_assistant/browser/BUILD.gn
index 06d055b3..99df83d 100644
--- a/components/autofill_assistant/browser/BUILD.gn
+++ b/components/autofill_assistant/browser/BUILD.gn
@@ -60,6 +60,7 @@
     "script_tracker.h",
     "service.cc",
     "service.h",
+    "ui_controller.cc",
     "ui_controller.h",
     "ui_delegate.h",
     "web_controller.cc",
diff --git a/components/autofill_assistant/browser/DEPS b/components/autofill_assistant/browser/DEPS
index a7c7949a..9c42415 100644
--- a/components/autofill_assistant/browser/DEPS
+++ b/components/autofill_assistant/browser/DEPS
@@ -7,5 +7,6 @@
   "+google_apis",
   "+net",
   "+services/network/public/cpp",
+  "+third_party/blink/public/mojom/payments/payment_request.mojom.h",
   "+third_party/re2",
 ]
diff --git a/components/autofill_assistant/browser/controller.cc b/components/autofill_assistant/browser/controller.cc
index de6315f5..c13bce3a 100644
--- a/components/autofill_assistant/browser/controller.cc
+++ b/components/autofill_assistant/browser/controller.cc
@@ -239,13 +239,15 @@
 
 void Controller::DidGetUserInteraction(const blink::WebInputEvent::Type type) {
   switch (type) {
-    case blink::WebInputEvent::kGestureLongTap:
-    case blink::WebInputEvent::kGestureTap:
+    case blink::WebInputEvent::kTouchStart:
+    case blink::WebInputEvent::kGestureTapDown:
       // Disable autostart after interaction with the web page.
       allow_autostart_ = false;
 
-      if (!script_tracker_->running())
+      if (!script_tracker_->running()) {
         script_tracker_->CheckScripts();
+        StartPeriodicScriptChecks();
+      }
       break;
 
     default:
@@ -282,6 +284,10 @@
   GetUiController()->UpdateScripts(runnable_scripts);
 }
 
+void Controller::DocumentAvailableInMainFrame() {
+  GetOrCheckScripts(web_contents()->GetLastCommittedURL());
+}
+
 void Controller::DidFinishLoad(content::RenderFrameHost* render_frame_host,
                                const GURL& validated_url) {
   // validated_url might not be the page URL. Ignore it and always check the
diff --git a/components/autofill_assistant/browser/controller.h b/components/autofill_assistant/browser/controller.h
index c641572..32c3ac5f 100644
--- a/components/autofill_assistant/browser/controller.h
+++ b/components/autofill_assistant/browser/controller.h
@@ -92,6 +92,7 @@
   void DidFinishLoad(content::RenderFrameHost* render_frame_host,
                      const GURL& validated_url) override;
   void WebContentsDestroyed() override;
+  void DocumentAvailableInMainFrame() override;
 
   // Overrides content::WebContentsDelegate:
   void LoadProgressChanged(content::WebContents* source,
diff --git a/components/autofill_assistant/browser/controller_unittest.cc b/components/autofill_assistant/browser/controller_unittest.cc
index 85528ee..345b240 100644
--- a/components/autofill_assistant/browser/controller_unittest.cc
+++ b/components/autofill_assistant/browser/controller_unittest.cc
@@ -298,7 +298,7 @@
   EXPECT_CALL(*mock_ui_controller_, UpdateScripts(SizeIs(1)));
   EXPECT_CALL(*mock_service_, OnGetActions(StrEq("runnable"), _, _)).Times(0);
 
-  SimulateUserInteraction(blink::WebInputEvent::kGestureTap);
+  SimulateUserInteraction(blink::WebInputEvent::kTouchStart);
   SimulateNavigateToUrl(GURL("http://a.example.com/path"));
 }
 
diff --git a/components/autofill_assistant/browser/mock_run_once_callback.h b/components/autofill_assistant/browser/mock_run_once_callback.h
index 97e3bf3a..fdb29b6 100644
--- a/components/autofill_assistant/browser/mock_run_once_callback.h
+++ b/components/autofill_assistant/browser/mock_run_once_callback.h
@@ -41,6 +41,23 @@
   return std::move(std::get<k>(args)).Run(p0, p1, p2);
 }
 
+// Template for capturing a base::OnceCallback passed to a mocked method
+//
+// This is useful to run the callback later on, at an appropriate time.
+//
+// base::OnceCallback<void(bool)> captured_callback;
+//   EXPECT_CALL(my_mock_, MyMethod(_))
+//     .WillOnce(CaptureOnceCallback<0>(&captured_callback));
+// [...]
+// std::move(captured_callback).Run();
+//
+
+ACTION_TEMPLATE(CaptureOnceCallback,
+                HAS_1_TEMPLATE_PARAMS(int, k),
+                AND_1_VALUE_PARAMS(p0)) {
+  *p0 = std::move(std::get<k>(args));
+}
+
 }  // namespace autofill_assistant
 
 #endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_MOCK_RUN_ONCE_CALLBACK_H_
diff --git a/components/autofill_assistant/browser/mock_ui_controller.h b/components/autofill_assistant/browser/mock_ui_controller.h
index 0e363ae..99abdfea 100644
--- a/components/autofill_assistant/browser/mock_ui_controller.h
+++ b/components/autofill_assistant/browser/mock_ui_controller.h
@@ -40,6 +40,11 @@
   }
   MOCK_METHOD1(OnChooseCard,
                void(base::OnceCallback<void(const std::string&)>& callback));
+  MOCK_METHOD2(
+      GetPaymentInformation,
+      void(payments::mojom::PaymentOptionsPtr payment_options,
+           base::OnceCallback<void(std::unique_ptr<PaymentInformation>)>
+               callback));
   MOCK_METHOD0(HideDetails, void());
   MOCK_METHOD1(ShowDetails, void(const DetailsProto& details));
 };
diff --git a/components/autofill_assistant/browser/script_tracker.cc b/components/autofill_assistant/browser/script_tracker.cc
index f78129d..64ce28d 100644
--- a/components/autofill_assistant/browser/script_tracker.cc
+++ b/components/autofill_assistant/browser/script_tracker.cc
@@ -18,6 +18,7 @@
     : delegate_(delegate),
       listener_(listener),
       running_checks_(false),
+      must_recheck_(false),
       weak_ptr_factory_(this) {
   DCHECK(delegate_);
   DCHECK(listener_);
@@ -35,8 +36,10 @@
 }
 
 void ScriptTracker::CheckScripts() {
-  if (running_checks_)
+  if (running_checks_) {
+    must_recheck_ = true;
     return;
+  }
   running_checks_ = true;
 
   RunPreconditionChecksSequentially(available_scripts_.begin());
@@ -95,6 +98,10 @@
   if (runnables_changed) {
     listener_->OnRunnableScriptsChanged(runnable_scripts_);
   }
+  if (must_recheck_) {
+    must_recheck_ = false;
+    CheckScripts();
+  }
 }
 
 bool ScriptTracker::RunnablesHaveChanged() {
diff --git a/components/autofill_assistant/browser/script_tracker.h b/components/autofill_assistant/browser/script_tracker.h
index a30f1eb3..eb02706 100644
--- a/components/autofill_assistant/browser/script_tracker.h
+++ b/components/autofill_assistant/browser/script_tracker.h
@@ -114,6 +114,10 @@
   // Scripts found to be runnable so far, in the current run of CheckScripts.
   std::vector<Script*> pending_runnable_scripts_;
 
+  // If a Check() was called while a check was in progress, run another one just
+  // afterwards, in case things have changed.
+  bool must_recheck_;
+
   // If a script is currently running, this is the script's executor. Otherwise,
   // this is nullptr.
   std::unique_ptr<ScriptExecutor> executor_;
diff --git a/components/autofill_assistant/browser/script_tracker_unittest.cc b/components/autofill_assistant/browser/script_tracker_unittest.cc
index d3cbed5..2627586 100644
--- a/components/autofill_assistant/browser/script_tracker_unittest.cc
+++ b/components/autofill_assistant/browser/script_tracker_unittest.cc
@@ -269,4 +269,32 @@
   ASSERT_THAT(runnable_script_paths(), ElementsAre("script path"));
 }
 
+TEST_F(ScriptTrackerTest, DuplicateCheckCalls) {
+  SupportsScriptResponseProto scripts;
+  AddScript(&scripts, "runnable name", "runnable path", "exists");
+
+  base::OnceCallback<void(bool)> captured_callback;
+  EXPECT_CALL(mock_web_controller_, OnElementExists(ElementsAre("exists"), _))
+      .WillOnce(CaptureOnceCallback<1>(&captured_callback))
+      .WillOnce(RunOnceCallback<1>(false));
+  SetAndCheckScripts(scripts);
+
+  // At this point, since the callback hasn't been run, there's still a check in
+  // progress. The three calls to CheckScripts will trigger one call to
+  // CheckScript right after first_call has run.
+  for (int i = 0; i < 3; i++) {
+    tracker_.CheckScripts();
+  }
+
+  EXPECT_THAT(runnable_scripts(), IsEmpty());
+  ASSERT_TRUE(captured_callback);
+  std::move(captured_callback).Run(true);
+
+  // The second check is run right away, after the first check, say that the
+  // element doesn't exist anymore, and we end up again with an empty
+  // runnable_scripts.
+  EXPECT_THAT(runnable_scripts(), IsEmpty());
+  EXPECT_EQ(2, runnable_scripts_changed_);
+}
+
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/ui_controller.cc b/components/autofill_assistant/browser/ui_controller.cc
new file mode 100644
index 0000000..228fee1
--- /dev/null
+++ b/components/autofill_assistant/browser/ui_controller.cc
@@ -0,0 +1,13 @@
+// Copyright 2018 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 "components/autofill_assistant/browser/ui_controller.h"
+
+namespace autofill_assistant {
+
+PaymentInformation::PaymentInformation() : succeed(false) {}
+
+PaymentInformation::~PaymentInformation() = default;
+
+}  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/ui_controller.h b/components/autofill_assistant/browser/ui_controller.h
index af5eaba..af5caee 100644
--- a/components/autofill_assistant/browser/ui_controller.h
+++ b/components/autofill_assistant/browser/ui_controller.h
@@ -11,11 +11,24 @@
 #include "base/callback_forward.h"
 #include "components/autofill_assistant/browser/script.h"
 #include "components/autofill_assistant/browser/ui_delegate.h"
+#include "third_party/blink/public/mojom/payments/payment_request.mojom.h"
 
 namespace autofill_assistant {
 struct ScriptHandle;
 class DetailsProto;
 
+struct PaymentInformation {
+  PaymentInformation();
+  ~PaymentInformation();
+
+  bool succeed;
+  std::string card_guid;
+  std::string address_guid;
+  std::string payer_name;
+  std::string payer_phone;
+  std::string payer_email;
+};
+
 // Controller to control autofill assistant UI.
 class UiController {
  public:
@@ -57,6 +70,13 @@
   virtual void ChooseCard(
       base::OnceCallback<void(const std::string&)> callback) = 0;
 
+  // Get payment information (through similar to payment request UX) to fill
+  // forms.
+  virtual void GetPaymentInformation(
+      payments::mojom::PaymentOptionsPtr payment_options,
+      base::OnceCallback<void(std::unique_ptr<PaymentInformation>)>
+          callback) = 0;
+
   // Hide contextual information.
   virtual void HideDetails() = 0;
 
diff --git a/components/metrics/single_sample_metrics_factory_impl_unittest.cc b/components/metrics/single_sample_metrics_factory_impl_unittest.cc
index 8af6441..7362085 100644
--- a/components/metrics/single_sample_metrics_factory_impl_unittest.cc
+++ b/components/metrics/single_sample_metrics_factory_impl_unittest.cc
@@ -125,7 +125,6 @@
   base::RunLoop().RunUntilIdle();
   tester.ExpectUniqueSample(kMetricName, kLastSample, 1);
 
-#if 0  // TODO(crbug.com/836238): Temporarily disabled for field crash test.
   // Verify construction implicitly by requesting a histogram with the same
   // parameters; this test relies on the fact that histogram objects are unique
   // per name. Different parameters will result in a Dummy histogram returned.
@@ -136,7 +135,6 @@
             base::Histogram::FactoryGet(
                 kMetricName, kMin, kMax, kBucketCount,
                 base::HistogramBase::kUmaTargetedHistogramFlag));
-#endif
 }
 
 TEST_F(SingleSampleMetricsFactoryImplTest, MultithreadedMetrics) {
diff --git a/components/neterror/resources/images/download-blue.svg b/components/neterror/resources/images/download-blue.svg
index 451261f..99e9be7 100644
--- a/components/neterror/resources/images/download-blue.svg
+++ b/components/neterror/resources/images/download-blue.svg
@@ -1 +1,5 @@
-<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1.2em" height="1.2em" viewBox="0 0 24 24"><path d="M5,20H19V18H5M19,9H15V3H9V9H5L12,16L19,9Z" fill="rgb(66, 133, 244)" /></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1.2em" height="1.2em" viewBox="0 0 24 24">
+    <path d="M5,20H19V18H5M19,9H15V3H9V9H5L12,16L19,9Z" fill="rgb(66, 133, 244)" />
+</svg>
\ No newline at end of file
diff --git a/components/neterror/resources/images/earth.svg b/components/neterror/resources/images/earth.svg
deleted file mode 100644
index e458102..0000000
--- a/components/neterror/resources/images/earth.svg
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M17.9,17.39C17.64,16.59 16.89,16 16,16H15V13A1,1 0 0,0 14,12H8V10H10A1,1 0 0,0 11,9V7H13A2,2 0 0,0 15,5V4.59C17.93,5.77 20,8.64 20,12C20,14.08 19.2,15.97 17.9,17.39M11,19.93C7.05,19.44 4,16.08 4,12C4,11.38 4.08,10.78 4.21,10.21L9,15V16A2,2 0 0,0 11,18M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z" fill="#3C4043" /></svg>
\ No newline at end of file
diff --git a/components/neterror/resources/images/file.svg b/components/neterror/resources/images/file.svg
index 64746c3..ce6f09be 100644
--- a/components/neterror/resources/images/file.svg
+++ b/components/neterror/resources/images/file.svg
@@ -1 +1,5 @@
-<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9V3.5L18.5,9M6,2C4.89,2 4,2.89 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2H6Z" fill="#3C4043" /></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24">
+    <path d="M13,9V3.5L18.5,9M6,2C4.89,2 4,2.89 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2H6Z" fill="#3C4043" />
+</svg>
\ No newline at end of file
diff --git a/components/neterror/resources/images/generic-globe.svg b/components/neterror/resources/images/generic-globe.svg
new file mode 100644
index 0000000..62fdfe80
--- /dev/null
+++ b/components/neterror/resources/images/generic-globe.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <path d="M12,2 C17.52,2 22,6.48 22,12 C22,17.52 17.52,22 12,22 C6.48,22 2,17.52 2,12 C2,6.48 6.48,2 12,2 Z M4,12 L8.39965738,12 C11.8069564,12.0216703 13.3215127,13.7306881 12.9433263,17.1270533 L9.48779297,17.1270533 L9.48779297,19.5969677 C10.2779812,19.8584533 11.1225862,20 12,20 C16.4154305,20 20,16.4154305 20,12 C20,11.8369689 19.9951131,11.6750705 19.985478,11.5144435 C19.3284927,12.5048145 18.3333333,13 17,13 C14.8625709,13 13.7938564,12.0835751 13.7938564,10.2507252 L10.0456962,10.2507252 C9.77189381,7.52243177 10.7285175,6.15828507 12.9155672,6.15828507 C12.9155672,5.18308692 13.2430063,4.56146185 13.7272555,4.1872682 C13.170934,4.0646458 12.592959,4 12,4 C7.5845695,4 4,7.5845695 4,12 Z" id="Combined-Shape" fill="#3C4043" fill-rule="nonzero"></path>
+</svg>
\ No newline at end of file
diff --git a/components/neterror/resources/images/help_outline.svg b/components/neterror/resources/images/help_outline.svg
index cfde6f3..d596819 100644
--- a/components/neterror/resources/images/help_outline.svg
+++ b/components/neterror/resources/images/help_outline.svg
@@ -1,3 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
     <path fill="none" d="M0 0h24v24H0z"/>
     <path d="M11 18h2v-2h-2v2zm1-16C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm0-14c-2.21 0-4 1.79-4 4h2c0-1.1.9-2 2-2s2 .9 2 2c0 2-3 1.75-3 5h2c0-2.25 3-2.5 3-5 0-2.21-1.79-4-4-4z"/>
diff --git a/components/neterror/resources/images/image.svg b/components/neterror/resources/images/image.svg
index 5dcc960a..1977b2f 100644
--- a/components/neterror/resources/images/image.svg
+++ b/components/neterror/resources/images/image.svg
@@ -1 +1,5 @@
-<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M8.5,13.5L11,16.5L14.5,12L19,18H5M21,19V5C21,3.89 20.1,3 19,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19Z" fill="#3C4043" /></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24">
+    <path d="M8.5,13.5L11,16.5L14.5,12L19,18H5M21,19V5C21,3.89 20.1,3 19,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19Z" fill="#3C4043" />
+</svg>
\ No newline at end of file
diff --git a/components/neterror/resources/images/music-note.svg b/components/neterror/resources/images/music-note.svg
index 13a2bf93..2741b37 100644
--- a/components/neterror/resources/images/music-note.svg
+++ b/components/neterror/resources/images/music-note.svg
@@ -1 +1,5 @@
-<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M12,3V12.26C11.5,12.09 11,12 10.5,12C8,12 6,14 6,16.5C6,19 8,21 10.5,21C13,21 15,19 15,16.5V6H19V3H12Z" fill="#3C4043" /></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24">
+    <path d="M12,3V12.26C11.5,12.09 11,12 10.5,12C8,12 6,14 6,16.5C6,19 8,21 10.5,21C13,21 15,19 15,16.5V6H19V3H12Z" fill="#3C4043" />
+</svg>
\ No newline at end of file
diff --git a/components/neterror/resources/images/offline_pin.svg b/components/neterror/resources/images/offline_pin.svg
index d21fe5b..94f8e6f 100644
--- a/components/neterror/resources/images/offline_pin.svg
+++ b/components/neterror/resources/images/offline_pin.svg
@@ -1,3 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
 <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24" width="24" height="24">
     <defs>
         <path id="a" d="M0 0h24v24H0V0z"/>
diff --git a/components/neterror/resources/images/video.svg b/components/neterror/resources/images/video.svg
index 637f89ce..750ac797 100644
--- a/components/neterror/resources/images/video.svg
+++ b/components/neterror/resources/images/video.svg
@@ -1 +1,5 @@
-<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M17,10.5V7A1,1 0 0,0 16,6H4A1,1 0 0,0 3,7V17A1,1 0 0,0 4,18H16A1,1 0 0,0 17,17V13.5L21,17.5V6.5L17,10.5Z" fill="#3C4043" /></svg>
\ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24">
+    <path d="M17,10.5V7A1,1 0 0,0 16,6H4A1,1 0 0,0 3,7V17A1,1 0 0,0 4,18H16A1,1 0 0,0 17,17V13.5L21,17.5V6.5L17,10.5Z" fill="#3C4043" />
+</svg>
\ No newline at end of file
diff --git a/components/neterror/resources/neterror.css b/components/neterror/resources/neterror.css
index b8158a4..9655508 100644
--- a/components/neterror/resources/neterror.css
+++ b/components/neterror/resources/neterror.css
@@ -432,7 +432,7 @@
 }
 
 .image-earth {
-  content: url(images/earth.svg);
+  content: url(images/generic-globe.svg);
 }
 
 .image-file {
diff --git a/components/neterror/resources/neterror.html b/components/neterror/resources/neterror.html
index be2f4bcd..25c98f9 100644
--- a/components/neterror/resources/neterror.html
+++ b/components/neterror/resources/neterror.html
@@ -75,7 +75,7 @@
         <div id="offline-content-summary" onclick="launchDownloadsPage()" hidden>
           <div class="offline-content-summary-images">
             <div class="offline-content-summary-image-truncate">
-              <img id="earth" src="images/earth.svg">
+              <img id="earth" src="images/generic-globe.svg">
             </div>
             <div class="offline-content-summary-image-truncate">
               <img id="music-note" src="images/music-note.svg">
diff --git a/components/payments/content/manifest_verifier.cc b/components/payments/content/manifest_verifier.cc
index 8b6e910..ee040c9 100644
--- a/components/payments/content/manifest_verifier.cc
+++ b/components/payments/content/manifest_verifier.cc
@@ -19,6 +19,7 @@
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/console_message_level.h"
+#include "net/base/url_util.h"
 #include "url/gurl.h"
 #include "url/origin.h"
 
@@ -110,10 +111,11 @@
         continue;
       }
 
-      // All URL payment method names must be HTTPS.
+      // All URL payment method names must be HTTPS or localhost for test.
       GURL method_manifest_url = GURL(method);
       if (!method_manifest_url.is_valid() ||
-          method_manifest_url.scheme() != "https") {
+          (method_manifest_url.scheme() != "https" &&
+           !net::IsLocalhost(method_manifest_url))) {
         dev_tools_.WarnIfPossible("\"" + method +
                                   "\" is not a valid payment method name.");
         continue;
diff --git a/components/safe_browsing/common/safe_browsing_prefs.cc b/components/safe_browsing/common/safe_browsing_prefs.cc
index a3203f8..c300dd0 100644
--- a/components/safe_browsing/common/safe_browsing_prefs.cc
+++ b/components/safe_browsing/common/safe_browsing_prefs.cc
@@ -168,21 +168,6 @@
 const base::Feature kCanShowScoutOptIn{"CanShowScoutOptIn",
                                        base::FEATURE_ENABLED_BY_DEFAULT};
 
-std::string ChooseOptInTextPreference(
-    const PrefService& prefs,
-    const std::string& extended_reporting_pref,
-    const std::string& scout_pref) {
-  // TODO(lpz): Delete this method and update callers
-  return scout_pref;
-}
-
-int ChooseOptInTextResource(const PrefService& prefs,
-                            int extended_reporting_resource,
-                            int scout_resource) {
-  // TODO(lpz): Delete this method and update callers
-  return scout_resource;
-}
-
 bool ExtendedReportingPrefExists(const PrefService& prefs) {
   return prefs.HasPrefPath(GetExtendedReportingPrefName(prefs));
 }
diff --git a/components/safe_browsing/common/safe_browsing_prefs.h b/components/safe_browsing/common/safe_browsing_prefs.h
index 51bb80e2..a90d70b6 100644
--- a/components/safe_browsing/common/safe_browsing_prefs.h
+++ b/components/safe_browsing/common/safe_browsing_prefs.h
@@ -142,23 +142,6 @@
   PASSWORD_PROTECTION_TRIGGER_MAX,
 };
 
-// Determines which opt-in text should be used based on the currently active
-// preference. Will return either |extended_reporting_pref| if the legacy
-// Extended Reporting pref is active, or |scout_pref| if the Scout pref is
-// active. Used for Android.
-std::string ChooseOptInTextPreference(
-    const PrefService& prefs,
-    const std::string& extended_reporting_pref,
-    const std::string& scout_pref);
-
-// Determines which opt-in text should be used based on the currently active
-// preference. Will return either |extended_reporting_resource| if the legacy
-// Extended Reporting pref is active, or |scout_resource| if the Scout pref is
-// active.
-int ChooseOptInTextResource(const PrefService& prefs,
-                            int extended_reporting_resource,
-                            int scout_resource);
-
 // Returns whether the currently active Safe Browsing Extended Reporting
 // preference exists (eg: has been set before).
 bool ExtendedReportingPrefExists(const PrefService& prefs);
diff --git a/components/safe_browsing/common/safe_browsing_prefs_unittest.cc b/components/safe_browsing/common/safe_browsing_prefs_unittest.cc
index 28ed094..cc3cb04 100644
--- a/components/safe_browsing/common/safe_browsing_prefs_unittest.cc
+++ b/components/safe_browsing/common/safe_browsing_prefs_unittest.cc
@@ -159,28 +159,6 @@
 
 // TODO(crbug.com/881476) disabled for flaky crashes.
 #if defined(OS_WIN)
-#define MAYBE_ChooseOptInText DISABLED_ChooseOptInText
-#else
-#define MAYBE_ChooseOptInText ChooseOptInText
-#endif
-TEST_F(SafeBrowsingPrefsTest, MAYBE_ChooseOptInText) {
-  // Ensure that Scout resources are always chosen.
-  const int kSberResource = 100;
-  const int kScoutResource = 500;
-
-  // By default, Scout opt-in is used
-  EXPECT_EQ(kScoutResource,
-            ChooseOptInTextResource(prefs_, kSberResource, kScoutResource));
-
-  // Enabling Scout still uses the Scout opt-in text.
-  ResetExperiments(/*can_show_scout=*/true);
-  ResetPrefs(/*scout=*/false, /*scout_group=*/true);
-  EXPECT_EQ(kScoutResource,
-            ChooseOptInTextResource(prefs_, kSberResource, kScoutResource));
-}
-
-// TODO(crbug.com/881476) disabled for flaky crashes.
-#if defined(OS_WIN)
 #define MAYBE_GetSafeBrowsingExtendedReportingLevel \
   DISABLED_GetSafeBrowsingExtendedReportingLevel
 #else
diff --git a/components/search/url_validity_checker_impl.cc b/components/search/url_validity_checker_impl.cc
index accddbfa..a19061e3 100644
--- a/components/search/url_validity_checker_impl.cc
+++ b/components/search/url_validity_checker_impl.cc
@@ -5,18 +5,35 @@
 #include "components/search/url_validity_checker_impl.h"
 
 #include "base/bind.h"
+#include "base/time/default_tick_clock.h"
+#include "base/time/tick_clock.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "net/http/http_request_headers.h"
 #include "net/http/http_status_code.h"
 
+namespace {
+
+// Request timeout duration.
+constexpr base::TimeDelta kRequestTimeout = base::TimeDelta::FromSeconds(10);
+
+}  // namespace
+
 // Stores the pending request and associated metadata. Deleted once the request
 // finishes.
 struct UrlValidityCheckerImpl::PendingRequest {
-  PendingRequest() = default;
+  PendingRequest(const GURL& url,
+                 const base::TimeTicks& time_created,
+                 const base::TickClock* clock,
+                 UrlValidityCheckerCallback callback)
+      : url(url),
+        time_created(time_created),
+        timeout_timer(clock),
+        callback(std::move(callback)) {}
 
   GURL url;
   base::TimeTicks time_created;
+  base::OneShotTimer timeout_timer;
   UrlValidityCheckerCallback callback;
   std::unique_ptr<network::SimpleURLLoader> loader;
 
@@ -25,7 +42,8 @@
 
 UrlValidityCheckerImpl::UrlValidityCheckerImpl(
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
-    : url_loader_factory_(url_loader_factory) {}
+    : url_loader_factory_(url_loader_factory),
+      clock_(base::DefaultTickClock::GetInstance()) {}
 
 UrlValidityCheckerImpl::~UrlValidityCheckerImpl() = default;
 
@@ -38,10 +56,8 @@
   resource_request->method = "HEAD";
   resource_request->allow_credentials = false;
 
-  auto request_iter = pending_requests_.emplace(pending_requests_.begin());
-  request_iter->url = url;
-  request_iter->time_created = NowTicks();
-  request_iter->callback = std::move(callback);
+  auto request_iter = pending_requests_.emplace(
+      pending_requests_.begin(), url, NowTicks(), clock_, std::move(callback));
   request_iter->loader = network::SimpleURLLoader::Create(
       std::move(resource_request), traffic_annotation);
   // Don't follow redirects to prevent leaking URL data to HTTP sites.
@@ -53,6 +69,10 @@
       base::BindOnce(&UrlValidityCheckerImpl::OnSimpleLoaderComplete,
                      weak_ptr_factory_.GetWeakPtr(), request_iter),
       /*max_body_size=*/1);
+  request_iter->timeout_timer.Start(
+      FROM_HERE, kRequestTimeout,
+      base::BindOnce(&UrlValidityCheckerImpl::OnSimpleLoaderHandler,
+                     weak_ptr_factory_.GetWeakPtr(), request_iter, false));
 }
 
 void UrlValidityCheckerImpl::OnSimpleLoaderRedirect(
diff --git a/components/search/url_validity_checker_impl.h b/components/search/url_validity_checker_impl.h
index fea4b02..e3a0257 100644
--- a/components/search/url_validity_checker_impl.h
+++ b/components/search/url_validity_checker_impl.h
@@ -15,6 +15,10 @@
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/simple_url_loader.h"
 
+namespace base {
+class TickClock;
+}  // namespace base
+
 namespace net {
 struct RedirectInfo;
 }  // namespace net
@@ -42,6 +46,10 @@
  private:
   struct PendingRequest;
 
+  // Called when the request times out. Calls back false and returns the request
+  // duration.
+  void OnRequestTimeout(std::list<PendingRequest>::iterator request_iter);
+
   void OnSimpleLoaderRedirect(
       std::list<PendingRequest>::iterator request_iter,
       const net::RedirectInfo& redirect_info,
@@ -65,6 +73,9 @@
   // Test time ticks used for testing.
   base::TimeTicks time_ticks_for_testing_;
 
+  // Non-owned pointer to TickClock. Used for request timeouts.
+  const base::TickClock* const clock_;
+
   base::WeakPtrFactory<UrlValidityCheckerImpl> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(UrlValidityCheckerImpl);
diff --git a/components/search/url_validity_checker_impl_unittest.cc b/components/search/url_validity_checker_impl_unittest.cc
index 4c154bf..6a7d200 100644
--- a/components/search/url_validity_checker_impl_unittest.cc
+++ b/components/search/url_validity_checker_impl_unittest.cc
@@ -22,7 +22,9 @@
 class UrlValidityCheckerImplTest : public testing::Test {
  protected:
   UrlValidityCheckerImplTest()
-      : test_shared_loader_factory_(
+      : scoped_task_environment_(
+            base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME),
+        test_shared_loader_factory_(
             base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
                 &test_url_loader_factory_)),
         url_checker_(test_shared_loader_factory_) {
@@ -144,3 +146,15 @@
                                 callback.Get());
   scoped_task_environment_.RunUntilIdle();
 }
+
+TEST_F(UrlValidityCheckerImplTest, DoesUrlResolve_OnTimeout) {
+  const GURL kUrl("https://www.foo.com");
+
+  base::MockCallback<UrlValidityChecker::UrlValidityCheckerCallback> callback;
+  EXPECT_CALL(callback, Run(false, _));
+
+  url_checker()->DoesUrlResolve(kUrl, TRAFFIC_ANNOTATION_FOR_TESTS,
+                                callback.Get());
+  scoped_task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(20));
+  scoped_task_environment_.RunUntilIdle();
+}
diff --git a/components/security_interstitials/core/safe_browsing_loud_error_ui.cc b/components/security_interstitials/core/safe_browsing_loud_error_ui.cc
index 522fdb3..bbb9938 100644
--- a/components/security_interstitials/core/safe_browsing_loud_error_ui.cc
+++ b/components/security_interstitials/core/safe_browsing_loud_error_ui.cc
@@ -306,12 +306,10 @@
       security_interstitials::kPrivacyLinkHtml,
       security_interstitials::CMD_OPEN_REPORTING_PRIVACY,
       l10n_util::GetStringUTF8(IDS_SAFE_BROWSING_PRIVACY_POLICY_PAGE).c_str());
-  load_time_data->SetString(security_interstitials::kOptInLink,
-                            l10n_util::GetStringFUTF16(
-                                is_scout_reporting_enabled()
-                                    ? IDS_SAFE_BROWSING_SCOUT_REPORTING_AGREE
-                                    : IDS_SAFE_BROWSING_MALWARE_REPORTING_AGREE,
-                                base::UTF8ToUTF16(privacy_link)));
+  load_time_data->SetString(
+      security_interstitials::kOptInLink,
+      l10n_util::GetStringFUTF16(IDS_SAFE_BROWSING_SCOUT_REPORTING_AGREE,
+                                 base::UTF8ToUTF16(privacy_link)));
   load_time_data->SetBoolean(security_interstitials::kBoxChecked,
                              is_extended_reporting_enabled());
 }
diff --git a/components/security_interstitials_strings.grdp b/components/security_interstitials_strings.grdp
index 2be55d3..d2f749b6 100644
--- a/components/security_interstitials_strings.grdp
+++ b/components/security_interstitials_strings.grdp
@@ -235,9 +235,6 @@
   <message name="IDS_SAFE_BROWSING_PRIVACY_POLICY_PAGE" desc="Label for the link to SafeBrowsing Privacy policy page">
     Privacy policy
   </message>
-  <message name="IDS_SAFE_BROWSING_MALWARE_REPORTING_AGREE" desc="SafeBrowsing Malware v2 Details label next to checkbox">
-    <ph name="BEGIN_WHITEPAPER_LINK">&lt;a href="#" id="whitepaper-link"&gt;</ph>Automatically report<ph name="END_WHITEPAPER_LINK">&lt;/a&gt;</ph> details of possible security incidents to Google. <ph name="PRIVACY_PAGE_LINK">$1</ph>
-  </message>
   <message name="IDS_SAFE_BROWSING_SCOUT_REPORTING_AGREE" desc="SafeBrowsing Scout label next to checkbox">
     Help improve Safe Browsing by sending some <ph name="BEGIN_WHITEPAPER_LINK">&lt;a href="#" id="whitepaper-link"&gt;</ph>system information and page content<ph name="END_WHITEPAPER_LINK">&lt;/a&gt;</ph> to Google. <ph name="PRIVACY_PAGE_LINK">$1</ph>
   </message>
diff --git a/components/viz/service/display/display.cc b/components/viz/service/display/display.cc
index eb754bb..9414a5d 100644
--- a/components/viz/service/display/display.cc
+++ b/components/viz/service/display/display.cc
@@ -230,12 +230,19 @@
       mode, output_surface_->context_provider(), bitmap_manager_);
 
   if (settings_.use_skia_renderer && mode == DisplayResourceProvider::kGpu) {
-    // Check the compositing mode, because SkiaRenderer only works with GPU
-    // compositing.
-    DCHECK(output_surface_);
-    renderer_ = std::make_unique<SkiaRenderer>(
-        &settings_, output_surface_.get(), resource_provider_.get(),
-        skia_output_surface_);
+    // Default to use DDL if skia_output_surface is not null.
+    if (skia_output_surface_) {
+      renderer_ = std::make_unique<SkiaRenderer>(
+          &settings_, output_surface_.get(), resource_provider_.get(),
+          skia_output_surface_, SkiaRenderer::DrawMode::DDL);
+    } else {
+      // GPU compositing with GL.
+      DCHECK(output_surface_);
+      DCHECK(output_surface_->context_provider());
+      renderer_ = std::make_unique<SkiaRenderer>(
+          &settings_, output_surface_.get(), resource_provider_.get(),
+          nullptr /* skia_output_surface */, SkiaRenderer::DrawMode::GL);
+    }
   } else if (output_surface_->context_provider()) {
     renderer_ = std::make_unique<GLRenderer>(&settings_, output_surface_.get(),
                                              resource_provider_.get(),
@@ -244,7 +251,7 @@
   } else if (output_surface_->vulkan_context_provider()) {
     renderer_ = std::make_unique<SkiaRenderer>(
         &settings_, output_surface_.get(), resource_provider_.get(),
-        nullptr /* skia_output_surface */);
+        nullptr /* skia_output_surface */, SkiaRenderer::DrawMode::VULKAN);
 #endif
   } else {
     auto renderer = std::make_unique<SoftwareRenderer>(
diff --git a/components/viz/service/display/overlay_strategy_underlay.cc b/components/viz/service/display/overlay_strategy_underlay.cc
index 7068234..310ba42 100644
--- a/components/viz/service/display/overlay_strategy_underlay.cc
+++ b/components/viz/service/display/overlay_strategy_underlay.cc
@@ -70,7 +70,7 @@
       candidate_list->AddPromotionHint(candidate);
       return true;
     } else {
-      // If |candidate| should get a promotion hint, then rememeber that now.
+      // If |candidate| should get a promotion hint, then remember that now.
       candidate_list->promotion_hint_info_map_.insert(
           new_candidate_list.promotion_hint_info_map_.begin(),
           new_candidate_list.promotion_hint_info_map_.end());
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc
index cb7f3f1..b50b178e 100644
--- a/components/viz/service/display/skia_renderer.cc
+++ b/components/viz/service/display/skia_renderer.cc
@@ -29,7 +29,6 @@
 #include "components/viz/service/display/resource_metadata.h"
 #include "components/viz/service/display/skia_output_surface.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
-#include "gpu/vulkan/buildflags.h"
 #include "skia/ext/opacity_filter_canvas.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "third_party/skia/include/core/SkColor.h"
@@ -179,17 +178,34 @@
 SkiaRenderer::SkiaRenderer(const RendererSettings* settings,
                            OutputSurface* output_surface,
                            DisplayResourceProvider* resource_provider,
-                           SkiaOutputSurface* skia_output_surface)
+                           SkiaOutputSurface* skia_output_surface,
+                           DrawMode mode)
     : DirectRenderer(settings, output_surface, resource_provider),
+      draw_mode_(mode),
       skia_output_surface_(skia_output_surface),
-      quad_vertex_skrect_(gfx::RectFToSkRect(QuadVertexRect())),
       lock_set_for_external_use_(resource_provider) {
-  if (auto* context_provider = output_surface_->context_provider()) {
-    const auto& context_caps = context_provider->ContextCapabilities();
-    use_swap_with_bounds_ = context_caps.swap_buffers_with_bounds;
-    if (context_caps.sync_query) {
-      sync_queries_ =
-          base::Optional<SyncQueryCollection>(context_provider->ContextGL());
+  switch (draw_mode_) {
+    case DrawMode::GL: {
+      DCHECK(output_surface_);
+      context_provider_ = output_surface_->context_provider();
+      const auto& context_caps = context_provider_->ContextCapabilities();
+      use_swap_with_bounds_ = context_caps.swap_buffers_with_bounds;
+      if (context_caps.sync_query) {
+        sync_queries_ =
+            base::Optional<SyncQueryCollection>(context_provider_->ContextGL());
+      }
+      break;
+    }
+    case DrawMode::VULKAN: {
+      DCHECK(output_surface_);
+#if BUILDFLAG(ENABLE_VULKAN)
+      vulkan_context_provider_ = output_surface_->vulkan_context_provider();
+#endif
+      break;
+    }
+    case DrawMode::DDL: {
+      DCHECK(skia_output_surface_);
+      break;
     }
   }
 }
@@ -197,20 +213,21 @@
 SkiaRenderer::~SkiaRenderer() = default;
 
 bool SkiaRenderer::CanPartialSwap() {
-  if (IsUsingVulkan())
+  if (draw_mode_ != DrawMode::GL)
     return false;
+
+  DCHECK(context_provider_);
   if (use_swap_with_bounds_)
     return false;
-  auto* context_provider = output_surface_->context_provider();
-  return context_provider
-             ? context_provider->ContextCapabilities().post_sub_buffer
-             : false;
+
+  return context_provider_->ContextCapabilities().post_sub_buffer;
 }
 
 void SkiaRenderer::BeginDrawingFrame() {
   TRACE_EVENT0("viz", "SkiaRenderer::BeginDrawingFrame");
-  if (IsUsingVulkan() || is_using_ddl())
+  if (draw_mode_ != DrawMode::GL)
     return;
+
   // Copied from GLRenderer.
   scoped_refptr<ResourceFence> read_lock_fence;
   if (sync_queries_) {
@@ -218,7 +235,7 @@
   } else {
     read_lock_fence =
         base::MakeRefCounted<DisplayResourceProvider::SynchronousFence>(
-            output_surface_->context_provider()->ContextGL());
+            context_provider_->ContextGL());
   }
   resource_provider_->SetReadLockFence(read_lock_fence.get());
 
@@ -277,12 +294,14 @@
     output_frame.sub_buffer_rect = swap_buffer_rect_;
   }
 
-  if (is_using_ddl()) {
-    skia_output_surface_->SkiaSwapBuffers(std::move(output_frame));
-  } else {
-    // TODO(penghuang): remove it when SkiaRenderer and SkDDL are always used.
+  switch (draw_mode_) {
+    case DrawMode::DDL: {
+      skia_output_surface_->SkiaSwapBuffers(std::move(output_frame));
+      break;
+    }
+    case DrawMode::VULKAN: {
 #if BUILDFLAG(ENABLE_VULKAN)
-    if (IsUsingVulkan()) {
+      // TODO(penghuang): remove it when SkiaRenderer and SkDDL are always used.
       auto backend = root_surface_->getBackendRenderTarget(
           SkSurface::kFlushRead_BackendHandleAccess);
       GrVkImageInfo vk_image_info;
@@ -291,9 +310,12 @@
       auto* vulkan_surface = output_surface_->GetVulkanSurface();
       auto* swap_chain = vulkan_surface->GetSwapChain();
       swap_chain->SetCurrentImageLayout(vk_image_info.fImageLayout);
-    }
 #endif
-    output_surface_->SwapBuffers(std::move(output_frame));
+      break;
+    }
+    case DrawMode::GL: {
+      output_surface_->SwapBuffers(std::move(output_frame));
+    }
   }
 
   swap_buffer_rect_ = gfx::Rect();
@@ -323,12 +345,13 @@
 
   // TODO(weiliangc): Set up correct can_use_lcd_text for SkSurfaceProps flags.
   // How to setup is in ResourceProvider. (http://crbug.com/644851)
-  if (is_using_ddl()) {
-    root_canvas_ = skia_output_surface_->BeginPaintCurrentFrame();
-    DCHECK(root_canvas_);
-  } else {
-    auto* gr_context = GetGrContext();
-    if (IsUsingVulkan()) {
+  switch (draw_mode_) {
+    case DrawMode::DDL: {
+      root_canvas_ = skia_output_surface_->BeginPaintCurrentFrame();
+      DCHECK(root_canvas_);
+      break;
+    }
+    case DrawMode::VULKAN: {
 #if BUILDFLAG(ENABLE_VULKAN)
       auto* vulkan_surface = output_surface_->GetVulkanSurface();
       auto* swap_chain = vulkan_surface->GetSwapChain();
@@ -345,34 +368,43 @@
           current_frame()->device_viewport_size.width(),
           current_frame()->device_viewport_size.height(), 0, 0, vk_image_info);
       root_surface_ = SkSurface::MakeFromBackendRenderTarget(
-          gr_context, render_target, kTopLeft_GrSurfaceOrigin,
+          GetGrContext(), render_target, kTopLeft_GrSurfaceOrigin,
           kBGRA_8888_SkColorType, nullptr, &surface_props);
       DCHECK(root_surface_);
       root_canvas_ = root_surface_->getCanvas();
 #else
       NOTREACHED();
 #endif
-    } else if (!root_canvas_ || root_canvas_->getGrContext() != gr_context ||
-               gfx::SkISizeToSize(root_canvas_->getBaseLayerSize()) !=
-                   current_frame()->device_viewport_size) {
-      // Either no SkSurface setup yet, or new GrContext, need to create new
-      // surface.
-      GrGLFramebufferInfo framebuffer_info;
-      framebuffer_info.fFBOID = 0;
-      framebuffer_info.fFormat = GL_RGB8_OES;
-      GrBackendRenderTarget render_target(
-          current_frame()->device_viewport_size.width(),
-          current_frame()->device_viewport_size.height(), 0, 8,
-          framebuffer_info);
+      break;
+    }
+    case DrawMode::GL: {
+      auto* gr_context = GetGrContext();
+      if (!root_canvas_ || root_canvas_->getGrContext() != gr_context ||
+          gfx::SkISizeToSize(root_canvas_->getBaseLayerSize()) !=
+              current_frame()->device_viewport_size) {
+        // Either no SkSurface setup yet, or new GrContext, need to create new
+        // surface.
+        GrGLFramebufferInfo framebuffer_info;
+        framebuffer_info.fFBOID = 0;
+        framebuffer_info.fFormat = GL_RGB8_OES;
+        GrBackendRenderTarget render_target(
+            current_frame()->device_viewport_size.width(),
+            current_frame()->device_viewport_size.height(), 0, 8,
+            framebuffer_info);
 
-      root_surface_ = SkSurface::MakeFromBackendRenderTarget(
-          gr_context, render_target, kBottomLeft_GrSurfaceOrigin,
-          kRGB_888x_SkColorType, nullptr, &surface_props);
-      DCHECK(root_surface_);
-      root_canvas_ = root_surface_->getCanvas();
+        root_surface_ = SkSurface::MakeFromBackendRenderTarget(
+            gr_context, render_target, kBottomLeft_GrSurfaceOrigin,
+            kRGB_888x_SkColorType, nullptr, &surface_props);
+        DCHECK(root_surface_);
+        root_canvas_ = root_surface_->getCanvas();
+      }
+      break;
     }
   }
 
+  current_canvas_ = root_canvas_;
+  current_surface_ = root_surface_.get();
+
   if (settings_->show_overdraw_feedback) {
     const auto& size = current_frame()->device_viewport_size;
     overdraw_surface_ = root_canvas_->makeSurface(
@@ -384,9 +416,6 @@
     nway_canvas_->addCanvas(root_canvas_);
     current_canvas_ = nway_canvas_.get();
     current_surface_ = overdraw_surface_.get();
-  } else {
-    current_canvas_ = root_canvas_;
-    current_surface_ = root_surface_.get();
   }
 }
 
@@ -396,14 +425,19 @@
   // This function is called after AllocateRenderPassResourceIfNeeded, so there
   // should be backing ready.
   RenderPassBacking& backing = iter->second;
-  if (is_using_ddl()) {
-    non_root_surface_ = nullptr;
-    current_canvas_ = skia_output_surface_->BeginPaintRenderPass(
-        render_pass_id, backing.size, backing.format, backing.mipmap);
-  } else {
-    non_root_surface_ = backing.render_pass_surface;
-    current_surface_ = non_root_surface_.get();
-    current_canvas_ = non_root_surface_->getCanvas();
+  switch (draw_mode_) {
+    case DrawMode::DDL: {
+      non_root_surface_ = nullptr;
+      current_canvas_ = skia_output_surface_->BeginPaintRenderPass(
+          render_pass_id, backing.size, backing.format, backing.mipmap);
+      break;
+    }
+    case DrawMode::GL:  // Fallthrough
+    case DrawMode::VULKAN: {
+      non_root_surface_ = backing.render_pass_surface;
+      current_surface_ = non_root_surface_.get();
+      current_canvas_ = non_root_surface_->getCanvas();
+    }
   }
 }
 
@@ -462,17 +496,15 @@
   if (!current_canvas_)
     return;
   base::Optional<SkAutoCanvasRestore> auto_canvas_restore;
-  if (draw_region)
+  if (draw_region || is_scissor_enabled_) {
     auto_canvas_restore.emplace(current_canvas_, true /* do_save */);
-
+    if (is_scissor_enabled_)
+      current_canvas_->clipRect(gfx::RectToSkRect(scissor_rect_));
+  }
   TRACE_EVENT0("viz", "SkiaRenderer::DoDrawQuad");
-  gfx::Transform quad_rect_matrix;
-  QuadRectTransform(&quad_rect_matrix,
-                    quad->shared_quad_state->quad_to_target_transform,
-                    gfx::RectF(quad->rect));
   gfx::Transform contents_device_transform =
       current_frame()->window_matrix * current_frame()->projection_matrix *
-      quad_rect_matrix;
+      quad->shared_quad_state->quad_to_target_transform;
   contents_device_transform.FlattenTo2d();
   SkMatrix sk_device_matrix;
   gfx::TransformToFlattenedSkMatrix(contents_device_transform,
@@ -498,16 +530,9 @@
       static_cast<SkBlendMode>(quad->shared_quad_state->blend_mode));
 
   if (draw_region) {
-    gfx::QuadF local_draw_region(*draw_region);
     SkPath draw_region_clip_path;
-    local_draw_region -=
-        gfx::Vector2dF(quad->visible_rect.x(), quad->visible_rect.y());
-    local_draw_region.Scale(1.0f / quad->visible_rect.width(),
-                            1.0f / quad->visible_rect.height());
-    local_draw_region -= gfx::Vector2dF(0.5f, 0.5f);
-
     SkPoint clip_points[4];
-    QuadFToSkPoints(local_draw_region, clip_points);
+    QuadFToSkPoints(*draw_region, clip_points);
     draw_region_clip_path.addPoly(clip_points, 4, true);
 
     current_canvas_->clipPath(draw_region_clip_path);
@@ -538,12 +563,7 @@
       NOTREACHED();
       break;
     case DrawQuad::YUV_VIDEO_CONTENT:
-      if (is_using_ddl()) {
-        DrawYUVVideoQuad(YUVVideoDrawQuad::MaterialCast(quad));
-      } else {
-        DrawUnsupportedQuad(quad);
-        NOTIMPLEMENTED();
-      }
+      DrawYUVVideoQuad(YUVVideoDrawQuad::MaterialCast(quad));
       break;
     case DrawQuad::INVALID:
     case DrawQuad::STREAM_VIDEO_CONTENT:
@@ -558,7 +578,7 @@
 void SkiaRenderer::DrawDebugBorderQuad(const DebugBorderDrawQuad* quad) {
   // We need to apply the matrix manually to have pixel-sized stroke width.
   SkPoint vertices[4];
-  QuadVertexSkRect().toQuad(vertices);
+  gfx::RectToSkRect(quad->rect).toQuad(vertices);
   SkPoint transformed_vertices[4];
   current_canvas_->getTotalMatrix().mapPoints(transformed_vertices, vertices,
                                               4);
@@ -576,7 +596,8 @@
 void SkiaRenderer::DrawPictureQuad(const PictureDrawQuad* quad) {
   SkMatrix content_matrix;
   content_matrix.setRectToRect(gfx::RectFToSkRect(quad->tex_coord_rect),
-                               QuadVertexSkRect(), SkMatrix::kFill_ScaleToFit);
+                               gfx::RectToSkRect(quad->rect),
+                               SkMatrix::kFill_ScaleToFit);
   current_canvas_->concat(content_matrix);
 
   const bool needs_transparency =
@@ -618,12 +639,10 @@
 }
 
 void SkiaRenderer::DrawSolidColorQuad(const SolidColorDrawQuad* quad) {
-  gfx::RectF visible_quad_vertex_rect = cc::MathUtil::ScaleRectProportional(
-      QuadVertexRect(), gfx::RectF(quad->rect), gfx::RectF(quad->visible_rect));
   current_paint_.setColor(quad->color);
   current_paint_.setAlpha(quad->shared_quad_state->opacity *
                           SkColorGetA(quad->color));
-  current_canvas_->drawRect(gfx::RectFToSkRect(visible_quad_vertex_rect),
+  current_canvas_->drawRect(gfx::RectToSkRect(quad->visible_rect),
                             current_paint_);
 }
 
@@ -638,9 +657,7 @@
   gfx::RectF visible_uv_rect = cc::MathUtil::ScaleRectProportional(
       uv_rect, gfx::RectF(quad->rect), gfx::RectF(quad->visible_rect));
   SkRect sk_uv_rect = gfx::RectFToSkRect(visible_uv_rect);
-  gfx::RectF visible_quad_vertex_rect = cc::MathUtil::ScaleRectProportional(
-      QuadVertexRect(), gfx::RectF(quad->rect), gfx::RectF(quad->visible_rect));
-  SkRect quad_rect = gfx::RectFToSkRect(visible_quad_vertex_rect);
+  SkRect quad_rect = gfx::RectToSkRect(quad->visible_rect);
 
   if (quad->y_flipped)
     current_canvas_->scale(1, -1);
@@ -675,18 +692,20 @@
   gfx::RectF visible_tex_coord_rect = cc::MathUtil::ScaleRectProportional(
       quad->tex_coord_rect, gfx::RectF(quad->rect),
       gfx::RectF(quad->visible_rect));
-  gfx::RectF visible_quad_vertex_rect = cc::MathUtil::ScaleRectProportional(
-      QuadVertexRect(), gfx::RectF(quad->rect), gfx::RectF(quad->visible_rect));
 
   SkRect uv_rect = gfx::RectFToSkRect(visible_tex_coord_rect);
   current_paint_.setFilterQuality(
       quad->nearest_neighbor ? kNone_SkFilterQuality : kLow_SkFilterQuality);
-  current_canvas_->drawImageRect(image, uv_rect,
-                                 gfx::RectFToSkRect(visible_quad_vertex_rect),
-                                 &current_paint_);
+  current_canvas_->drawImageRect(
+      image, uv_rect, gfx::RectToSkRect(quad->visible_rect), &current_paint_);
 }
 
 void SkiaRenderer::DrawYUVVideoQuad(const YUVVideoDrawQuad* quad) {
+  if (draw_mode_ != DrawMode::DDL) {
+    NOTIMPLEMENTED();
+    return;
+  }
+
   DCHECK(resource_provider_);
   ScopedYUVSkImageBuilder builder(this, quad);
   const SkImage* image = builder.sk_image();
@@ -695,15 +714,12 @@
   gfx::RectF visible_tex_coord_rect = cc::MathUtil::ScaleRectProportional(
       quad->ya_tex_coord_rect, gfx::RectF(quad->rect),
       gfx::RectF(quad->visible_rect));
-  gfx::RectF visible_quad_vertex_rect = cc::MathUtil::ScaleRectProportional(
-      QuadVertexRect(), gfx::RectF(quad->rect), gfx::RectF(quad->visible_rect));
 
   SkRect uv_rect = gfx::RectFToSkRect(visible_tex_coord_rect);
   // TODO(penghuang): figure out how to set correct filter quality.
   current_paint_.setFilterQuality(kLow_SkFilterQuality);
-  current_canvas_->drawImageRect(image, uv_rect,
-                                 gfx::RectFToSkRect(visible_quad_vertex_rect),
-                                 &current_paint_);
+  current_canvas_->drawImageRect(
+      image, uv_rect, gfx::RectToSkRect(quad->visible_rect), &current_paint_);
 }
 
 bool SkiaRenderer::CalculateRPDQParams(sk_sp<SkImage> content,
@@ -773,7 +789,7 @@
 
 const TileDrawQuad* SkiaRenderer::CanPassBeDrawnDirectly(
     const RenderPass* pass) {
-  return DirectRenderer::CanPassBeDrawnDirectly(pass, IsUsingVulkan(),
+  return DirectRenderer::CanPassBeDrawnDirectly(pass, is_using_vulkan(),
                                                 resource_provider_);
 }
 
@@ -792,11 +808,19 @@
     // there should be backing ready.
     RenderPassBacking& backing = iter->second;
 
-    sk_sp<SkImage> content_image =
-        is_using_ddl() ? skia_output_surface_->MakePromiseSkImageFromRenderPass(
-                             quad->render_pass_id, backing.size, backing.format,
-                             backing.mipmap)
-                       : backing.render_pass_surface->makeImageSnapshot();
+    sk_sp<SkImage> content_image;
+    switch (draw_mode_) {
+      case DrawMode::DDL: {
+        content_image = skia_output_surface_->MakePromiseSkImageFromRenderPass(
+            quad->render_pass_id, backing.size, backing.format, backing.mipmap);
+        break;
+      }
+      case DrawMode::GL:  // Fallthrough
+      case DrawMode::VULKAN: {
+        content_image = backing.render_pass_surface->makeImageSnapshot();
+      }
+    }
+
     DrawRenderPassQuadInternal(quad, content_image);
   }
 }
@@ -814,14 +838,11 @@
   SkRect dest_visible_rect;
   if (params.filter_image) {
     content_rect = RectFToSkRect(params.tex_coord_rect);
-    dest_visible_rect = gfx::RectFToSkRect(cc::MathUtil::ScaleRectProportional(
-        QuadVertexRect(), gfx::RectF(quad->rect), gfx::RectF(params.dst_rect)));
+    dest_visible_rect = gfx::RectFToSkRect(params.dst_rect);
     content_image = params.filter_image;
   } else {
     content_rect = RectFToSkRect(quad->tex_coord_rect);
-    dest_visible_rect = gfx::RectFToSkRect(cc::MathUtil::ScaleRectProportional(
-        QuadVertexRect(), gfx::RectF(quad->rect),
-        gfx::RectF(quad->visible_rect)));
+    dest_visible_rect = gfx::RectToSkRect(quad->visible_rect);
   }
 
   // Prepare mask.
@@ -835,7 +856,7 @@
     SkRect mask_rect = gfx::RectFToSkRect(
         gfx::ScaleRect(quad->mask_uv_rect, quad->mask_texture_size.width(),
                        quad->mask_texture_size.height()));
-    mask_to_dest_matrix.setRectToRect(mask_rect, QuadVertexSkRect(),
+    mask_to_dest_matrix.setRectToRect(mask_rect, gfx::RectToSkRect(quad->rect),
                                       SkMatrix::kFill_ScaleToFit);
     mask_filter =
         SkShaderMaskFilter::Make(mask_image->makeShader(&mask_to_dest_matrix));
@@ -859,7 +880,8 @@
     // Convert the content_image to a shader, and use drawRect() with the
     // shader.
     SkMatrix content_to_dest_matrix;
-    content_to_dest_matrix.setRectToRect(content_rect, QuadVertexSkRect(),
+    content_to_dest_matrix.setRectToRect(content_rect,
+                                         gfx::RectToSkRect(quad->rect),
                                          SkMatrix::kFill_ScaleToFit);
     auto shader = content_image->makeShader(&content_to_dest_matrix);
     current_paint_.setShader(std::move(shader));
@@ -876,8 +898,8 @@
                               : nullptr;
   DCHECK(background_image_filter);
   SkMatrix content_to_dest_matrix;
-  content_to_dest_matrix.setRectToRect(content_rect, QuadVertexSkRect(),
-                                       SkMatrix::kFill_ScaleToFit);
+  content_to_dest_matrix.setRectToRect(
+      content_rect, gfx::RectToSkRect(quad->rect), SkMatrix::kFill_ScaleToFit);
   SkMatrix local_matrix;
   local_matrix.setTranslate(quad->filters_origin.x(), quad->filters_origin.y());
   local_matrix.postScale(quad->filters_scale.x(), quad->filters_scale.y());
@@ -886,7 +908,7 @@
       background_image_filter->makeWithLocalMatrix(local_matrix);
 
   SkAutoCanvasRestore auto_canvas_restore(current_canvas_, true /* do_save */);
-  current_canvas_->clipRect(QuadVertexSkRect());
+  current_canvas_->clipRect(gfx::RectToSkRect(quad->rect));
 
   SkPaint paint;
   paint.setMaskFilter(mask_filter);
@@ -913,7 +935,7 @@
   current_paint_.setColor(SK_ColorMAGENTA);
 #endif
   current_paint_.setAlpha(quad->shared_quad_state->opacity * 255);
-  current_canvas_->drawRect(QuadVertexSkRect(), current_paint_);
+  current_canvas_->drawRect(gfx::RectToSkRect(quad->rect), current_paint_);
 }
 
 void SkiaRenderer::CopyDrawnRenderPass(
@@ -940,28 +962,36 @@
     return;
   }
 
-  if (is_using_ddl()) {
-    // Root framebuffer uses id 0 in SkiaOutputSurface.
-    RenderPassId render_pass_id = 0;
-    // If we are in child render pass and we don't have overdraw, copy the
-    // current render pass.
-    if (root_canvas_ != current_canvas_ &&
-        current_canvas_ != nway_canvas_.get()) {
-      render_pass_id = current_frame()->current_render_pass->id;
+  switch (draw_mode_) {
+    case DrawMode::DDL: {
+      if (settings_->show_overdraw_feedback) {
+        // TODO(crbug.com/889122): Overdraw currently requires calling flush on
+        // canvas on SkiaRenderer's thread.
+        return;
+      }
+      // Root framebuffer uses id 0 in SkiaOutputSurface.
+      RenderPassId render_pass_id = 0;
+      // If we are in child render pass and we don't have overdraw, copy the
+      // current render pass.
+      if (root_canvas_ != current_canvas_)
+        render_pass_id = current_frame()->current_render_pass->id;
+      skia_output_surface_->CopyOutput(render_pass_id, window_copy_rect,
+                                       std::move(request));
+      break;
     }
-    skia_output_surface_->CopyOutput(render_pass_id, window_copy_rect,
-                                     std::move(request));
-    return;
+    case DrawMode::GL:  // Fallthrough
+    case DrawMode::VULKAN: {
+      sk_sp<SkImage> copy_image =
+          current_surface_->makeImageSnapshot()->makeSubset(
+              RectToSkIRect(window_copy_rect));
+
+      // Send copy request by copying into a bitmap.
+      SkBitmap bitmap;
+      copy_image->asLegacyBitmap(&bitmap);
+      request->SendResult(
+          std::make_unique<CopyOutputSkBitmapResult>(copy_rect, bitmap));
+    }
   }
-
-  sk_sp<SkImage> copy_image = current_surface_->makeImageSnapshot()->makeSubset(
-      RectToSkIRect(window_copy_rect));
-
-  // Send copy request by copying into a bitmap.
-  SkBitmap bitmap;
-  copy_image->asLegacyBitmap(&bitmap);
-  request->SendResult(
-      std::make_unique<CopyOutputSkBitmapResult>(copy_rect, bitmap));
 }
 
 void SkiaRenderer::SetEnableDCLayers(bool enable) {
@@ -977,13 +1007,19 @@
 }
 
 void SkiaRenderer::FinishDrawingQuadList() {
-  if (is_using_ddl()) {
-    gpu::SyncToken sync_token = skia_output_surface_->SubmitPaint();
-    promise_images_.clear();
-    yuv_promise_images_.clear();
-    lock_set_for_external_use_.UnlockResources(sync_token);
-  } else {
-    current_canvas_->flush();
+  switch (draw_mode_) {
+    case DrawMode::DDL: {
+      gpu::SyncToken sync_token = skia_output_surface_->SubmitPaint();
+      promise_images_.clear();
+      yuv_promise_images_.clear();
+      lock_set_for_external_use_.UnlockResources(sync_token);
+      break;
+    }
+    case DrawMode::GL:  // Fallthrough
+    case DrawMode::VULKAN: {
+      current_canvas_->flush();
+      break;
+    }
   }
 }
 
@@ -1005,21 +1041,20 @@
   return true;
 }
 
-bool SkiaRenderer::IsUsingVulkan() const {
-#if BUILDFLAG(ENABLE_VULKAN)
-  if (output_surface_->vulkan_context_provider())
-    return output_surface_->vulkan_context_provider()->GetGrContext();
-#endif
-  return false;
-}
-
 GrContext* SkiaRenderer::GetGrContext() {
-  DCHECK(!is_using_ddl());
+  switch (draw_mode_) {
+    case DrawMode::DDL:
+      return nullptr;
+    case DrawMode::VULKAN:
 #if BUILDFLAG(ENABLE_VULKAN)
-  if (output_surface_->vulkan_context_provider())
-    return output_surface_->vulkan_context_provider()->GetGrContext();
+      return vulkan_context_provider_->GetGrContext();
+#else
+      NOTREACHED();
+      return nullptr;
 #endif
-  return output_surface_->context_provider()->GrContext();
+    case DrawMode::GL:
+      return context_provider_->GrContext();
+  }
 }
 
 void SkiaRenderer::UpdateRenderPassTextures(
@@ -1065,20 +1100,21 @@
   // TODO(penghuang): check supported format correctly.
   gpu::Capabilities caps;
   caps.texture_format_bgra8888 = true;
-  GrContext* gr_context = nullptr;
-  if (!is_using_ddl()) {
-    if (IsUsingVulkan()) {
+  GrContext* gr_context = GetGrContext();
+  switch (draw_mode_) {
+    case DrawMode::DDL:
+      break;
+    case DrawMode::VULKAN: {
       // TODO(penghuang): check supported format correctly.
       caps.texture_format_bgra8888 = true;
-    } else {
-      ContextProvider* context_provider = output_surface_->context_provider();
-      if (context_provider) {
-        caps.texture_format_bgra8888 =
-            context_provider->ContextCapabilities().texture_format_bgra8888;
-      }
+      break;
     }
-    gr_context = GetGrContext();
+    case DrawMode::GL: {
+      caps.texture_format_bgra8888 =
+          context_provider_->ContextCapabilities().texture_format_bgra8888;
+    }
   }
+
   render_pass_backings_.insert(std::pair<RenderPassId, RenderPassBacking>(
       render_pass_id,
       RenderPassBacking(gr_context, caps, requirements.size,
diff --git a/components/viz/service/display/skia_renderer.h b/components/viz/service/display/skia_renderer.h
index 05318a8..b96d21f 100644
--- a/components/viz/service/display/skia_renderer.h
+++ b/components/viz/service/display/skia_renderer.h
@@ -12,6 +12,7 @@
 #include "components/viz/service/display/direct_renderer.h"
 #include "components/viz/service/display/sync_query_collection.h"
 #include "components/viz/service/viz_service_export.h"
+#include "gpu/vulkan/buildflags.h"
 #include "ui/latency/latency_info.h"
 
 class SkNWayCanvas;
@@ -27,15 +28,20 @@
 class SolidColorDrawQuad;
 class TextureDrawQuad;
 class TileDrawQuad;
+class VulkanContextProvider;
 class YUVVideoDrawQuad;
 
 class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer {
  public:
+  // Different draw modes that are supported by SkiaRenderer right now.
+  enum DrawMode { GL, DDL, VULKAN };
+
   // TODO(penghuang): Remove skia_output_surface when DDL is used everywhere.
   SkiaRenderer(const RendererSettings* settings,
                OutputSurface* output_surface,
                DisplayResourceProvider* resource_provider,
-               SkiaOutputSurface* skia_output_surface);
+               SkiaOutputSurface* skia_output_surface,
+               DrawMode mode);
   ~SkiaRenderer() override;
 
   void SwapBuffers(std::vector<ui::LatencyInfo> latency_info,
@@ -101,10 +107,7 @@
       const RenderPassDrawQuad* quad,
       const cc::FilterOperations* background_filters) const;
   bool IsUsingVulkan() const;
-  GrContext* GetGrContext();
-  bool is_using_ddl() const { return !!skia_output_surface_; }
   const TileDrawQuad* CanPassBeDrawnDirectly(const RenderPass* pass) override;
-  const SkRect& QuadVertexSkRect() const { return quad_vertex_skrect_; }
 
   // A map from RenderPass id to the texture used to draw the RenderPass from.
   struct RenderPassBacking {
@@ -124,29 +127,46 @@
   };
   base::flat_map<RenderPassId, RenderPassBacking> render_pass_backings_;
 
-  SkiaOutputSurface* const skia_output_surface_ = nullptr;
-  bool disable_picture_quad_image_filtering_ = false;
-  bool is_scissor_enabled_ = false;
+  const DrawMode draw_mode_;
 
-  gfx::Rect scissor_rect_;
+  // Get corresponding GrContext in DrawMode::GL or DrawMode::VULKAN. Returns
+  // nullptr when there is no GrContext.
+  GrContext* GetGrContext();
+  bool is_using_ddl() const { return draw_mode_ == DrawMode::DDL; }
+  bool is_using_vulkan() const { return draw_mode_ == DrawMode::VULKAN; }
 
+  // Interface used for drawing. Common among different draw modes.
   sk_sp<SkSurface> root_surface_;
   sk_sp<SkSurface> non_root_surface_;
-  sk_sp<SkSurface> overdraw_surface_;
-  std::unique_ptr<SkCanvas> overdraw_canvas_;
-  std::unique_ptr<SkNWayCanvas> nway_canvas_;
   SkCanvas* root_canvas_ = nullptr;
   SkCanvas* current_canvas_ = nullptr;
   SkSurface* current_surface_ = nullptr;
-  SkPaint current_paint_;
-  const SkRect quad_vertex_skrect_;
 
+  bool disable_picture_quad_image_filtering_ = false;
+  bool is_scissor_enabled_ = false;
+  gfx::Rect scissor_rect_;
+  SkPaint current_paint_;
+
+  // Specific for overdraw.
+  sk_sp<SkSurface> overdraw_surface_;
+  std::unique_ptr<SkCanvas> overdraw_canvas_;
+  std::unique_ptr<SkNWayCanvas> nway_canvas_;
+
+  // Specific for GL.
+  ContextProvider* context_provider_ = nullptr;
   base::Optional<SyncQueryCollection> sync_queries_;
   bool use_swap_with_bounds_ = false;
-
   gfx::Rect swap_buffer_rect_;
   std::vector<gfx::Rect> swap_content_bounds_;
 
+// Specific for Vulkan.
+#if BUILDFLAG(ENABLE_VULKAN)
+  VulkanContextProvider* vulkan_context_provider_ = nullptr;
+#endif
+
+  // Specific for SkDDL.
+  SkiaOutputSurface* const skia_output_surface_ = nullptr;
+
   // Lock set for resources that are used for the current frame. All resources
   // in this set will be unlocked with a sync token when the frame is done in
   // the compositor thread. And the sync token will be released when the DDL
@@ -159,7 +179,6 @@
   // |lock_set_for_external_use_| are unlocked on the compositor thread.
   // It is only used with DDL.
   base::flat_map<ResourceId, sk_sp<SkImage>> promise_images_;
-
   using YUVIds = std::tuple<ResourceId, ResourceId, ResourceId, ResourceId>;
   base::flat_map<YUVIds, sk_sp<SkImage>> yuv_promise_images_;
 
diff --git a/components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.cc b/components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.cc
index c938519a..9e99733 100644
--- a/components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.cc
+++ b/components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.cc
@@ -4,10 +4,43 @@
 
 #include "components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.h"
 
+#include "components/viz/service/display/overlay_strategy_single_on_top.h"
+#include "components/viz/service/display/overlay_strategy_underlay.h"
 #include "components/viz/service/display_embedder/compositor_overlay_candidate_validator_android.h"
 #include "third_party/khronos/GLES2/gl2.h"
+#include "ui/gfx/geometry/rect_conversions.h"
 
 namespace viz {
+namespace {
+class OverlayCandidateValidatorImpl : public OverlayCandidateValidator {
+ public:
+  OverlayCandidateValidatorImpl() = default;
+  ~OverlayCandidateValidatorImpl() override = default;
+
+  void GetStrategies(OverlayProcessor::StrategyList* strategies) override {
+    strategies->push_back(std::make_unique<OverlayStrategyUnderlay>(
+        this, OverlayStrategyUnderlay::OpaqueMode::AllowTransparentCandidates));
+  }
+  bool AllowCALayerOverlays() override { return false; }
+  bool AllowDCLayerOverlays() override { return false; }
+  void CheckOverlaySupport(OverlayCandidateList* surfaces) override {
+    DCHECK(!surfaces->empty());
+
+    // Only update the last candidate that was added to the list. All previous
+    // overlays should have already been handled.
+    auto& candidate = surfaces->back();
+    candidate.display_rect =
+        gfx::RectF(gfx::ToEnclosingRect(candidate.display_rect));
+    candidate.overlay_handled = true;
+
+#if DCHECK_IS_ON()
+    for (auto& candidate : *surfaces)
+      DCHECK(candidate.overlay_handled);
+#endif
+  }
+};
+
+}  // namespace
 
 GLOutputSurfaceBufferQueueAndroid::GLOutputSurfaceBufferQueueAndroid(
     scoped_refptr<VizProcessContextProvider> context_provider,
@@ -23,7 +56,7 @@
                                  GL_RGBA,
                                  buffer_format),
       overlay_candidate_validator_(
-          std::make_unique<CompositorOverlayCandidateValidatorAndroid>()) {}
+          std::make_unique<OverlayCandidateValidatorImpl>()) {}
 
 GLOutputSurfaceBufferQueueAndroid::~GLOutputSurfaceBufferQueueAndroid() =
     default;
diff --git a/content/browser/cache_storage/cache_storage_blob_to_disk_cache.cc b/content/browser/cache_storage/cache_storage_blob_to_disk_cache.cc
index 3a727b7..dbfaccf 100644
--- a/content/browser/cache_storage/cache_storage_blob_to_disk_cache.cc
+++ b/content/browser/cache_storage/cache_storage_blob_to_disk_cache.cc
@@ -40,15 +40,19 @@
   DCHECK(!consumer_handle_.is_valid());
   DCHECK(!pending_read_);
 
-  mojo::DataPipe pipe(blink::BlobUtils::GetDataPipeCapacity(blob_size));
+  MojoCreateDataPipeOptions options;
+  options.struct_size = sizeof(MojoCreateDataPipeOptions);
+  options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE;
+  options.element_num_bytes = 1;
+  options.capacity_num_bytes = blink::BlobUtils::GetDataPipeCapacity(blob_size);
 
-  if (!pipe.consumer_handle.is_valid()) {
+  mojo::ScopedDataPipeProducerHandle producer_handle;
+  MojoResult rv =
+      mojo::CreateDataPipe(&options, &producer_handle, &consumer_handle_);
+  if (rv != MOJO_RESULT_OK) {
     std::move(callback).Run(std::move(entry), false /* success */);
     return;
   }
-  DCHECK(pipe.producer_handle.is_valid());
-
-  consumer_handle_ = std::move(pipe.consumer_handle);
 
   disk_cache_body_index_ = disk_cache_body_index;
   entry_ = std::move(entry);
@@ -56,7 +60,7 @@
 
   blink::mojom::BlobReaderClientPtr client;
   client_binding_.Bind(MakeRequest(&client));
-  blob->ReadAll(std::move(pipe.producer_handle), std::move(client));
+  blob->ReadAll(std::move(producer_handle), std::move(client));
 
   handle_watcher_.Watch(
       consumer_handle_.get(), MOJO_HANDLE_SIGNAL_READABLE,
diff --git a/content/browser/devtools/protocol/page_handler.cc b/content/browser/devtools/protocol/page_handler.cc
index 5f2d301..2f0ea69 100644
--- a/content/browser/devtools/protocol/page_handler.cc
+++ b/content/browser/devtools/protocol/page_handler.cc
@@ -188,7 +188,8 @@
 
 }  // namespace
 
-PageHandler::PageHandler(EmulationHandler* emulation_handler)
+PageHandler::PageHandler(EmulationHandler* emulation_handler,
+                         bool allow_set_download_behavior)
     : DevToolsDomainHandler(Page::Metainfo::domainName),
       enabled_(false),
       screencast_enabled_(false),
@@ -205,6 +206,7 @@
       last_surface_size_(gfx::Size()),
       host_(nullptr),
       emulation_handler_(emulation_handler),
+      allow_set_download_behavior_(allow_set_download_behavior),
       observer_(this),
       weak_factory_(this) {
   bool create_video_consumer = true;
@@ -855,6 +857,9 @@
 
 Response PageHandler::SetDownloadBehavior(const std::string& behavior,
                                           Maybe<std::string> download_path) {
+  if (!allow_set_download_behavior_)
+    return Response::Error("Not allowed.");
+
   WebContentsImpl* web_contents = GetWebContents();
   if (!web_contents)
     return Response::InternalError();
diff --git a/content/browser/devtools/protocol/page_handler.h b/content/browser/devtools/protocol/page_handler.h
index ea8e3b1..ba523ccc 100644
--- a/content/browser/devtools/protocol/page_handler.h
+++ b/content/browser/devtools/protocol/page_handler.h
@@ -58,7 +58,7 @@
                     public Page::Backend,
                     public RenderWidgetHostObserver {
  public:
-  explicit PageHandler(EmulationHandler* handler);
+  PageHandler(EmulationHandler* handler, bool allow_set_download_behavior);
   ~PageHandler() override;
 
   static std::vector<PageHandler*> EnabledForWebContents(
@@ -212,6 +212,7 @@
 
   RenderFrameHostImpl* host_;
   EmulationHandler* emulation_handler_;
+  bool allow_set_download_behavior_;
   std::unique_ptr<Page::Frontend> frontend_;
   ScopedObserver<RenderWidgetHost, RenderWidgetHostObserver> observer_;
   JavaScriptDialogCallback pending_dialog_;
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc
index 435f38d..ff0a598 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -457,8 +457,8 @@
           ? protocol::TargetHandler::AccessMode::kRegular
           : protocol::TargetHandler::AccessMode::kAutoAttachOnly,
       GetId(), registry)));
-  session->AddHandler(
-      base::WrapUnique(new protocol::PageHandler(emulation_handler)));
+  session->AddHandler(base::WrapUnique(new protocol::PageHandler(
+      emulation_handler, session->client()->MayAffectLocalFiles())));
   session->AddHandler(base::WrapUnique(new protocol::SecurityHandler()));
   if (!frame_tree_node_ || !frame_tree_node_->parent()) {
     session->AddHandler(base::WrapUnique(
diff --git a/content/browser/indexed_db/indexed_db_backing_store.cc b/content/browser/indexed_db/indexed_db_backing_store.cc
index bea395b..413adf0 100644
--- a/content/browser/indexed_db/indexed_db_backing_store.cc
+++ b/content/browser/indexed_db/indexed_db_backing_store.cc
@@ -571,7 +571,6 @@
     IndexedDBFactory* indexed_db_factory,
     const Origin& origin,
     const FilePath& blob_path,
-    scoped_refptr<net::URLRequestContextGetter> request_context_getter,
     std::unique_ptr<LevelDBDatabase> db,
     std::unique_ptr<LevelDBComparator> comparator,
     base::SequencedTaskRunner* task_runner)
@@ -579,7 +578,6 @@
       origin_(origin),
       blob_path_(blob_path),
       origin_identifier_(ComputeOriginIdentifier(origin)),
-      request_context_getter_(request_context_getter),
       task_runner_(task_runner),
       db_(std::move(db)),
       comparator_(std::move(comparator)),
@@ -622,7 +620,6 @@
     IndexedDBFactory* indexed_db_factory,
     const Origin& origin,
     const FilePath& path_base,
-    scoped_refptr<net::URLRequestContextGetter> request_context,
     IndexedDBDataLossInfo* data_loss_info,
     bool* disk_full,
     base::SequencedTaskRunner* task_runner,
@@ -630,8 +627,8 @@
     Status* status) {
   DefaultLevelDBFactory leveldb_factory;
   return IndexedDBBackingStore::Open(
-      indexed_db_factory, origin, path_base, request_context, data_loss_info,
-      disk_full, &leveldb_factory, task_runner, clean_journal, status);
+      indexed_db_factory, origin, path_base, data_loss_info, disk_full,
+      &leveldb_factory, task_runner, clean_journal, status);
 }
 
 Status IndexedDBBackingStore::DestroyBackingStore(const FilePath& path_base,
@@ -969,7 +966,6 @@
     IndexedDBFactory* indexed_db_factory,
     const Origin& origin,
     const FilePath& path_base,
-    scoped_refptr<net::URLRequestContextGetter> request_context_getter,
     IndexedDBDataLossInfo* data_loss_info,
     bool* is_disk_full,
     LevelDBFactory* leveldb_factory,
@@ -1105,8 +1101,8 @@
           base::trace_event::MemoryDumpProvider::Options());
 
   scoped_refptr<IndexedDBBackingStore> backing_store =
-      Create(indexed_db_factory, origin, blob_path, request_context_getter,
-             std::move(db), std::move(comparator), task_runner, status);
+      Create(indexed_db_factory, origin, blob_path, std::move(db),
+             std::move(comparator), task_runner, status);
 
   if (clean_journal && backing_store.get()) {
     *status = backing_store->CleanUpBlobJournal(LiveBlobJournalKey::Encode());
@@ -1156,8 +1152,7 @@
           base::trace_event::MemoryDumpProvider::Options());
 
   return Create(nullptr /* indexed_db_factory */, origin, FilePath(),
-                nullptr /* request_context */, std::move(db),
-                std::move(comparator), task_runner, status);
+                std::move(db), std::move(comparator), task_runner, status);
 }
 
 // static
@@ -1165,14 +1160,13 @@
     IndexedDBFactory* indexed_db_factory,
     const Origin& origin,
     const FilePath& blob_path,
-    scoped_refptr<net::URLRequestContextGetter> request_context,
     std::unique_ptr<LevelDBDatabase> db,
     std::unique_ptr<LevelDBComparator> comparator,
     base::SequencedTaskRunner* task_runner,
     Status* status) {
   // TODO(jsbell): Handle comparator name changes.
   scoped_refptr<IndexedDBBackingStore> backing_store(new IndexedDBBackingStore(
-      indexed_db_factory, origin, blob_path, request_context, std::move(db),
+      indexed_db_factory, origin, blob_path, std::move(db),
       std::move(comparator), task_runner));
   *status = backing_store->SetUpMetadata();
   if (!status->ok())
diff --git a/content/browser/indexed_db/indexed_db_backing_store.h b/content/browser/indexed_db/indexed_db_backing_store.h
index 95f0147e..5da4da7d 100644
--- a/content/browser/indexed_db/indexed_db_backing_store.h
+++ b/content/browser/indexed_db/indexed_db_backing_store.h
@@ -50,10 +50,6 @@
 class FileWriterDelegate;
 }
 
-namespace net {
-class URLRequestContextGetter;
-}
-
 namespace content {
 
 class IndexedDBFactory;
@@ -406,7 +402,6 @@
       IndexedDBFactory* indexed_db_factory,
       const url::Origin& origin,
       const base::FilePath& path_base,
-      scoped_refptr<net::URLRequestContextGetter> request_context_getter,
       IndexedDBDataLossInfo* data_loss_info,
       bool* disk_full,
       base::SequencedTaskRunner* task_runner,
@@ -416,7 +411,6 @@
       IndexedDBFactory* indexed_db_factory,
       const url::Origin& origin,
       const base::FilePath& path_base,
-      scoped_refptr<net::URLRequestContextGetter> request_context_getter,
       IndexedDBDataLossInfo* data_loss_info,
       bool* disk_full,
       LevelDBFactory* leveldb_factory,
@@ -602,7 +596,6 @@
       IndexedDBFactory* indexed_db_factory,
       const url::Origin& origin,
       const base::FilePath& blob_path,
-      scoped_refptr<net::URLRequestContextGetter> request_context_getter,
       std::unique_ptr<LevelDBDatabase> db,
       std::unique_ptr<LevelDBComparator> comparator,
       base::SequencedTaskRunner* task_runner);
@@ -647,7 +640,6 @@
       IndexedDBFactory* indexed_db_factory,
       const url::Origin& origin,
       const base::FilePath& blob_path,
-      scoped_refptr<net::URLRequestContextGetter> request_context_getter,
       std::unique_ptr<LevelDBDatabase> db,
       std::unique_ptr<LevelDBComparator> comparator,
       base::SequencedTaskRunner* task_runner,
@@ -697,7 +689,6 @@
   // provides for future flexibility.
   const std::string origin_identifier_;
 
-  scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
   std::set<int> child_process_ids_granted_;
   std::map<std::string, std::unique_ptr<BlobChangeRecord>> incognito_blob_map_;
diff --git a/content/browser/indexed_db/indexed_db_backing_store_unittest.cc b/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
index d423c62..c9d7084 100644
--- a/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
@@ -30,7 +30,6 @@
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_utils.h"
-#include "net/url_request/url_request_test_util.h"
 #include "storage/browser/blob/blob_data_builder.h"
 #include "storage/browser/blob/blob_data_handle.h"
 #include "storage/browser/blob/blob_storage_context.h"
@@ -95,7 +94,6 @@
       IndexedDBFactory* indexed_db_factory,
       const Origin& origin,
       const base::FilePath& path_base,
-      scoped_refptr<net::URLRequestContextGetter> request_context_getter,
       LevelDBFactory* leveldb_factory,
       base::SequencedTaskRunner* task_runner,
       leveldb::Status* status) {
@@ -122,8 +120,8 @@
 
     scoped_refptr<TestableIndexedDBBackingStore> backing_store(
         new TestableIndexedDBBackingStore(indexed_db_factory, origin, blob_path,
-                                          request_context_getter, std::move(db),
-                                          std::move(comparator), task_runner));
+                                          std::move(db), std::move(comparator),
+                                          task_runner));
 
     *status = backing_store->SetUpMetadata();
     if (!status->ok())
@@ -180,14 +178,12 @@
       IndexedDBFactory* indexed_db_factory,
       const Origin& origin,
       const base::FilePath& blob_path,
-      scoped_refptr<net::URLRequestContextGetter> request_context_getter,
       std::unique_ptr<LevelDBDatabase> db,
       std::unique_ptr<LevelDBComparator> comparator,
       base::SequencedTaskRunner* task_runner)
       : IndexedDBBackingStore(indexed_db_factory,
                               origin,
                               blob_path,
-                              request_context_getter,
                               std::move(db),
                               std::move(comparator),
                               task_runner),
@@ -209,14 +205,12 @@
       : IndexedDBFactoryImpl(idb_context, base::DefaultClock::GetInstance()) {}
 
   scoped_refptr<TestableIndexedDBBackingStore> OpenBackingStoreForTest(
-      const Origin& origin,
-      scoped_refptr<net::URLRequestContextGetter> url_request_context_getter) {
+      const Origin& origin) {
     IndexedDBDataLossInfo data_loss_info;
     bool disk_full;
     leveldb::Status status;
     scoped_refptr<IndexedDBBackingStore> backing_store = OpenBackingStore(
-        origin, context()->data_path(), url_request_context_getter,
-        &data_loss_info, &disk_full, &status);
+        origin, context()->data_path(), &data_loss_info, &disk_full, &status);
     scoped_refptr<TestableIndexedDBBackingStore> testable_store =
         static_cast<TestableIndexedDBBackingStore*>(backing_store.get());
     return testable_store;
@@ -228,15 +222,14 @@
   scoped_refptr<IndexedDBBackingStore> OpenBackingStoreHelper(
       const Origin& origin,
       const base::FilePath& data_directory,
-      scoped_refptr<net::URLRequestContextGetter> request_context_getter,
       IndexedDBDataLossInfo* data_loss_info,
       bool* disk_full,
       bool first_time,
       leveldb::Status* status) override {
     DefaultLevelDBFactory leveldb_factory;
-    return TestableIndexedDBBackingStore::Open(
-        this, origin, data_directory, request_context_getter, &leveldb_factory,
-        context()->TaskRunner(), status);
+    return TestableIndexedDBBackingStore::Open(this, origin, data_directory,
+                                               &leveldb_factory,
+                                               context()->TaskRunner(), status);
   }
 
  private:
@@ -246,11 +239,7 @@
 class IndexedDBBackingStoreTest : public testing::Test {
  public:
   IndexedDBBackingStoreTest()
-      : url_request_context_getter_(
-            base::MakeRefCounted<net::TestURLRequestContextGetter>(
-                base::CreateSingleThreadTaskRunnerWithTraits(
-                    {BrowserThread::UI}))),
-        special_storage_policy_(
+      : special_storage_policy_(
             base::MakeRefCounted<MockSpecialStoragePolicy>()),
         quota_manager_proxy_(
             base::MakeRefCounted<MockQuotaManagerProxy>(nullptr, nullptr)) {}
@@ -265,8 +254,7 @@
               test->idb_factory_ = base::MakeRefCounted<TestIDBFactory>(
                   test->idb_context_.get());
               test->backing_store_ =
-                  test->idb_factory_->OpenBackingStoreForTest(
-                      origin, test->url_request_context_getter_);
+                  test->idb_factory_->OpenBackingStoreForTest(origin);
             },
             base::Unretained(this)));
     RunAllTasksUntilIdle();
@@ -319,11 +307,9 @@
   IndexedDBValue value2_;
 
  protected:
-  // Must be initialized before url_request_context_getter_
   TestBrowserThreadBundle thread_bundle_;
 
   base::ScopedTempDir temp_dir_;
-  scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
   scoped_refptr<MockSpecialStoragePolicy> special_storage_policy_;
   scoped_refptr<MockQuotaManagerProxy> quota_manager_proxy_;
   scoped_refptr<IndexedDBContextImpl> idb_context_;
diff --git a/content/browser/indexed_db/indexed_db_cleanup_on_io_error_unittest.cc b/content/browser/indexed_db/indexed_db_cleanup_on_io_error_unittest.cc
index 0c702bf..5f730766 100644
--- a/content/browser/indexed_db/indexed_db_cleanup_on_io_error_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_cleanup_on_io_error_unittest.cc
@@ -14,7 +14,6 @@
 #include "content/browser/indexed_db/indexed_db_data_loss_info.h"
 #include "content/browser/indexed_db/leveldb/leveldb_database.h"
 #include "content/browser/indexed_db/leveldb/mock_leveldb_factory.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/leveldatabase/env_chromium.h"
@@ -86,7 +85,6 @@
   base::ScopedTempDir temp_directory;
   ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
   const base::FilePath path = temp_directory.GetPath();
-  scoped_refptr<net::URLRequestContextGetter> request_context_getter;
 
   BustedLevelDBFactory busted_factory;
   content::MockLevelDBFactory mock_leveldb_factory;
@@ -103,15 +101,14 @@
   bool clean_journal = false;
   leveldb::Status s;
   scoped_refptr<IndexedDBBackingStore> backing_store =
-      IndexedDBBackingStore::Open(
-          factory, origin, path, request_context_getter, &data_loss_info,
-          &disk_full, &mock_leveldb_factory, task_runner, clean_journal, &s);
+      IndexedDBBackingStore::Open(factory, origin, path, &data_loss_info,
+                                  &disk_full, &mock_leveldb_factory,
+                                  task_runner, clean_journal, &s);
 }
 
 TEST(IndexedDBNonRecoverableIOErrorTest, NuancedCleanupTest) {
   content::IndexedDBFactory* factory = nullptr;
   const url::Origin origin = url::Origin::Create(GURL("http://localhost:81"));
-  scoped_refptr<net::URLRequestContextGetter> request_context_getter;
   base::ScopedTempDir temp_directory;
   ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
   const base::FilePath path = temp_directory.GetPath();
@@ -135,9 +132,9 @@
                                           leveldb_env::kNewLogger,
                                           base::File::FILE_ERROR_NO_SPACE));
   scoped_refptr<IndexedDBBackingStore> backing_store =
-      IndexedDBBackingStore::Open(
-          factory, origin, path, request_context_getter, &data_loss_info,
-          &disk_full, &mock_leveldb_factory, task_runner, clean_journal, &s);
+      IndexedDBBackingStore::Open(factory, origin, path, &data_loss_info,
+                                  &disk_full, &mock_leveldb_factory,
+                                  task_runner, clean_journal, &s);
   ASSERT_TRUE(s.IsIOError());
 
   busted_factory.SetOpenError(MakeIOError("some filename",
@@ -145,18 +142,18 @@
                                           leveldb_env::kNewLogger,
                                           base::File::FILE_ERROR_NO_MEMORY));
   scoped_refptr<IndexedDBBackingStore> backing_store2 =
-      IndexedDBBackingStore::Open(
-          factory, origin, path, request_context_getter, &data_loss_info,
-          &disk_full, &mock_leveldb_factory, task_runner, clean_journal, &s);
+      IndexedDBBackingStore::Open(factory, origin, path, &data_loss_info,
+                                  &disk_full, &mock_leveldb_factory,
+                                  task_runner, clean_journal, &s);
   ASSERT_TRUE(s.IsIOError());
 
   busted_factory.SetOpenError(MakeIOError("some filename", "some message",
                                           leveldb_env::kNewLogger,
                                           base::File::FILE_ERROR_IO));
   scoped_refptr<IndexedDBBackingStore> backing_store3 =
-      IndexedDBBackingStore::Open(
-          factory, origin, path, request_context_getter, &data_loss_info,
-          &disk_full, &mock_leveldb_factory, task_runner, clean_journal, &s);
+      IndexedDBBackingStore::Open(factory, origin, path, &data_loss_info,
+                                  &disk_full, &mock_leveldb_factory,
+                                  task_runner, clean_journal, &s);
   ASSERT_TRUE(s.IsIOError());
 
   busted_factory.SetOpenError(MakeIOError("some filename",
@@ -164,9 +161,9 @@
                                           leveldb_env::kNewLogger,
                                           base::File::FILE_ERROR_FAILED));
   scoped_refptr<IndexedDBBackingStore> backing_store4 =
-      IndexedDBBackingStore::Open(
-          factory, origin, path, request_context_getter, &data_loss_info,
-          &disk_full, &mock_leveldb_factory, task_runner, clean_journal, &s);
+      IndexedDBBackingStore::Open(factory, origin, path, &data_loss_info,
+                                  &disk_full, &mock_leveldb_factory,
+                                  task_runner, clean_journal, &s);
   ASSERT_TRUE(s.IsIOError());
 }
 
diff --git a/content/browser/indexed_db/indexed_db_dispatcher_host.cc b/content/browser/indexed_db/indexed_db_dispatcher_host.cc
index 2172021..f7c98ab 100644
--- a/content/browser/indexed_db/indexed_db_dispatcher_host.cc
+++ b/content/browser/indexed_db/indexed_db_dispatcher_host.cc
@@ -89,10 +89,8 @@
  public:
   IDBSequenceHelper(
       int ipc_process_id,
-      scoped_refptr<net::URLRequestContextGetter> request_context_getter,
       scoped_refptr<IndexedDBContextImpl> indexed_db_context)
       : ipc_process_id_(ipc_process_id),
-        request_context_getter_(std::move(request_context_getter)),
         indexed_db_context_(std::move(indexed_db_context)) {}
   ~IDBSequenceHelper() {}
 
@@ -118,7 +116,6 @@
 
  private:
   const int ipc_process_id_;
-  scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
   scoped_refptr<IndexedDBContextImpl> indexed_db_context_;
 
   DISALLOW_COPY_AND_ASSIGN(IDBSequenceHelper);
@@ -126,14 +123,12 @@
 
 IndexedDBDispatcherHost::IndexedDBDispatcherHost(
     int ipc_process_id,
-    scoped_refptr<net::URLRequestContextGetter> request_context_getter,
     scoped_refptr<IndexedDBContextImpl> indexed_db_context,
     scoped_refptr<ChromeBlobStorageContext> blob_storage_context)
     : indexed_db_context_(std::move(indexed_db_context)),
       blob_storage_context_(std::move(blob_storage_context)),
       ipc_process_id_(ipc_process_id),
       idb_helper_(new IDBSequenceHelper(ipc_process_id_,
-                                        std::move(request_context_getter),
                                         indexed_db_context_)),
       weak_factory_(this) {
   DCHECK(indexed_db_context_.get());
@@ -292,8 +287,8 @@
   DCHECK(indexed_db_context_->TaskRunner()->RunsTasksInCurrentSequence());
 
   base::FilePath indexed_db_path = indexed_db_context_->data_path();
-  indexed_db_context_->GetIDBFactory()->GetDatabaseNames(
-      callbacks, origin, indexed_db_path, request_context_getter_);
+  indexed_db_context_->GetIDBFactory()->GetDatabaseNames(callbacks, origin,
+                                                         indexed_db_path);
 }
 
 void IndexedDBDispatcherHost::IDBSequenceHelper::OpenOnIDBThread(
@@ -315,10 +310,8 @@
       std::make_unique<IndexedDBPendingConnection>(
           callbacks, database_callbacks, ipc_process_id_, transaction_id,
           version);
-  DCHECK(request_context_getter_);
   indexed_db_context_->GetIDBFactory()->Open(name, std::move(connection),
-                                             request_context_getter_, origin,
-                                             indexed_db_path);
+                                             origin, indexed_db_path);
 }
 
 void IndexedDBDispatcherHost::IDBSequenceHelper::DeleteDatabaseOnIDBThread(
@@ -329,10 +322,8 @@
   DCHECK(indexed_db_context_->TaskRunner()->RunsTasksInCurrentSequence());
 
   base::FilePath indexed_db_path = indexed_db_context_->data_path();
-  DCHECK(request_context_getter_);
   indexed_db_context_->GetIDBFactory()->DeleteDatabase(
-      name, request_context_getter_, callbacks, origin, indexed_db_path,
-      force_close);
+      name, callbacks, origin, indexed_db_path, force_close);
 }
 
 void IndexedDBDispatcherHost::IDBSequenceHelper::
diff --git a/content/browser/indexed_db/indexed_db_dispatcher_host.h b/content/browser/indexed_db/indexed_db_dispatcher_host.h
index 099b0315..a4babe25 100644
--- a/content/browser/indexed_db/indexed_db_dispatcher_host.h
+++ b/content/browser/indexed_db/indexed_db_dispatcher_host.h
@@ -21,7 +21,6 @@
 #include "content/public/browser/render_process_host_observer.h"
 #include "mojo/public/cpp/bindings/associated_binding_set.h"
 #include "mojo/public/cpp/bindings/strong_associated_binding_set.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom.h"
 
 namespace base {
@@ -45,7 +44,6 @@
   // Only call the constructor from the UI thread.
   IndexedDBDispatcherHost(
       int ipc_process_id,
-      scoped_refptr<net::URLRequestContextGetter> request_context_getter,
       scoped_refptr<IndexedDBContextImpl> indexed_db_context,
       scoped_refptr<ChromeBlobStorageContext> blob_storage_context);
 
diff --git a/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc b/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc
index 7b8ccdc9..64bae16 100644
--- a/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc
@@ -27,7 +27,6 @@
 #include "content/public/test/test_utils.h"
 #include "mojo/public/cpp/bindings/associated_interface_ptr.h"
 #include "mojo/public/cpp/bindings/strong_associated_binding.h"
-#include "net/url_request/url_request_test_util.h"
 #include "storage/browser/test/mock_quota_manager.h"
 #include "storage/browser/test/mock_quota_manager_proxy.h"
 #include "storage/browser/test/mock_special_storage_policy.h"
@@ -174,9 +173,6 @@
             quota_manager_->proxy())),
         host_(new IndexedDBDispatcherHost(
             kFakeProcessId,
-            base::MakeRefCounted<net::TestURLRequestContextGetter>(
-                base::CreateSingleThreadTaskRunnerWithTraits(
-                    {BrowserThread::IO})),
             context_impl_,
             ChromeBlobStorageContext::GetFor(&browser_context_))) {
     quota_manager_->SetQuota(ToOrigin(kOrigin),
diff --git a/content/browser/indexed_db/indexed_db_factory.h b/content/browser/indexed_db/indexed_db_factory.h
index b3e866d..9bc595c 100644
--- a/content/browser/indexed_db/indexed_db_factory.h
+++ b/content/browser/indexed_db/indexed_db_factory.h
@@ -23,10 +23,6 @@
 #include "url/gurl.h"
 #include "url/origin.h"
 
-namespace net {
-class URLRequestContextGetter;
-}
-
 namespace content {
 
 class IndexedDBBackingStore;
@@ -43,21 +39,17 @@
   virtual void ReleaseDatabase(const IndexedDBDatabase::Identifier& identifier,
                                bool forced_close) = 0;
 
-  virtual void GetDatabaseNames(
-      scoped_refptr<IndexedDBCallbacks> callbacks,
-      const url::Origin& origin,
-      const base::FilePath& data_directory,
-      scoped_refptr<net::URLRequestContextGetter> request_context_getter) = 0;
+  virtual void GetDatabaseNames(scoped_refptr<IndexedDBCallbacks> callbacks,
+                                const url::Origin& origin,
+                                const base::FilePath& data_directory) = 0;
   virtual void Open(
       const base::string16& name,
       std::unique_ptr<IndexedDBPendingConnection> connection,
-      scoped_refptr<net::URLRequestContextGetter> request_context_getter,
       const url::Origin& origin,
       const base::FilePath& data_directory) = 0;
 
   virtual void DeleteDatabase(
       const base::string16& name,
-      scoped_refptr<net::URLRequestContextGetter> request_context_getter,
       scoped_refptr<IndexedDBCallbacks> callbacks,
       const url::Origin& origin,
       const base::FilePath& data_directory,
@@ -117,7 +109,6 @@
   virtual scoped_refptr<IndexedDBBackingStore> OpenBackingStore(
       const url::Origin& origin,
       const base::FilePath& data_directory,
-      scoped_refptr<net::URLRequestContextGetter> request_context_getter,
       IndexedDBDataLossInfo* data_loss_info,
       bool* disk_full,
       leveldb::Status* status) = 0;
@@ -125,7 +116,6 @@
   virtual scoped_refptr<IndexedDBBackingStore> OpenBackingStoreHelper(
       const url::Origin& origin,
       const base::FilePath& data_directory,
-      scoped_refptr<net::URLRequestContextGetter> request_context_getter,
       IndexedDBDataLossInfo* data_loss_info,
       bool* disk_full,
       bool first_time,
diff --git a/content/browser/indexed_db/indexed_db_factory_impl.cc b/content/browser/indexed_db/indexed_db_factory_impl.cc
index e7bb4a7..8ed83d0 100644
--- a/content/browser/indexed_db/indexed_db_factory_impl.cc
+++ b/content/browser/indexed_db/indexed_db_factory_impl.cc
@@ -396,8 +396,7 @@
 void IndexedDBFactoryImpl::GetDatabaseNames(
     scoped_refptr<IndexedDBCallbacks> callbacks,
     const Origin& origin,
-    const base::FilePath& data_directory,
-    scoped_refptr<net::URLRequestContextGetter> request_context_getter) {
+    const base::FilePath& data_directory) {
   IDB_TRACE("IndexedDBFactoryImpl::GetDatabaseNames");
   // TODO(dgrogan): Plumb data_loss back to script eventually?
   IndexedDBDataLossInfo data_loss_info;
@@ -405,8 +404,7 @@
   leveldb::Status s;
   // TODO(cmumford): Handle this error
   scoped_refptr<IndexedDBBackingStore> backing_store =
-      OpenBackingStore(origin, data_directory, request_context_getter,
-                       &data_loss_info, &disk_full, &s);
+      OpenBackingStore(origin, data_directory, &data_loss_info, &disk_full, &s);
   if (!backing_store.get()) {
     IndexedDBDatabaseError error(
         blink::kWebIDBDatabaseExceptionUnknownError,
@@ -440,7 +438,6 @@
 
 void IndexedDBFactoryImpl::DeleteDatabase(
     const base::string16& name,
-    scoped_refptr<net::URLRequestContextGetter> request_context_getter,
     scoped_refptr<IndexedDBCallbacks> callbacks,
     const Origin& origin,
     const base::FilePath& data_directory,
@@ -460,8 +457,7 @@
   bool disk_full = false;
   leveldb::Status s;
   scoped_refptr<IndexedDBBackingStore> backing_store =
-      OpenBackingStore(origin, data_directory, request_context_getter,
-                       &data_loss_info, &disk_full, &s);
+      OpenBackingStore(origin, data_directory, &data_loss_info, &disk_full, &s);
   if (!backing_store.get()) {
     IndexedDBDatabaseError error(
         blink::kWebIDBDatabaseExceptionUnknownError,
@@ -627,20 +623,18 @@
 IndexedDBFactoryImpl::OpenBackingStoreHelper(
     const Origin& origin,
     const base::FilePath& data_directory,
-    scoped_refptr<net::URLRequestContextGetter> request_context_getter,
     IndexedDBDataLossInfo* data_loss_info,
     bool* disk_full,
     bool first_time,
     leveldb::Status* status) {
   return IndexedDBBackingStore::Open(
-      this, origin, data_directory, request_context_getter, data_loss_info,
-      disk_full, context_->TaskRunner(), first_time, status);
+      this, origin, data_directory, data_loss_info, disk_full,
+      context_->TaskRunner(), first_time, status);
 }
 
 scoped_refptr<IndexedDBBackingStore> IndexedDBFactoryImpl::OpenBackingStore(
     const Origin& origin,
     const base::FilePath& data_directory,
-    scoped_refptr<net::URLRequestContextGetter> request_context_getter,
     IndexedDBDataLossInfo* data_loss_info,
     bool* disk_full,
     leveldb::Status* status) {
@@ -667,9 +661,8 @@
   } else {
     first_time = !backends_opened_since_boot_.count(origin);
 
-    backing_store =
-        OpenBackingStoreHelper(origin, data_directory, request_context_getter,
-                               data_loss_info, disk_full, first_time, status);
+    backing_store = OpenBackingStoreHelper(
+        origin, data_directory, data_loss_info, disk_full, first_time, status);
   }
 
   if (backing_store.get()) {
@@ -693,7 +686,6 @@
 void IndexedDBFactoryImpl::Open(
     const base::string16& name,
     std::unique_ptr<IndexedDBPendingConnection> connection,
-    scoped_refptr<net::URLRequestContextGetter> request_context_getter,
     const Origin& origin,
     const base::FilePath& data_directory) {
   IDB_TRACE("IndexedDBFactoryImpl::Open");
@@ -705,9 +697,8 @@
   bool was_open = (it != database_map_.end());
   if (!was_open) {
     leveldb::Status s;
-    scoped_refptr<IndexedDBBackingStore> backing_store =
-        OpenBackingStore(origin, data_directory, request_context_getter,
-                         &data_loss_info, &disk_full, &s);
+    scoped_refptr<IndexedDBBackingStore> backing_store = OpenBackingStore(
+        origin, data_directory, &data_loss_info, &disk_full, &s);
     if (!backing_store.get()) {
       if (disk_full) {
         connection->callbacks->OnError(IndexedDBDatabaseError(
diff --git a/content/browser/indexed_db/indexed_db_factory_impl.h b/content/browser/indexed_db/indexed_db_factory_impl.h
index 6a11d403..e3a5d87 100644
--- a/content/browser/indexed_db/indexed_db_factory_impl.h
+++ b/content/browser/indexed_db/indexed_db_factory_impl.h
@@ -55,18 +55,14 @@
 
   void GetDatabaseNames(scoped_refptr<IndexedDBCallbacks> callbacks,
                         const url::Origin& origin,
-                        const base::FilePath& data_directory,
-                        scoped_refptr<net::URLRequestContextGetter>
-                            request_context_getter) override;
+                        const base::FilePath& data_directory) override;
   void Open(const base::string16& name,
             std::unique_ptr<IndexedDBPendingConnection> connection,
-            scoped_refptr<net::URLRequestContextGetter> request_context_getter,
             const url::Origin& origin,
             const base::FilePath& data_directory) override;
 
   void DeleteDatabase(
       const base::string16& name,
-      scoped_refptr<net::URLRequestContextGetter> request_context_getter,
       scoped_refptr<IndexedDBCallbacks> callbacks,
       const url::Origin& origin,
       const base::FilePath& data_directory,
@@ -122,7 +118,6 @@
   scoped_refptr<IndexedDBBackingStore> OpenBackingStore(
       const url::Origin& origin,
       const base::FilePath& data_directory,
-      scoped_refptr<net::URLRequestContextGetter> request_context_getter,
       IndexedDBDataLossInfo* data_loss_info,
       bool* disk_full,
       leveldb::Status* s) override;
@@ -130,7 +125,6 @@
   scoped_refptr<IndexedDBBackingStore> OpenBackingStoreHelper(
       const url::Origin& origin,
       const base::FilePath& data_directory,
-      scoped_refptr<net::URLRequestContextGetter> request_context_getter,
       IndexedDBDataLossInfo* data_loss_info,
       bool* disk_full,
       bool first_time,
diff --git a/content/browser/indexed_db/indexed_db_factory_unittest.cc b/content/browser/indexed_db/indexed_db_factory_unittest.cc
index 849666e..424d90f 100644
--- a/content/browser/indexed_db/indexed_db_factory_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_factory_unittest.cc
@@ -52,9 +52,8 @@
     IndexedDBDataLossInfo data_loss_info;
     bool disk_full;
     leveldb::Status s;
-    scoped_refptr<IndexedDBBackingStore> backing_store =
-        OpenBackingStore(origin, data_directory, nullptr /* request_context */,
-                         &data_loss_info, &disk_full, &s);
+    scoped_refptr<IndexedDBBackingStore> backing_store = OpenBackingStore(
+        origin, data_directory, &data_loss_info, &disk_full, &s);
     EXPECT_EQ(blink::kWebIDBDataLossNone, data_loss_info.status);
     return backing_store;
   }
@@ -447,7 +446,6 @@
   scoped_refptr<IndexedDBBackingStore> OpenBackingStore(
       const Origin& origin,
       const base::FilePath& data_directory,
-      scoped_refptr<net::URLRequestContextGetter> request_context_getter,
       IndexedDBDataLossInfo* data_loss_info,
       bool* disk_full,
       leveldb::Status* s) override {
@@ -503,8 +501,7 @@
                     callbacks, dummy_database_callbacks,
                     0 /* child_process_id */, 2 /* transaction_id */,
                     1 /* version */));
-            factory->Open(name, std::move(connection),
-                          nullptr /* request_context */, origin,
+            factory->Open(name, std::move(connection), origin,
                           context->data_path());
             EXPECT_TRUE(callbacks->error_called());
           },
@@ -531,8 +528,7 @@
                     callbacks, db_callbacks, 0 /* child_process_id */,
                     transaction_id,
                     IndexedDBDatabaseMetadata::DEFAULT_VERSION));
-            factory->Open(ASCIIToUTF16("db"), std::move(connection),
-                          nullptr /* request_context */, origin,
+            factory->Open(ASCIIToUTF16("db"), std::move(connection), origin,
                           context->data_path());
 
             EXPECT_TRUE(callbacks->connection());
@@ -569,8 +565,7 @@
                     callbacks, db_callbacks, 0 /* child_process_id */,
                     transaction_id,
                     IndexedDBDatabaseMetadata::DEFAULT_VERSION));
-            factory->Open(ASCIIToUTF16("db"), std::move(connection),
-                          nullptr /* request_context */, origin,
+            factory->Open(ASCIIToUTF16("db"), std::move(connection), origin,
                           context->data_path());
 
             EXPECT_TRUE(callbacks->connection());
@@ -613,9 +608,9 @@
             const Origin origin = Origin::Create(GURL("http://localhost:81"));
             EXPECT_FALSE(factory->IsBackingStoreOpen(origin));
 
-            factory->DeleteDatabase(
-                ASCIIToUTF16("db"), nullptr /* request_context */, callbacks,
-                origin, context->data_path(), false /* force_close */);
+            factory->DeleteDatabase(ASCIIToUTF16("db"), callbacks, origin,
+                                    context->data_path(),
+                                    false /* force_close */);
 
             EXPECT_TRUE(factory->IsBackingStoreOpen(origin));
             EXPECT_TRUE(factory->IsBackingStorePendingClose(origin));
@@ -645,8 +640,7 @@
             const Origin origin = Origin::Create(GURL("http://localhost:81"));
             EXPECT_FALSE(factory->IsBackingStoreOpen(origin));
 
-            factory->GetDatabaseNames(callbacks, origin, context->data_path(),
-                                      nullptr /* request_context */);
+            factory->GetDatabaseNames(callbacks, origin, context->data_path());
 
             EXPECT_TRUE(factory->IsBackingStoreOpen(origin));
             EXPECT_TRUE(factory->IsBackingStorePendingClose(origin));
@@ -681,8 +675,7 @@
                     callbacks, db_callbacks, 0 /* child_process_id */,
                     transaction_id,
                     IndexedDBDatabaseMetadata::DEFAULT_VERSION));
-            factory->Open(ASCIIToUTF16("db"), std::move(connection),
-                          nullptr /* request_context */, origin,
+            factory->Open(ASCIIToUTF16("db"), std::move(connection), origin,
                           context->data_path());
 
             EXPECT_TRUE(callbacks->connection());
@@ -782,7 +775,7 @@
                 std::make_unique<IndexedDBPendingConnection>(
                     *upgrade_callbacks, db_callbacks, 0 /* child_process_id */,
                     transaction_id, db_version),
-                nullptr /* request_context */, origin, context->data_path());
+                origin, context->data_path());
 
             EXPECT_TRUE((*factory)->IsDatabaseOpen(origin, db_name));
           },
@@ -822,8 +815,7 @@
                   std::make_unique<IndexedDBPendingConnection>(
                       failed_open_callbacks, db_callbacks,
                       0 /* child_process_id */, transaction_id, db_version));
-              factory->Open(db_name, std::move(connection),
-                            nullptr /* request_context */, origin,
+              factory->Open(db_name, std::move(connection), origin,
                             context->data_path());
               EXPECT_TRUE(failed_open_callbacks->saw_error());
               EXPECT_FALSE(factory->IsDatabaseOpen(origin, db_name));
@@ -898,7 +890,7 @@
                   std::make_unique<IndexedDBPendingConnection>(
                       *callbacks, db_callbacks, 0 /* child_process_id */,
                       transaction_id, 1 /* version */),
-                  nullptr /* request_context */, origin, context->data_path());
+                  origin, context->data_path());
             },
             base::Unretained(context()), base::Unretained(&factory),
             base::Unretained(&callbacks),
diff --git a/content/browser/indexed_db/indexed_db_fake_backing_store.cc b/content/browser/indexed_db/indexed_db_fake_backing_store.cc
index 7477de7..7444756a6 100644
--- a/content/browser/indexed_db/indexed_db_fake_backing_store.cc
+++ b/content/browser/indexed_db/indexed_db_fake_backing_store.cc
@@ -6,7 +6,6 @@
 
 #include "base/files/file_path.h"
 #include "base/threading/sequenced_task_runner_handle.h"
-#include "net/url_request/url_request_context_getter.h"
 
 namespace content {
 namespace {
@@ -20,7 +19,6 @@
     : IndexedDBBackingStore(nullptr /* indexed_db_factory */,
                             url::Origin::Create(GURL("http://localhost:81")),
                             base::FilePath(),
-                            scoped_refptr<net::URLRequestContextGetter>(),
                             std::unique_ptr<LevelDBDatabase>(),
                             std::unique_ptr<LevelDBComparator>(),
                             base::SequencedTaskRunnerHandle::Get().get()) {}
@@ -30,7 +28,6 @@
     : IndexedDBBackingStore(factory,
                             url::Origin::Create(GURL("http://localhost:81")),
                             base::FilePath(),
-                            nullptr /* request_context */,
                             std::unique_ptr<LevelDBDatabase>(),
                             std::unique_ptr<LevelDBComparator>(),
                             task_runner) {}
diff --git a/content/browser/indexed_db/indexed_db_unittest.cc b/content/browser/indexed_db/indexed_db_unittest.cc
index 4763c2f5..e651a8e 100644
--- a/content/browser/indexed_db/indexed_db_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_unittest.cc
@@ -173,7 +173,6 @@
             const int child_process_id = 0;
             const int64_t host_transaction_id = 0;
             const int64_t version = 0;
-            const scoped_refptr<net::URLRequestContextGetter> request_context;
 
             IndexedDBFactory* factory = idb_context->GetIDBFactory();
 
@@ -184,14 +183,14 @@
                           std::make_unique<IndexedDBPendingConnection>(
                               open_callbacks, open_db_callbacks,
                               child_process_id, host_transaction_id, version),
-                          request_context, origin, idb_context->data_path());
+                          origin, idb_context->data_path());
             EXPECT_TRUE(base::DirectoryExists(test_path));
 
             factory->Open(base::ASCIIToUTF16("closeddb"),
                           std::make_unique<IndexedDBPendingConnection>(
                               closed_callbacks, closed_db_callbacks,
                               child_process_id, host_transaction_id, version),
-                          request_context, origin, idb_context->data_path());
+                          origin, idb_context->data_path());
 
             closed_callbacks->connection()->Close();
 
@@ -260,14 +259,13 @@
 
             const int child_process_id = 0;
             const int64_t transaction_id = 1;
-            const scoped_refptr<net::URLRequestContextGetter> request_context;
 
             std::unique_ptr<IndexedDBPendingConnection> connection(
                 std::make_unique<IndexedDBPendingConnection>(
                     callbacks, db_callbacks, child_process_id, transaction_id,
                     IndexedDBDatabaseMetadata::DEFAULT_VERSION));
             factory->Open(base::ASCIIToUTF16("db"), std::move(connection),
-                          request_context, Origin(kTestOrigin), temp_path);
+                          Origin(kTestOrigin), temp_path);
 
             EXPECT_TRUE(callbacks->connection());
 
diff --git a/content/browser/indexed_db/mock_indexed_db_factory.h b/content/browser/indexed_db/mock_indexed_db_factory.h
index 3c68d50..98c8fc18 100644
--- a/content/browser/indexed_db/mock_indexed_db_factory.h
+++ b/content/browser/indexed_db/mock_indexed_db_factory.h
@@ -21,36 +21,29 @@
   MOCK_METHOD2(ReleaseDatabase,
                void(const IndexedDBDatabase::Identifier& identifier,
                     bool forced_close));
+  MOCK_METHOD3(GetDatabaseNames,
+               void(scoped_refptr<IndexedDBCallbacks> callbacks,
+                    const url::Origin& origin,
+                    const base::FilePath& data_directory));
   MOCK_METHOD4(
-      GetDatabaseNames,
-      void(scoped_refptr<IndexedDBCallbacks> callbacks,
-           const url::Origin& origin,
-           const base::FilePath& data_directory,
-           scoped_refptr<net::URLRequestContextGetter> request_context_getter));
-  MOCK_METHOD5(
       OpenProxy,
       void(const base::string16& name,
            IndexedDBPendingConnection* connection,
-           scoped_refptr<net::URLRequestContextGetter> request_context_getter,
            const url::Origin& origin,
            const base::FilePath& data_directory));
   // Googlemock can't deal with move-only types, so *Proxy() is a workaround.
   void Open(const base::string16& name,
             std::unique_ptr<IndexedDBPendingConnection> connection,
-            scoped_refptr<net::URLRequestContextGetter> request_context_getter,
             const url::Origin& origin,
             const base::FilePath& data_directory) override {
-    OpenProxy(name, connection.get(), request_context_getter, origin,
-              data_directory);
+    OpenProxy(name, connection.get(), origin, data_directory);
   }
-  MOCK_METHOD6(
-      DeleteDatabase,
-      void(const base::string16& name,
-           scoped_refptr<net::URLRequestContextGetter> request_context_getter,
-           scoped_refptr<IndexedDBCallbacks> callbacks,
-           const url::Origin& origin,
-           const base::FilePath& data_directory,
-           bool force_close));
+  MOCK_METHOD5(DeleteDatabase,
+               void(const base::string16& name,
+                    scoped_refptr<IndexedDBCallbacks> callbacks,
+                    const url::Origin& origin,
+                    const base::FilePath& data_directory,
+                    bool force_close));
   MOCK_METHOD2(AbortTransactionsAndCompactDatabaseProxy,
                void(base::OnceCallback<void(leveldb::Status)>* callback,
                     const url::Origin& origin));
@@ -105,26 +98,22 @@
  protected:
   ~MockIndexedDBFactory() override;
 
-  MOCK_METHOD6(
-      OpenBackingStore,
-      scoped_refptr<IndexedDBBackingStore>(
-          const url::Origin& origin,
-          const base::FilePath& data_directory,
-          scoped_refptr<net::URLRequestContextGetter> request_context_getter,
-          IndexedDBDataLossInfo* data_loss_info,
-          bool* disk_full,
-          leveldb::Status* s));
+  MOCK_METHOD5(OpenBackingStore,
+               scoped_refptr<IndexedDBBackingStore>(
+                   const url::Origin& origin,
+                   const base::FilePath& data_directory,
+                   IndexedDBDataLossInfo* data_loss_info,
+                   bool* disk_full,
+                   leveldb::Status* s));
 
-  MOCK_METHOD7(
-      OpenBackingStoreHelper,
-      scoped_refptr<IndexedDBBackingStore>(
-          const url::Origin& origin,
-          const base::FilePath& data_directory,
-          scoped_refptr<net::URLRequestContextGetter> request_context_getter,
-          IndexedDBDataLossInfo* data_loss_info,
-          bool* disk_full,
-          bool first_time,
-          leveldb::Status* s));
+  MOCK_METHOD6(OpenBackingStoreHelper,
+               scoped_refptr<IndexedDBBackingStore>(
+                   const url::Origin& origin,
+                   const base::FilePath& data_directory,
+                   IndexedDBDataLossInfo* data_loss_info,
+                   bool* disk_full,
+                   bool first_time,
+                   leveldb::Status* s));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockIndexedDBFactory);
diff --git a/content/browser/renderer_host/input/synthetic_gesture.cc b/content/browser/renderer_host/input/synthetic_gesture.cc
index fd09c2a..f5ba649b 100644
--- a/content/browser/renderer_host/input/synthetic_gesture.cc
+++ b/content/browser/renderer_host/input/synthetic_gesture.cc
@@ -52,4 +52,8 @@
   }
 }
 
+bool SyntheticGesture::AllowHighFrequencyDispatch() const {
+  return true;
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/input/synthetic_gesture.h b/content/browser/renderer_host/input/synthetic_gesture.h
index 90d4990..6f5d33057 100644
--- a/content/browser/renderer_host/input/synthetic_gesture.h
+++ b/content/browser/renderer_host/input/synthetic_gesture.h
@@ -51,6 +51,12 @@
   virtual Result ForwardInputEvents(
       const base::TimeTicks& timestamp, SyntheticGestureTarget* target) = 0;
 
+  // Returns whether the gesture events can be dispatched at high frequency
+  // (e.g. at 120Hz), instead of the regular frequence (at 60Hz). Some gesture
+  // interact differently depending on how long they take (e.g. the TAP gesture
+  // generates a click only if its duration is longer than a threshold).
+  virtual bool AllowHighFrequencyDispatch() const;
+
  protected:
   DISALLOW_COPY_AND_ASSIGN(SyntheticGesture);
 };
diff --git a/content/browser/renderer_host/input/synthetic_gesture_controller.cc b/content/browser/renderer_host/input/synthetic_gesture_controller.cc
index 44308e0..eef8cd0 100644
--- a/content/browser/renderer_host/input/synthetic_gesture_controller.cc
+++ b/content/browser/renderer_host/input/synthetic_gesture_controller.cc
@@ -40,11 +40,10 @@
     StartGesture(*pending_gesture_queue_.FrontGesture());
 }
 
-void SyntheticGestureController::StartTimer() {
-  // TODO(sad): Change the interval to allow sending multiple events per begin
-  // frame.
+void SyntheticGestureController::StartTimer(bool high_frequency) {
   dispatch_timer_.Start(
-      FROM_HERE, base::TimeDelta::FromMicroseconds(16666),
+      FROM_HERE,
+      base::TimeDelta::FromMicroseconds(high_frequency ? 8333 : 16666),
       base::BindRepeating(
           [](base::WeakPtr<SyntheticGestureController> weak_ptr) {
             if (weak_ptr)
@@ -90,7 +89,7 @@
                            "SyntheticGestureController::running",
                            &gesture);
   if (!dispatch_timer_.IsRunning())
-    StartTimer();
+    StartTimer(gesture.AllowHighFrequencyDispatch());
 }
 
 void SyntheticGestureController::StopGesture(
diff --git a/content/browser/renderer_host/input/synthetic_gesture_controller.h b/content/browser/renderer_host/input/synthetic_gesture_controller.h
index 085fdc353f..dcc3b8e 100644
--- a/content/browser/renderer_host/input/synthetic_gesture_controller.h
+++ b/content/browser/renderer_host/input/synthetic_gesture_controller.h
@@ -52,7 +52,7 @@
  private:
   friend class SyntheticGestureControllerTestBase;
 
-  void StartTimer();
+  void StartTimer(bool high_frequency);
   void StartGesture(const SyntheticGesture& gesture);
   void StopGesture(const SyntheticGesture& gesture,
                    OnGestureCompleteCallback completion_callback,
diff --git a/content/browser/renderer_host/input/synthetic_pointer_action.cc b/content/browser/renderer_host/input/synthetic_pointer_action.cc
index 742087c..9e889da 100644
--- a/content/browser/renderer_host/input/synthetic_pointer_action.cc
+++ b/content/browser/renderer_host/input/synthetic_pointer_action.cc
@@ -47,6 +47,10 @@
                           : SyntheticGesture::GESTURE_RUNNING;
 }
 
+bool SyntheticPointerAction::AllowHighFrequencyDispatch() const {
+  return false;
+}
+
 SyntheticPointerAction::GestureState
 SyntheticPointerAction::ForwardTouchOrMouseInputEvents(
     const base::TimeTicks& timestamp,
diff --git a/content/browser/renderer_host/input/synthetic_pointer_action.h b/content/browser/renderer_host/input/synthetic_pointer_action.h
index 39b3656..e836a08 100644
--- a/content/browser/renderer_host/input/synthetic_pointer_action.h
+++ b/content/browser/renderer_host/input/synthetic_pointer_action.h
@@ -24,6 +24,7 @@
   SyntheticGesture::Result ForwardInputEvents(
       const base::TimeTicks& timestamp,
       SyntheticGestureTarget* target) override;
+  bool AllowHighFrequencyDispatch() const override;
 
  private:
   enum GestureState { UNINITIALIZED, RUNNING, INVALID, DONE };
diff --git a/content/browser/renderer_host/input/synthetic_tap_gesture.cc b/content/browser/renderer_host/input/synthetic_tap_gesture.cc
index 80503e5..54b70a02 100644
--- a/content/browser/renderer_host/input/synthetic_tap_gesture.cc
+++ b/content/browser/renderer_host/input/synthetic_tap_gesture.cc
@@ -46,6 +46,10 @@
                           : SyntheticGesture::GESTURE_RUNNING;
 }
 
+bool SyntheticTapGesture::AllowHighFrequencyDispatch() const {
+  return false;
+}
+
 void SyntheticTapGesture::ForwardTouchOrMouseInputEvents(
     const base::TimeTicks& timestamp, SyntheticGestureTarget* target) {
   switch (state_) {
diff --git a/content/browser/renderer_host/input/synthetic_tap_gesture.h b/content/browser/renderer_host/input/synthetic_tap_gesture.h
index 03d4f47..b3d2bfc 100644
--- a/content/browser/renderer_host/input/synthetic_tap_gesture.h
+++ b/content/browser/renderer_host/input/synthetic_tap_gesture.h
@@ -22,6 +22,7 @@
   SyntheticGesture::Result ForwardInputEvents(
       const base::TimeTicks& timestamp,
       SyntheticGestureTarget* target) override;
+  bool AllowHighFrequencyDispatch() const override;
 
  private:
   enum GestureState {
diff --git a/content/browser/renderer_host/overscroll_controller.cc b/content/browser/renderer_host/overscroll_controller.cc
index 06b310e..23c4586 100644
--- a/content/browser/renderer_host/overscroll_controller.cc
+++ b/content/browser/renderer_host/overscroll_controller.cc
@@ -531,6 +531,8 @@
   if (overscroll_mode_ == OVERSCROLL_NONE)
     return false;
 
+  overscroll_ignored_ = false;
+
   // Tell the delegate about the overscroll update so that it can update
   // the display accordingly (e.g. show history preview etc.).
   if (delegate_) {
diff --git a/content/browser/renderer_host/overscroll_controller_unittest.cc b/content/browser/renderer_host/overscroll_controller_unittest.cc
index 166d1fe3..fc980f1 100644
--- a/content/browser/renderer_host/overscroll_controller_unittest.cc
+++ b/content/browser/renderer_host/overscroll_controller_unittest.cc
@@ -496,11 +496,18 @@
 }
 
 // Verifies that if an overscroll happens before cool off period after a page
-// scroll, it does not trigger pull-to-refresh.
-TEST_F(OverscrollControllerTest, PullToRefreshCoolOff) {
+// scroll, it does not trigger pull-to-refresh. Verifies following sequence of
+// scrolls:
+//  1) Page scroll;
+//  2) Scroll before cool off -> PTR not triggered;
+//  3) Scroll before cool off -> PTR not triggered;
+//  4) Scroll after cool off  -> PTR triggered;
+//  5) Scroll before cool off -> PTR triggered.
+TEST_F(OverscrollControllerTest, PullToRefreshBeforeCoolOff) {
   ScopedPullToRefreshMode scoped_mode(
       OverscrollConfig::PullToRefreshMode::kEnabled);
 
+  // 1) Page scroll.
   base::TimeTicks timestamp =
       blink::WebInputEvent::GetStaticTimeStampForTests();
 
@@ -510,8 +517,7 @@
   SimulateAck(false);
 
   // Simulate a touchscreen gesture scroll-update event that passes the start
-  // threshold and ACK it as not processed. Pull-to-refresh should not be
-  // triggered.
+  // threshold and ACK it as processed. Pull-to-refresh should not be triggered.
   EXPECT_FALSE(SimulateGestureScrollUpdate(
       0, 80, blink::kWebGestureDeviceTouchscreen, timestamp, false));
   SimulateAck(true);
@@ -533,9 +539,8 @@
   EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode());
   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode());
 
-  // Next scroll should happen before cool off period is finished, so that it
-  // does not trigger pull-to-refresh.
-  timestamp += base::TimeDelta::FromSecondsD(0.5);
+  // 2) Scroll before cool off -> PTR not triggered.
+  timestamp += base::TimeDelta::FromMilliseconds(500);
 
   EXPECT_FALSE(SimulateGestureEvent(blink::WebInputEvent::kGestureScrollBegin,
                                     blink::kWebGestureDeviceTouchscreen,
@@ -565,6 +570,205 @@
   EXPECT_EQ(OverscrollSource::NONE, controller_source());
   EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode());
   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode());
+
+  // 3) Scroll before cool off -> PTR not triggered.
+  timestamp += base::TimeDelta::FromMilliseconds(500);
+
+  EXPECT_FALSE(SimulateGestureEvent(blink::WebInputEvent::kGestureScrollBegin,
+                                    blink::kWebGestureDeviceTouchscreen,
+                                    timestamp));
+  SimulateAck(false);
+
+  // Simulate a touchscreen gesture scroll-update event that passes the start
+  // threshold and ACK it as not processed. Pull-to-refresh should not be
+  // triggered.
+  EXPECT_FALSE(SimulateGestureScrollUpdate(
+      0, 80, blink::kWebGestureDeviceTouchscreen, timestamp, false));
+  SimulateAck(false);
+  EXPECT_EQ(OVERSCROLL_NONE, controller_mode());
+  EXPECT_EQ(OverscrollSource::NONE, controller_source());
+  EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode());
+  EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode());
+
+  timestamp += base::TimeDelta::FromSeconds(1);
+
+  // Simulate a touchscreen gesture scroll-end which would normally end
+  // pull-to-refresh, and ACK it as not processed. Nothing should happen.
+  EXPECT_FALSE(SimulateGestureEvent(blink::WebInputEvent::kGestureScrollEnd,
+                                    blink::kWebGestureDeviceTouchscreen,
+                                    timestamp));
+  SimulateAck(false);
+  EXPECT_EQ(OVERSCROLL_NONE, controller_mode());
+  EXPECT_EQ(OverscrollSource::NONE, controller_source());
+  EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode());
+  EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode());
+
+  // 4) Scroll after cool off -> PTR triggered.
+  timestamp += base::TimeDelta::FromSeconds(1);
+
+  EXPECT_FALSE(SimulateGestureEvent(blink::WebInputEvent::kGestureScrollBegin,
+                                    blink::kWebGestureDeviceTouchscreen,
+                                    timestamp));
+  SimulateAck(false);
+
+  // Simulate a touchscreen gesture scroll-update event that passes the start
+  // threshold and ACK it as not processed. Pull-to-refresh should be triggered.
+  EXPECT_FALSE(SimulateGestureScrollUpdate(
+      0, 80, blink::kWebGestureDeviceTouchscreen, timestamp, false));
+  SimulateAck(false);
+  EXPECT_EQ(OVERSCROLL_SOUTH, controller_mode());
+  EXPECT_EQ(OverscrollSource::TOUCHSCREEN, controller_source());
+  EXPECT_EQ(OVERSCROLL_SOUTH, delegate()->current_mode());
+  EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode());
+
+  timestamp += base::TimeDelta::FromSeconds(1);
+
+  // Simulate a touchscreen gesture scroll-end which will end pull-to-refresh,
+  // and ACK it as not processed. Pull-to-refresh should be aborted.
+  EXPECT_FALSE(SimulateGestureEvent(blink::WebInputEvent::kGestureScrollEnd,
+                                    blink::kWebGestureDeviceTouchscreen,
+                                    timestamp));
+  SimulateAck(false);
+  EXPECT_EQ(OVERSCROLL_NONE, controller_mode());
+  EXPECT_EQ(OverscrollSource::NONE, controller_source());
+  EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode());
+  EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode());
+
+  // 5) Scroll before cool off -> PTR triggered.
+  timestamp += base::TimeDelta::FromMilliseconds(500);
+
+  EXPECT_FALSE(SimulateGestureEvent(blink::WebInputEvent::kGestureScrollBegin,
+                                    blink::kWebGestureDeviceTouchscreen,
+                                    timestamp));
+  SimulateAck(false);
+
+  // Simulate a touchscreen gesture scroll-update event that passes the start
+  // threshold and ACK it as not processed. Pull-to-refresh should be triggered.
+  EXPECT_FALSE(SimulateGestureScrollUpdate(
+      0, 80, blink::kWebGestureDeviceTouchscreen, timestamp, false));
+  SimulateAck(false);
+  EXPECT_EQ(OVERSCROLL_SOUTH, controller_mode());
+  EXPECT_EQ(OverscrollSource::TOUCHSCREEN, controller_source());
+  EXPECT_EQ(OVERSCROLL_SOUTH, delegate()->current_mode());
+  EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode());
+
+  timestamp += base::TimeDelta::FromSeconds(1);
+
+  // Simulate a touchscreen gesture scroll-end which will end pull-to-refresh,
+  // and ACK it as not processed. Pull-to-refresh should be aborted.
+  EXPECT_FALSE(SimulateGestureEvent(blink::WebInputEvent::kGestureScrollEnd,
+                                    blink::kWebGestureDeviceTouchscreen,
+                                    timestamp));
+  SimulateAck(false);
+  EXPECT_EQ(OVERSCROLL_NONE, controller_mode());
+  EXPECT_EQ(OverscrollSource::NONE, controller_source());
+  EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode());
+  EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode());
+}
+
+// Verifies that if an overscroll happens after cool off period after a page
+// scroll, it triggers pull-to-refresh. Verifies the following sequence of
+// scrolls:
+//  1) Page scroll;
+//  2) Scroll after cool off  -> PTR triggered;
+//  3) Scroll before cool off -> PTR triggered;
+TEST_F(OverscrollControllerTest, PullToRefreshAfterCoolOff) {
+  ScopedPullToRefreshMode scoped_mode(
+      OverscrollConfig::PullToRefreshMode::kEnabled);
+
+  // 1) Page scroll.
+  base::TimeTicks timestamp =
+      blink::WebInputEvent::GetStaticTimeStampForTests();
+
+  EXPECT_FALSE(SimulateGestureEvent(blink::WebInputEvent::kGestureScrollBegin,
+                                    blink::kWebGestureDeviceTouchscreen,
+                                    timestamp));
+  SimulateAck(false);
+
+  // Simulate a touchscreen gesture scroll-update event that passes the start
+  // threshold and ACK it as processed. Pull-to-refresh should not be triggered.
+  EXPECT_FALSE(SimulateGestureScrollUpdate(
+      0, 80, blink::kWebGestureDeviceTouchscreen, timestamp, false));
+  SimulateAck(true);
+  EXPECT_EQ(OVERSCROLL_NONE, controller_mode());
+  EXPECT_EQ(OverscrollSource::NONE, controller_source());
+  EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode());
+  EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode());
+
+  timestamp += base::TimeDelta::FromSeconds(1);
+
+  // Simulate a touchscreen gesture scroll-end which would normally end
+  // pull-to-refresh, and ACK it as not processed. Nothing should happen.
+  EXPECT_FALSE(SimulateGestureEvent(blink::WebInputEvent::kGestureScrollEnd,
+                                    blink::kWebGestureDeviceTouchscreen,
+                                    timestamp));
+  SimulateAck(false);
+  EXPECT_EQ(OVERSCROLL_NONE, controller_mode());
+  EXPECT_EQ(OverscrollSource::NONE, controller_source());
+  EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode());
+  EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode());
+
+  // 2) Scroll after cool off -> PTR triggered.
+  timestamp += base::TimeDelta::FromSeconds(1);
+
+  EXPECT_FALSE(SimulateGestureEvent(blink::WebInputEvent::kGestureScrollBegin,
+                                    blink::kWebGestureDeviceTouchscreen,
+                                    timestamp));
+  SimulateAck(false);
+
+  // Simulate a touchscreen gesture scroll-update event that passes the start
+  // threshold and ACK it as not processed. Pull-to-refresh should be triggered.
+  EXPECT_FALSE(SimulateGestureScrollUpdate(
+      0, 80, blink::kWebGestureDeviceTouchscreen, timestamp, false));
+  SimulateAck(false);
+  EXPECT_EQ(OVERSCROLL_SOUTH, controller_mode());
+  EXPECT_EQ(OverscrollSource::TOUCHSCREEN, controller_source());
+  EXPECT_EQ(OVERSCROLL_SOUTH, delegate()->current_mode());
+  EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode());
+
+  timestamp += base::TimeDelta::FromSeconds(1);
+
+  // Simulate a touchscreen gesture scroll-end which will end pull-to-refresh,
+  // and ACK it as not processed. Pull-to-refresh should be aborted.
+  EXPECT_FALSE(SimulateGestureEvent(blink::WebInputEvent::kGestureScrollEnd,
+                                    blink::kWebGestureDeviceTouchscreen,
+                                    timestamp));
+  SimulateAck(false);
+  EXPECT_EQ(OVERSCROLL_NONE, controller_mode());
+  EXPECT_EQ(OverscrollSource::NONE, controller_source());
+  EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode());
+  EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode());
+
+  // 3) Scroll before cool off -> PTR triggered.
+  timestamp += base::TimeDelta::FromMilliseconds(500);
+
+  EXPECT_FALSE(SimulateGestureEvent(blink::WebInputEvent::kGestureScrollBegin,
+                                    blink::kWebGestureDeviceTouchscreen,
+                                    timestamp));
+  SimulateAck(false);
+
+  // Simulate a touchscreen gesture scroll-update event that passes the start
+  // threshold and ACK it as not processed. Pull-to-refresh should be triggered.
+  EXPECT_FALSE(SimulateGestureScrollUpdate(
+      0, 80, blink::kWebGestureDeviceTouchscreen, timestamp, false));
+  SimulateAck(false);
+  EXPECT_EQ(OVERSCROLL_SOUTH, controller_mode());
+  EXPECT_EQ(OverscrollSource::TOUCHSCREEN, controller_source());
+  EXPECT_EQ(OVERSCROLL_SOUTH, delegate()->current_mode());
+  EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode());
+
+  timestamp += base::TimeDelta::FromSeconds(1);
+
+  // Simulate a touchscreen gesture scroll-end which will end pull-to-refresh,
+  // and ACK it as not processed. Pull-to-refresh should be aborted.
+  EXPECT_FALSE(SimulateGestureEvent(blink::WebInputEvent::kGestureScrollEnd,
+                                    blink::kWebGestureDeviceTouchscreen,
+                                    timestamp));
+  SimulateAck(false);
+  EXPECT_EQ(OVERSCROLL_NONE, controller_mode());
+  EXPECT_EQ(OverscrollSource::NONE, controller_source());
+  EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode());
+  EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode());
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 41588b0..0a20b9c 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1573,7 +1573,6 @@
       permission_service_context_(new PermissionServiceContext(this)),
       indexed_db_factory_(new IndexedDBDispatcherHost(
           id_,
-          storage_partition_impl_->GetURLRequestContext(),
           storage_partition_impl_->GetIndexedDBContext(),
           ChromeBlobStorageContext::GetFor(browser_context_))),
       service_worker_dispatcher_host_(new ServiceWorkerDispatcherHost(
diff --git a/content/browser/service_worker/service_worker_installed_script_reader.cc b/content/browser/service_worker/service_worker_installed_script_reader.cc
index 0b4f479..3b8c5c2 100644
--- a/content/browser/service_worker/service_worker_installed_script_reader.cc
+++ b/content/browser/service_worker/service_worker_installed_script_reader.cc
@@ -118,25 +118,38 @@
   DCHECK_GE(http_info->response_data_size, 0);
   uint64_t body_size = http_info->response_data_size;
   uint64_t meta_data_size = 0;
-  mojo::DataPipe body_pipe(blink::BlobUtils::GetDataPipeCapacity(body_size));
-  if (!body_pipe.producer_handle.is_valid()) {
+
+  MojoCreateDataPipeOptions options;
+  options.struct_size = sizeof(MojoCreateDataPipeOptions);
+  options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE;
+  options.element_num_bytes = 1;
+  options.capacity_num_bytes = blink::BlobUtils::GetDataPipeCapacity(body_size);
+
+  mojo::ScopedDataPipeConsumerHandle body_consumer_handle;
+  MojoResult rv =
+      mojo::CreateDataPipe(&options, &body_handle_, &body_consumer_handle);
+  if (rv != MOJO_RESULT_OK) {
     CompleteSendIfNeeded(FinishedReason::kCreateDataPipeError);
     return;
   }
-  body_handle_ = std::move(body_pipe.producer_handle);
+
   // Start sending meta data (V8 code cache data).
   if (http_info->http_info->metadata) {
     DCHECK_GE(http_info->http_info->metadata->size(), 0);
     meta_data_size = http_info->http_info->metadata->size();
-    mojo::DataPipe meta_pipe(
-        blink::BlobUtils::GetDataPipeCapacity(meta_data_size));
-    if (!meta_pipe.producer_handle.is_valid()) {
+
+    mojo::ScopedDataPipeProducerHandle meta_producer_handle;
+    options.capacity_num_bytes =
+        blink::BlobUtils::GetDataPipeCapacity(meta_data_size);
+    rv = mojo::CreateDataPipe(&options, &meta_producer_handle,
+                              &meta_data_consumer);
+    if (rv != MOJO_RESULT_OK) {
       CompleteSendIfNeeded(FinishedReason::kCreateDataPipeError);
       return;
     }
-    meta_data_consumer = std::move(meta_pipe.consumer_handle);
+
     meta_data_sender_ = std::make_unique<MetaDataSender>(
-        http_info->http_info->metadata, std::move(meta_pipe.producer_handle));
+        http_info->http_info->metadata, std::move(meta_producer_handle));
     meta_data_sender_->Start(base::BindOnce(
         &ServiceWorkerInstalledScriptReader::OnMetaDataSent, AsWeakPtr()));
   }
@@ -170,7 +183,7 @@
   }
 
   client_->OnStarted(charset, std::move(header_strings),
-                     std::move(body_pipe.consumer_handle), body_size,
+                     std::move(body_consumer_handle), body_size,
                      std::move(meta_data_consumer), meta_data_size);
   client_->OnHttpInfoRead(http_info);
 }
diff --git a/content/common/service_worker/service_worker_loader_helpers.cc b/content/common/service_worker/service_worker_loader_helpers.cc
index a05dbe61..1b26bc94 100644
--- a/content/common/service_worker/service_worker_loader_helpers.cc
+++ b/content/common/service_worker/service_worker_loader_helpers.cc
@@ -136,17 +136,23 @@
     uint64_t blob_size,
     base::OnceCallback<void(int)> on_blob_read_complete,
     mojo::ScopedDataPipeConsumerHandle* handle_out) {
-  // TODO(falken): Change to CreateDataPipe() and return an error if allocation
-  // failed.
-  mojo::DataPipe data_pipe(blink::BlobUtils::GetDataPipeCapacity(blob_size));
+  MojoCreateDataPipeOptions options;
+  options.struct_size = sizeof(MojoCreateDataPipeOptions);
+  options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE;
+  options.element_num_bytes = 1;
+  options.capacity_num_bytes = blink::BlobUtils::GetDataPipeCapacity(blob_size);
+
+  mojo::ScopedDataPipeProducerHandle producer_handle;
+  MojoResult rv = mojo::CreateDataPipe(&options, &producer_handle, handle_out);
+  if (rv != MOJO_RESULT_OK)
+    return net::ERR_FAILED;
+
   blink::mojom::BlobReaderClientPtr blob_reader_client;
   mojo::MakeStrongBinding(
       std::make_unique<BlobCompleteCaller>(std::move(on_blob_read_complete)),
       mojo::MakeRequest(&blob_reader_client));
 
-  (*blob)->ReadAll(std::move(data_pipe.producer_handle),
-                   std::move(blob_reader_client));
-  *handle_out = std::move(data_pipe.consumer_handle);
+  (*blob)->ReadAll(std::move(producer_handle), std::move(blob_reader_client));
   return net::OK;
 }
 
diff --git a/content/gpu/gpu_child_thread.cc b/content/gpu/gpu_child_thread.cc
index 87c0b20..f46ed60f 100644
--- a/content/gpu/gpu_child_thread.cc
+++ b/content/gpu/gpu_child_thread.cc
@@ -277,6 +277,7 @@
   service_factory_.reset(new GpuServiceFactory(
       gpu_service->gpu_preferences(),
       gpu_service->gpu_channel_manager()->gpu_driver_bug_workarounds(),
+      gpu_service->gpu_feature_info(),
       gpu_service->media_gpu_channel_manager()->AsWeakPtr(),
       std::move(overlay_factory_cb)));
 
diff --git a/content/gpu/gpu_service_factory.cc b/content/gpu/gpu_service_factory.cc
index 1f90da0..c1b474f 100644
--- a/content/gpu/gpu_service_factory.cc
+++ b/content/gpu/gpu_service_factory.cc
@@ -25,11 +25,13 @@
 GpuServiceFactory::GpuServiceFactory(
     const gpu::GpuPreferences& gpu_preferences,
     const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
+    const gpu::GpuFeatureInfo& gpu_feature_info,
     base::WeakPtr<media::MediaGpuChannelManager> media_gpu_channel_manager,
     media::AndroidOverlayMojoFactoryCB android_overlay_factory_cb) {
 #if BUILDFLAG(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS)
   gpu_preferences_ = gpu_preferences;
   gpu_workarounds_ = gpu_workarounds;
+  gpu_feature_info_ = gpu_feature_info;
   task_runner_ = base::ThreadTaskRunnerHandle::Get();
   media_gpu_channel_manager_ = std::move(media_gpu_channel_manager);
   android_overlay_factory_cb_ = std::move(android_overlay_factory_cb);
@@ -50,8 +52,8 @@
   service_manager::EmbeddedServiceInfo info;
   info.factory = base::BindRepeating(
       &media::CreateGpuMediaService, gpu_preferences_, gpu_workarounds_,
-      task_runner_, media_gpu_channel_manager_, android_overlay_factory_cb_,
-      std::move(cdm_proxy_factory_cb));
+      gpu_feature_info_, task_runner_, media_gpu_channel_manager_,
+      android_overlay_factory_cb_, std::move(cdm_proxy_factory_cb));
   // This service will host audio/video decoders, and if these decoding
   // operations are blocked, user may hear audio glitch or see video freezing,
   // hence "user blocking".
diff --git a/content/gpu/gpu_service_factory.h b/content/gpu/gpu_service_factory.h
index 1316a948e..a639f34 100644
--- a/content/gpu/gpu_service_factory.h
+++ b/content/gpu/gpu_service_factory.h
@@ -11,6 +11,7 @@
 #include "base/single_thread_task_runner.h"
 #include "content/child/service_factory.h"
 #include "gpu/config/gpu_driver_bug_workarounds.h"
+#include "gpu/config/gpu_feature_info.h"
 #include "gpu/config/gpu_preferences.h"
 #include "media/base/android_overlay_mojo_factory.h"
 #include "media/mojo/buildflags.h"
@@ -27,6 +28,7 @@
   GpuServiceFactory(
       const gpu::GpuPreferences& gpu_preferences,
       const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
+      const gpu::GpuFeatureInfo& gpu_feature_info,
       base::WeakPtr<media::MediaGpuChannelManager> media_gpu_channel_manager,
       media::AndroidOverlayMojoFactoryCB android_overlay_factory_cb);
   ~GpuServiceFactory() override;
@@ -45,6 +47,7 @@
   media::AndroidOverlayMojoFactoryCB android_overlay_factory_cb_;
   gpu::GpuPreferences gpu_preferences_;
   gpu::GpuDriverBugWorkarounds gpu_workarounds_;
+  gpu::GpuFeatureInfo gpu_feature_info_;
 #endif
 
   DISALLOW_COPY_AND_ASSIGN(GpuServiceFactory);
diff --git a/content/public/browser/devtools_agent_host_client.cc b/content/public/browser/devtools_agent_host_client.cc
index 6f53074c..f5f71bd 100644
--- a/content/public/browser/devtools_agent_host_client.cc
+++ b/content/public/browser/devtools_agent_host_client.cc
@@ -20,4 +20,8 @@
   return true;
 }
 
+bool DevToolsAgentHostClient::MayAffectLocalFiles() {
+  return true;
+}
+
 }  // namespace content
diff --git a/content/public/browser/devtools_agent_host_client.h b/content/public/browser/devtools_agent_host_client.h
index 0ecc7aa3..8a93a1d4 100644
--- a/content/public/browser/devtools_agent_host_client.h
+++ b/content/public/browser/devtools_agent_host_client.h
@@ -38,6 +38,10 @@
   // Returns true if the client is allowed to discover other DevTools targets.
   // If not, it will be restricted to auto-attaching to related targets.
   virtual bool MayDiscoverTargets();
+
+  // Returns true if the client is allowed to affect local files over the
+  // protocol. Example would be manipulating a deault downloads path.
+  virtual bool MayAffectLocalFiles();
 };
 
 }  // namespace content
diff --git a/content/public/renderer/render_frame_observer.h b/content/public/renderer/render_frame_observer.h
index cff1efb..ce1f26c 100644
--- a/content/public/renderer/render_frame_observer.h
+++ b/content/public/renderer/render_frame_observer.h
@@ -81,6 +81,7 @@
   virtual void DidFailProvisionalLoad(const blink::WebURLError& error) {}
   virtual void DidFinishLoad() {}
   virtual void DidFinishDocumentLoad() {}
+  virtual void DidHandleOnloadEvents() {}
   virtual void DidCreateScriptContext(v8::Local<v8::Context> context,
                                       int world_id) {}
   virtual void WillReleaseScriptContext(v8::Local<v8::Context> context,
diff --git a/content/renderer/media_recorder/media_recorder_handler.cc b/content/renderer/media_recorder/media_recorder_handler.cc
index 8e5f6b1..e287e68 100644
--- a/content/renderer/media_recorder/media_recorder_handler.cc
+++ b/content/renderer/media_recorder/media_recorder_handler.cc
@@ -168,7 +168,8 @@
       video ? arraysize(kVideoCodecs) : arraysize(kAudioCodecs);
 
   std::vector<std::string> codecs_list;
-  media::SplitCodecsToVector(web_codecs.Utf8(), &codecs_list, true /* strip */);
+  media::SplitCodecs(web_codecs.Utf8(), &codecs_list);
+  media::StripCodecs(&codecs_list);
   for (const auto& codec : codecs_list) {
     auto* const* found = std::find_if(
         &codecs[0], &codecs[codecs_count], [&codec](const char* name) {
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 20d0ca5..1e07fe5 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -4584,6 +4584,8 @@
   if (!frame_->Parent()) {
     Send(new FrameHostMsg_DocumentOnLoadCompleted(routing_id_));
   }
+  for (auto& observer : observers_)
+    observer.DidHandleOnloadEvents();
 }
 
 void RenderFrameImpl::DidFailLoad(const WebURLError& error,
diff --git a/content/shell/test_runner/web_frame_test_client.cc b/content/shell/test_runner/web_frame_test_client.cc
index c8bc5aa4..2325db1 100644
--- a/content/shell/test_runner/web_frame_test_client.cc
+++ b/content/shell/test_runner/web_frame_test_client.cc
@@ -45,30 +45,6 @@
 
 namespace {
 
-void PrintFrameDescription(WebTestDelegate* delegate,
-                           blink::WebLocalFrame* frame) {
-  std::string name = content::GetFrameNameForLayoutTests(frame);
-  if (frame == frame->View()->MainFrame()) {
-    DCHECK(name.empty());
-    delegate->PrintMessage("main frame");
-    return;
-  }
-  if (name.empty()) {
-    delegate->PrintMessage("frame (anonymous)");
-    return;
-  }
-  delegate->PrintMessage(std::string("frame \"") + name + "\"");
-}
-
-void PrintFrameuserGestureStatus(WebTestDelegate* delegate,
-                                 blink::WebLocalFrame* frame,
-                                 const char* msg) {
-  bool is_user_gesture =
-      blink::WebUserGestureIndicator::IsProcessingUserGesture(frame);
-  delegate->PrintMessage(std::string("Frame with user gesture \"") +
-                         (is_user_gesture ? "true" : "false") + "\"" + msg);
-}
-
 // Used to write a platform neutral file:/// URL by taking the
 // filename and its directory. (e.g., converts
 // "file:///tmp/foo/bar.txt" to just "bar.txt").
@@ -181,6 +157,22 @@
 
 WebFrameTestClient::~WebFrameTestClient() {}
 
+// static
+void WebFrameTestClient::PrintFrameDescription(WebTestDelegate* delegate,
+                                               blink::WebLocalFrame* frame) {
+  std::string name = content::GetFrameNameForLayoutTests(frame);
+  if (frame == frame->View()->MainFrame()) {
+    DCHECK(name.empty());
+    delegate->PrintMessage("main frame");
+    return;
+  }
+  if (name.empty()) {
+    delegate->PrintMessage("frame (anonymous)");
+    return;
+  }
+  delegate->PrintMessage(std::string("frame \"") + name + "\"");
+}
+
 void WebFrameTestClient::RunModalAlertDialog(const blink::WebString& message) {
   if (!test_runner()->ShouldDumpJavaScriptDialogs())
     return;
@@ -384,66 +376,6 @@
   }
 }
 
-void WebFrameTestClient::LoadErrorPage(int reason) {
-  if (test_runner()->shouldDumpFrameLoadCallbacks()) {
-    delegate_->PrintMessage(base::StringPrintf(
-        "- loadErrorPage: %s\n", net::ErrorToString(reason).c_str()));
-  }
-}
-
-void WebFrameTestClient::DidStartProvisionalLoad(
-    blink::WebDocumentLoader* document_loader,
-    blink::WebURLRequest& request) {
-  // PlzNavigate
-  // A provisional load notification is received when a frame navigation is
-  // sent to the browser. We don't want to log it again during commit.
-  if (delegate_->IsNavigationInitiatedByRenderer(request))
-    return;
-
-  test_runner()->tryToSetTopLoadingFrame(
-      web_frame_test_proxy_base_->web_frame());
-
-  if (test_runner()->shouldDumpFrameLoadCallbacks()) {
-    PrintFrameDescription(delegate_, web_frame_test_proxy_base_->web_frame());
-    delegate_->PrintMessage(" - didStartProvisionalLoadForFrame\n");
-  }
-
-  if (test_runner()->shouldDumpUserGestureInFrameLoadCallbacks()) {
-    PrintFrameuserGestureStatus(delegate_,
-                                web_frame_test_proxy_base_->web_frame(),
-                                " - in didStartProvisionalLoadForFrame\n");
-  }
-}
-
-void WebFrameTestClient::DidFailProvisionalLoad(
-    const blink::WebURLError& error,
-    blink::WebHistoryCommitType commit_type) {
-  if (test_runner()->shouldDumpFrameLoadCallbacks()) {
-    PrintFrameDescription(delegate_, web_frame_test_proxy_base_->web_frame());
-    delegate_->PrintMessage(" - didFailProvisionalLoadWithError\n");
-  }
-}
-
-void WebFrameTestClient::DidCommitProvisionalLoad(
-    const blink::WebHistoryItem& history_item,
-    blink::WebHistoryCommitType history_type,
-    blink::WebGlobalObjectReusePolicy) {
-  if (test_runner()->shouldDumpFrameLoadCallbacks()) {
-    PrintFrameDescription(delegate_, web_frame_test_proxy_base_->web_frame());
-    delegate_->PrintMessage(" - didCommitLoadForFrame\n");
-  }
-}
-
-void WebFrameTestClient::DidFinishSameDocumentNavigation(
-    const blink::WebHistoryItem& history_item,
-    blink::WebHistoryCommitType history_type,
-    bool content_initiated) {
-  if (test_runner()->shouldDumpFrameLoadCallbacks()) {
-    PrintFrameDescription(delegate_, web_frame_test_proxy_base_->web_frame());
-    delegate_->PrintMessage(" - didCommitLoadForFrame\n");
-  }
-}
-
 void WebFrameTestClient::DidReceiveTitle(const blink::WebString& title,
                                          blink::WebTextDirection direction) {
   if (test_runner()->shouldDumpFrameLoadCallbacks() &&
@@ -465,20 +397,6 @@
   }
 }
 
-void WebFrameTestClient::DidFinishDocumentLoad() {
-  if (test_runner()->shouldDumpFrameLoadCallbacks()) {
-    PrintFrameDescription(delegate_, web_frame_test_proxy_base_->web_frame());
-    delegate_->PrintMessage(" - didFinishDocumentLoadForFrame\n");
-  }
-}
-
-void WebFrameTestClient::DidHandleOnloadEvents() {
-  if (test_runner()->shouldDumpFrameLoadCallbacks()) {
-    PrintFrameDescription(delegate_, web_frame_test_proxy_base_->web_frame());
-    delegate_->PrintMessage(" - didHandleOnloadEventsForFrame\n");
-  }
-}
-
 void WebFrameTestClient::DidFailLoad(const blink::WebURLError& error,
                                      blink::WebHistoryCommitType commit_type) {
   if (test_runner()->shouldDumpFrameLoadCallbacks()) {
@@ -487,11 +405,9 @@
   }
 }
 
-void WebFrameTestClient::DidFinishLoad() {
-  if (test_runner()->shouldDumpFrameLoadCallbacks()) {
-    PrintFrameDescription(delegate_, web_frame_test_proxy_base_->web_frame());
-    delegate_->PrintMessage(" - didFinishLoadForFrame\n");
-  }
+void WebFrameTestClient::DidStartLoading() {
+  test_runner()->tryToSetTopLoadingFrame(
+      web_frame_test_proxy_base_->web_frame());
 }
 
 void WebFrameTestClient::DidStopLoading() {
@@ -499,12 +415,6 @@
       web_frame_test_proxy_base_->web_frame());
 }
 
-void WebFrameTestClient::DidDetectXSS(const blink::WebURL& insecure_url,
-                                      bool did_block_entire_page) {
-  if (test_runner()->shouldDumpFrameLoadCallbacks())
-    delegate_->PrintMessage("didDetectXSS\n");
-}
-
 void WebFrameTestClient::DidDispatchPingLoader(const blink::WebURL& url) {
   if (test_runner()->shouldDumpPingLoaderCallbacks())
     delegate_->PrintMessage(std::string("PingLoader dispatched to '") +
diff --git a/content/shell/test_runner/web_frame_test_client.h b/content/shell/test_runner/web_frame_test_client.h
index d787f4a..ac30611 100644
--- a/content/shell/test_runner/web_frame_test_client.h
+++ b/content/shell/test_runner/web_frame_test_client.h
@@ -33,6 +33,9 @@
 
   ~WebFrameTestClient() override;
 
+  static void PrintFrameDescription(WebTestDelegate* delegate,
+                                    blink::WebLocalFrame* frame);
+
   // WebLocalFrameClient overrides needed by WebFrameTestProxy.
   void RunModalAlertDialog(const blink::WebString& message) override;
   bool RunModalConfirmDialog(const blink::WebString& message) override;
@@ -57,29 +60,13 @@
                    blink::WebLocalFrameClient::CrossOriginRedirects
                        cross_origin_redirect_behavior,
                    mojo::ScopedMessagePipeHandle blob_url_token) override;
-  void LoadErrorPage(int reason) override;
-  void DidStartProvisionalLoad(blink::WebDocumentLoader* loader,
-                               blink::WebURLRequest& request) override;
-  void DidFailProvisionalLoad(const blink::WebURLError& error,
-                              blink::WebHistoryCommitType commit_type) override;
-  void DidCommitProvisionalLoad(const blink::WebHistoryItem& history_item,
-                                blink::WebHistoryCommitType history_type,
-                                blink::WebGlobalObjectReusePolicy) override;
-  void DidFinishSameDocumentNavigation(
-      const blink::WebHistoryItem& history_item,
-      blink::WebHistoryCommitType history_type,
-      bool content_initiated) override;
   void DidReceiveTitle(const blink::WebString& title,
                        blink::WebTextDirection direction) override;
   void DidChangeIcon(blink::WebIconURL::Type icon_type) override;
-  void DidFinishDocumentLoad() override;
-  void DidHandleOnloadEvents() override;
   void DidFailLoad(const blink::WebURLError& error,
                    blink::WebHistoryCommitType commit_type) override;
-  void DidFinishLoad() override;
+  void DidStartLoading() override;
   void DidStopLoading() override;
-  void DidDetectXSS(const blink::WebURL& insecure_url,
-                    bool did_block_entire_page) override;
   void DidDispatchPingLoader(const blink::WebURL& url) override;
   void WillSendRequest(blink::WebURLRequest& request) override;
   void DidReceiveResponse(const blink::WebURLResponse& response) override;
diff --git a/content/shell/test_runner/web_frame_test_proxy.cc b/content/shell/test_runner/web_frame_test_proxy.cc
index c8868f7..66b098a 100644
--- a/content/shell/test_runner/web_frame_test_proxy.cc
+++ b/content/shell/test_runner/web_frame_test_proxy.cc
@@ -4,11 +4,113 @@
 
 #include "content/shell/test_runner/web_frame_test_proxy.h"
 
+#include "content/public/renderer/render_frame_observer.h"
+#include "content/shell/test_runner/test_interfaces.h"
+#include "content/shell/test_runner/test_runner.h"
+#include "content/shell/test_runner/web_frame_test_client.h"
+#include "content/shell/test_runner/web_test_delegate.h"
 #include "content/shell/test_runner/web_test_interfaces.h"
 #include "content/shell/test_runner/web_view_test_proxy.h"
+#include "third_party/blink/public/web/web_user_gesture_indicator.h"
 
 namespace test_runner {
 
+namespace {
+
+void PrintFrameUserGestureStatus(WebTestDelegate* delegate,
+                                 blink::WebLocalFrame* frame,
+                                 const char* msg) {
+  bool is_user_gesture =
+      blink::WebUserGestureIndicator::IsProcessingUserGesture(frame);
+  delegate->PrintMessage(std::string("Frame with user gesture \"") +
+                         (is_user_gesture ? "true" : "false") + "\"" + msg);
+}
+
+class TestRenderFrameObserver : public content::RenderFrameObserver {
+ public:
+  TestRenderFrameObserver(content::RenderFrame* frame, WebViewTestProxy* proxy)
+      : RenderFrameObserver(frame), web_view_test_proxy_(proxy) {}
+
+  ~TestRenderFrameObserver() override {}
+
+ private:
+  TestRunner* test_runner() {
+    return web_view_test_proxy_->test_interfaces()->GetTestRunner();
+  }
+
+  WebTestDelegate* delegate() { return web_view_test_proxy_->delegate(); }
+
+  // content::RenderFrameObserver overrides.
+  void OnDestruct() override { delete this; }
+
+  void DidStartProvisionalLoad(blink::WebDocumentLoader* document_loader,
+                               bool is_content_initiated) override {
+    // A provisional load notification is received when a frame navigation is
+    // sent to the browser. We don't want to log it again during commit.
+    if (delegate()->IsNavigationInitiatedByRenderer(
+            document_loader->GetRequest())) {
+      return;
+    }
+
+    if (test_runner()->shouldDumpFrameLoadCallbacks()) {
+      WebFrameTestClient::PrintFrameDescription(delegate(),
+                                                render_frame()->GetWebFrame());
+      delegate()->PrintMessage(" - didStartProvisionalLoadForFrame\n");
+    }
+
+    if (test_runner()->shouldDumpUserGestureInFrameLoadCallbacks()) {
+      PrintFrameUserGestureStatus(delegate(), render_frame()->GetWebFrame(),
+                                  " - in didStartProvisionalLoadForFrame\n");
+    }
+  }
+
+  void DidFailProvisionalLoad(const blink::WebURLError& error) override {
+    if (test_runner()->shouldDumpFrameLoadCallbacks()) {
+      WebFrameTestClient::PrintFrameDescription(delegate(),
+                                                render_frame()->GetWebFrame());
+      delegate()->PrintMessage(" - didFailProvisionalLoadWithError\n");
+    }
+  }
+
+  void DidCommitProvisionalLoad(bool is_same_document_navigation,
+                                ui::PageTransition transition) override {
+    if (test_runner()->shouldDumpFrameLoadCallbacks()) {
+      WebFrameTestClient::PrintFrameDescription(delegate(),
+                                                render_frame()->GetWebFrame());
+      delegate()->PrintMessage(" - didCommitLoadForFrame\n");
+    }
+  }
+
+  void DidFinishDocumentLoad() override {
+    if (test_runner()->shouldDumpFrameLoadCallbacks()) {
+      WebFrameTestClient::PrintFrameDescription(delegate(),
+                                                render_frame()->GetWebFrame());
+      delegate()->PrintMessage(" - didFinishDocumentLoadForFrame\n");
+    }
+  }
+
+  void DidFinishLoad() override {
+    if (test_runner()->shouldDumpFrameLoadCallbacks()) {
+      WebFrameTestClient::PrintFrameDescription(delegate(),
+                                                render_frame()->GetWebFrame());
+      delegate()->PrintMessage(" - didFinishLoadForFrame\n");
+    }
+  }
+
+  void DidHandleOnloadEvents() override {
+    if (test_runner()->shouldDumpFrameLoadCallbacks()) {
+      WebFrameTestClient::PrintFrameDescription(delegate(),
+                                                render_frame()->GetWebFrame());
+      delegate()->PrintMessage(" - didHandleOnloadEventsForFrame\n");
+    }
+  }
+
+  WebViewTestProxy* web_view_test_proxy_;
+  DISALLOW_COPY_AND_ASSIGN(TestRenderFrameObserver);
+};
+
+}  // namespace
+
 WebFrameTestProxy::~WebFrameTestProxy() = default;
 
 void WebFrameTestProxy::Initialize(
@@ -20,6 +122,7 @@
 
   test_client_ =
       interfaces->CreateWebFrameTestClient(view_proxy_for_frame, this);
+  new TestRenderFrameObserver(this, view_proxy_for_frame);  // deletes itself.
 }
 
 // WebLocalFrameClient implementation.
@@ -53,44 +156,6 @@
                                std::move(blob_url_token));
 }
 
-void WebFrameTestProxy::DidStartProvisionalLoad(
-    blink::WebDocumentLoader* document_loader,
-    blink::WebURLRequest& request) {
-  test_client_->DidStartProvisionalLoad(document_loader, request);
-  RenderFrameImpl::DidStartProvisionalLoad(document_loader, request);
-}
-
-void WebFrameTestProxy::DidFailProvisionalLoad(
-    const blink::WebURLError& error,
-    blink::WebHistoryCommitType commit_type) {
-  test_client_->DidFailProvisionalLoad(error, commit_type);
-  // If the test finished, don't notify the embedder of the failed load,
-  // as we already destroyed the document loader.
-  if (!web_frame()->GetProvisionalDocumentLoader())
-    return;
-  RenderFrameImpl::DidFailProvisionalLoad(error, commit_type);
-}
-
-void WebFrameTestProxy::DidCommitProvisionalLoad(
-    const blink::WebHistoryItem& item,
-    blink::WebHistoryCommitType commit_type,
-    blink::WebGlobalObjectReusePolicy global_object_reuse_policy) {
-  test_client_->DidCommitProvisionalLoad(item, commit_type,
-                                         global_object_reuse_policy);
-  RenderFrameImpl::DidCommitProvisionalLoad(item, commit_type,
-                                            global_object_reuse_policy);
-}
-
-void WebFrameTestProxy::DidFinishSameDocumentNavigation(
-    const blink::WebHistoryItem& item,
-    blink::WebHistoryCommitType commit_type,
-    bool content_initiated) {
-  test_client_->DidFinishSameDocumentNavigation(item, commit_type,
-                                                content_initiated);
-  RenderFrameImpl::DidFinishSameDocumentNavigation(item, commit_type,
-                                                   content_initiated);
-}
-
 void WebFrameTestProxy::DidReceiveTitle(const blink::WebString& title,
                                         blink::WebTextDirection direction) {
   test_client_->DidReceiveTitle(title, direction);
@@ -102,25 +167,15 @@
   RenderFrameImpl::DidChangeIcon(icon_type);
 }
 
-void WebFrameTestProxy::DidFinishDocumentLoad() {
-  test_client_->DidFinishDocumentLoad();
-  RenderFrameImpl::DidFinishDocumentLoad();
-}
-
-void WebFrameTestProxy::DidHandleOnloadEvents() {
-  test_client_->DidHandleOnloadEvents();
-  RenderFrameImpl::DidHandleOnloadEvents();
-}
-
 void WebFrameTestProxy::DidFailLoad(const blink::WebURLError& error,
                                     blink::WebHistoryCommitType commit_type) {
   test_client_->DidFailLoad(error, commit_type);
   RenderFrameImpl::DidFailLoad(error, commit_type);
 }
 
-void WebFrameTestProxy::DidFinishLoad() {
-  RenderFrameImpl::DidFinishLoad();
-  test_client_->DidFinishLoad();
+void WebFrameTestProxy::DidStartLoading() {
+  test_client_->DidStartLoading();
+  RenderFrameImpl::DidStartLoading();
 }
 
 void WebFrameTestProxy::DidStopLoading() {
@@ -173,14 +228,6 @@
   RenderFrameImpl::ShowContextMenu(context_menu_data);
 }
 
-void WebFrameTestProxy::DidDetectXSS(const blink::WebURL& insecure_url,
-                                     bool did_block_entire_page) {
-  // This is not implemented in RenderFrameImpl, so need to explicitly call
-  // into the base proxy.
-  test_client_->DidDetectXSS(insecure_url, did_block_entire_page);
-  RenderFrameImpl::DidDetectXSS(insecure_url, did_block_entire_page);
-}
-
 void WebFrameTestProxy::DidDispatchPingLoader(const blink::WebURL& url) {
   // This is not implemented in RenderFrameImpl, so need to explicitly call
   // into the base proxy.
diff --git a/content/shell/test_runner/web_frame_test_proxy.h b/content/shell/test_runner/web_frame_test_proxy.h
index c72ff70..f037de52 100644
--- a/content/shell/test_runner/web_frame_test_proxy.h
+++ b/content/shell/test_runner/web_frame_test_proxy.h
@@ -67,25 +67,12 @@
                    blink::WebLocalFrameClient::CrossOriginRedirects
                        cross_origin_redirect_behavior,
                    mojo::ScopedMessagePipeHandle blob_url_token) override;
-  void DidStartProvisionalLoad(blink::WebDocumentLoader* document_loader,
-                               blink::WebURLRequest& request) override;
-  void DidFailProvisionalLoad(const blink::WebURLError& error,
-                              blink::WebHistoryCommitType commit_type) override;
-  void DidCommitProvisionalLoad(
-      const blink::WebHistoryItem& item,
-      blink::WebHistoryCommitType commit_type,
-      blink::WebGlobalObjectReusePolicy global_object_reuse_policy) override;
-  void DidFinishSameDocumentNavigation(const blink::WebHistoryItem& item,
-                                       blink::WebHistoryCommitType commit_type,
-                                       bool content_initiated) override;
   void DidReceiveTitle(const blink::WebString& title,
                        blink::WebTextDirection direction) override;
   void DidChangeIcon(blink::WebIconURL::Type icon_type) override;
-  void DidFinishDocumentLoad() override;
-  void DidHandleOnloadEvents() override;
   void DidFailLoad(const blink::WebURLError& error,
                    blink::WebHistoryCommitType commit_type) override;
-  void DidFinishLoad() override;
+  void DidStartLoading() override;
   void DidStopLoading() override;
   void DidChangeSelection(bool is_selection_empty) override;
   void DidChangeContents() override;
@@ -98,8 +85,6 @@
   bool RunModalBeforeUnloadDialog(bool is_reload) override;
   void ShowContextMenu(
       const blink::WebContextMenuData& context_menu_data) override;
-  void DidDetectXSS(const blink::WebURL& insecure_url,
-                    bool did_block_entire_page) override;
   void DidDispatchPingLoader(const blink::WebURL& url) override;
   void WillSendRequest(blink::WebURLRequest& request) override;
   void DidReceiveResponse(const blink::WebURLResponse& response) override;
diff --git a/content/test/gpu/gpu_tests/pixel_test_pages.py b/content/test/gpu/gpu_tests/pixel_test_pages.py
index 2caddf95..33318e5b 100644
--- a/content/test/gpu/gpu_tests/pixel_test_pages.py
+++ b/content/test/gpu/gpu_tests/pixel_test_pages.py
@@ -543,7 +543,7 @@
       'pixel_canvas_display_linear-rgb.html',
       base_name + '_CanvasDisplayLinearRGBAccelerated2D',
       test_rect=[0, 0, 140, 140],
-      revision=4,
+      revision=5,
       browser_args=browser_args),
 
     PixelTestPage(
@@ -557,7 +557,7 @@
       'pixel_canvas_display_linear-rgb.html',
       base_name + '_CanvasDisplayLinearRGBUnaccelerated2DGPUCompositing',
       test_rect=[0, 0, 140, 140],
-      revision=4,
+      revision=5,
       browser_args=browser_args + ['--disable-accelerated-2d-canvas']),
 
     PixelTestPage(
diff --git a/extensions/browser/extension_event_histogram_value.h b/extensions/browser/extension_event_histogram_value.h
index 247a6c9..cd8295f9 100644
--- a/extensions/browser/extension_event_histogram_value.h
+++ b/extensions/browser/extension_event_histogram_value.h
@@ -260,7 +260,7 @@
   SOCKETS_UDP_ON_RECEIVE = 239,
   SOCKETS_UDP_ON_RECEIVE_ERROR = 240,
   STORAGE_ON_CHANGED = 241,
-  STREAMS_PRIVATE_ON_EXECUTE_MIME_TYPE_HANDLER = 242,
+  DELETED_STREAMS_PRIVATE_ON_EXECUTE_MIME_TYPE_HANDLER = 242,
   SYNC_FILE_SYSTEM_ON_FILE_STATUS_CHANGED = 243,
   SYNC_FILE_SYSTEM_ON_SERVICE_STATUS_CHANGED = 244,
   SYSTEM_DISPLAY_ON_DISPLAY_CHANGED = 245,
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index dcb58e12..e47008d 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -841,7 +841,7 @@
   ENTERPRISE_PLATFORMKEYS_IMPORTCERTIFICATE = 780,
   ENTERPRISE_PLATFORMKEYS_REMOVECERTIFICATE = 781,
   FILEMANAGERPRIVATE_OPENINSPECTOR = 782,
-  STREAMSPRIVATE_ABORT = 783,
+  DELETED_STREAMSPRIVATE_ABORT = 783,
   MANAGEMENT_SETLAUNCHTYPE = 784,
   MANAGEMENT_GENERATEAPPFORLINK = 785,
   DELETED_GUESTVIEWINTERNAL_ALLOCATEINSTANCEID = 786,
diff --git a/extensions/common/manifest_handlers/mime_types_handler.h b/extensions/common/manifest_handlers/mime_types_handler.h
index 807153d..22dfd725 100644
--- a/extensions/common/manifest_handlers/mime_types_handler.h
+++ b/extensions/common/manifest_handlers/mime_types_handler.h
@@ -44,8 +44,7 @@
   const std::set<std::string>& mime_type_set() const { return mime_type_set_; }
 
   // Returns true if this MimeTypesHandler has a plugin associated with it (for
-  // the mimeHandlerPrivate API). Returns false if the MimeTypesHandler is for
-  // the streamsPrivate API.
+  // the mimeHandlerPrivate API).
   bool HasPlugin() const;
 
   // If HasPlugin() returns true, this will return the plugin path for the
diff --git a/extensions/common/permissions/api_permission.h b/extensions/common/permissions/api_permission.h
index 211db96b..58ed2bad 100644
--- a/extensions/common/permissions/api_permission.h
+++ b/extensions/common/permissions/api_permission.h
@@ -175,7 +175,7 @@
     kSocket = 131,
     kStartupPages = 132,
     kStorage = 133,
-    kStreamsPrivate = 134,
+    kDeleted_StreamsPrivate = 134,
     kSyncFileSystem = 135,
     kSystemPrivate = 136,
     kSystemDisplay = 137,
diff --git a/gpu/config/gpu_util.cc b/gpu/config/gpu_util.cc
index 522bd45..d3760c9 100644
--- a/gpu/config/gpu_util.cc
+++ b/gpu/config/gpu_util.cc
@@ -239,6 +239,11 @@
     gpu_feature_info->status_values[GPU_FEATURE_TYPE_ACCELERATED_WEBGL2] =
         kGpuFeatureStatusBlacklisted;
   }
+
+  if (gpu_feature_info->IsWorkaroundEnabled(DISABLE_AIMAGEREADER)) {
+    gpu_feature_info->status_values[GPU_FEATURE_TYPE_ANDROID_SURFACE_CONTROL] =
+        kGpuFeatureStatusBlacklisted;
+  }
 }
 
 GPUInfo* g_gpu_info_cache = nullptr;
diff --git a/infra/config/branch/cq.cfg b/infra/config/branch/cq.cfg
index 7b7db9c5..d5053fc4 100644
--- a/infra/config/branch/cq.cfg
+++ b/infra/config/branch/cq.cfg
@@ -37,11 +37,30 @@
       builders { name: "android_cronet" }
       builders { name: "android-kitkat-arm-rel" }
       builders { name: "android-marshmallow-arm64-rel" }
+      builders {
+        name: "android_optional_gpu_tests_rel"
+        path_regexp: "cc/.+"
+        path_regexp: "chrome/browser/vr/.+"
+        path_regexp: "components/viz/.+"
+        path_regexp: "content/test/gpu/.+"
+        path_regexp: "gpu/.+"
+        path_regexp: "media/(audio|filters|gpu)/.+"
+        path_regexp: "services/viz/.+"
+        path_regexp: "testing/trigger_scripts/.+"
+        path_regexp: "third_party/blink/renderer/modules/webgl/.+"
+        path_regexp: "ui/gl/.+"
+      }
       builders { name: "cast_shell_android" }
       builders { name: "cast_shell_linux" }
       builders { name: "chromeos-amd64-generic-rel" }
       builders { name: "chromeos-daisy-rel" }
       builders { name: "chromium_presubmit" }
+      builders {
+        name: "closure_compilation"
+        path_regexp: "components/offline_pages/resources/.+"
+        path_regexp: "third_party/closure_compiler/.+"
+        path_regexp: "third_party/polymer/.+"
+      }
       builders { name: "fuchsia_arm64" }
       builders { name: "fuchsia_x64" }
       # https://crbug.com/739556; make this non-experimental ASAP.
@@ -55,12 +74,36 @@
         experiment_percentage: 10
       }
       builders { name: "ios-simulator" }
+      builders {
+        name: "ios-simulator-cronet"
+        # TODO(crbug.com/881860): Add "components/cronet/<anything except "android">"
+        path_regexp: "components/grpc_support/.+"
+        path_regexp: "ios/.+"
+      }
+      builders {
+        name: "ios-simulator-full-configs"
+        path_regexp: "ios/.+"
+      }
       # https://crbug.com/739556
       builders {
         name: "ios-simulator-xcode-clang"
         experiment_percentage: 10
       }
+      builders {
+        name: "linux-blink-gen-property-trees"
+        path_regexp: "third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-gen-property-trees"
+        path_regexp: "third_party/WebKit/LayoutTests/flag-specific/enable-blink-gen-property-trees/.+"
+      }
       builders { name: "linux-chromeos-rel" }
+      builders { name: "linux_chromium_asan_rel_ng" }
+      builders { name: "linux_chromium_compile_dbg_ng" }
+      builders {
+        name: "linux_chromium_dbg_ng"
+        path_regexp: "build/.*check_gn_headers.*"
+      }
+      builders { name: "linux_chromium_headless_rel" }
+      builders { name: "linux_chromium_rel_ng" }
+      builders { name: "linux_chromium_tsan_rel_ng" }
       # https://crbug.com/833482
       builders {
         name: "linux-dcheck-off-rel"
@@ -72,22 +115,106 @@
         experiment_percentage: 5
       }
       builders { name: "linux-jumbo-rel" }
+      builders {
+        name: "linux_layout_tests_layout_ng"
+        path_regexp: "third_party/Webkit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG"
+        path_regexp: "third_party/Webkit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/.+"
+        path_regexp: "third_party/blink/renderer/core/(editing|layout|paint)/.+"
+        path_regexp: "third_party/blink/renderer/platform/fonts/.+"
+      }
+      builders {
+        name: "linux_layout_tests_slimming_paint_v2"
+        path_regexp: "third_party/WebKit/LayoutTests/FlagExpectations/(enable-slimming-paint-v2|enable-blink-gen-property-trees)"
+        path_regexp: "third_party/WebKit/LayoutTests/flag-specific/(enable-slimming-paint-v2|enable-blink-gen-property-trees)/.+"
+        path_regexp: "third_party/blink/renderer/core/(layout|svg|paint)/.+"
+        path_regexp: "third_party/blink/renderer/platform/graphics/.+"
+      }
       builders { name: "linux-libfuzzer-asan-rel" }
+      builders {
+        name: "linux_mojo"
+        path_regexp: "services/network/.+"
+        path_regexp: "testing/buildbot/filters/mojo\\.fyi\\.network_.*"
+        path_regexp: "third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService"
+        path_regexp: "third_party/WebKit/LayoutTests/flag-specific/enable-features=NetworkService/.+"
+      }
       builders { name: "linux-ozone-rel" }
-      builders { name: "linux_chromium_compile_dbg_ng" }
-      builders { name: "linux_chromium_asan_rel_ng" }
-      builders { name: "linux_chromium_headless_rel" }
-      builders { name: "linux_chromium_rel_ng" }
-      builders { name: "linux_chromium_tsan_rel_ng" }
+      builders {
+        name: "linux_optional_gpu_tests_rel"
+        path_regexp: "chrome/browser/vr/.+"
+        path_regexp: "content/test/gpu/.+"
+        path_regexp: "gpu/.+"
+        path_regexp: "media/(audio|filters|gpu)/.+"
+        path_regexp: "testing/trigger_scripts/.+"
+        path_regexp: "third_party/blink/renderer/modules/webgl/.+"
+        path_regexp: "ui/gl/.+"
+      }
+      builders {
+        name: "linux_vr"
+        path_regexp: "chrome/browser/vr/.+"
+      }
       builders { name: "mac_chromium_compile_dbg_ng" }
       builders { name: "mac_chromium_rel_ng" }
+      builders {
+        name: "mac_optional_gpu_tests_rel"
+        path_regexp: "chrome/browser/vr/.+"
+        path_regexp: "content/test/gpu/.+"
+        path_regexp: "gpu/.+"
+        path_regexp: "media/(audio|filters|gpu)/.+"
+        path_regexp: "services/shape_detection/.+"
+        path_regexp: "testing/trigger_scripts/.+"
+        path_regexp: "third_party/blink/renderer/modules/webgl/.+"
+        path_regexp: "ui/gl/.+"
+      }
       builders { name: "win10_chromium_x64_rel_ng" }
-      builders { name: "win_chromium_compile_dbg_ng" }
-      builders { name: "win7_chromium_rel_ng"}
       builders {
         name: "win7_chromium_rel_loc_exp"
         experiment_percentage: 20
       }
+      builders { name: "win7_chromium_rel_ng"}
+      builders { name: "win_chromium_compile_dbg_ng" }
+      builders {
+        name: "win_optional_gpu_tests_rel"
+        path_regexp: "chrome/browser/vr/.+"
+        path_regexp: "content/test/gpu/.+"
+        path_regexp: "device/vr/.+"
+        path_regexp: "gpu/.+"
+        path_regexp: "media/(audio|filters|gpu)/.+"
+        path_regexp: "testing/trigger_scripts/.+"
+        path_regexp: "third_party/blink/renderer/modules/vr/.+"
+        path_regexp: "third_party/blink/renderer/modules/webgl/.+"
+        path_regexp: "third_party/blink/renderer/modules/xr/.+"
+        path_regexp: "third_party/blink/renderer/platform/graphics/gpu/.+"
+        path_regexp: "ui/gl/.+"
+      }
+    }
+
+    buckets {
+      name: "master.tryserver.blink"
+      builders {
+        name: "linux_trusty_blink_rel"
+        path_regexp: "cc/.+"
+        path_regexp: "third_party/WebKit/LayoutTests/FlagExpectations/(enable-slimming-paint-v2|enable-blink-gen-property-trees)"
+        path_regexp: "third_party/WebKit/LayoutTests/flag-specific/(enable-slimming-paint-v2|enable-blink-gen-property-trees)/.+"
+        path_regexp: "third_party/blink/renderer/core/(layout|svg|paint)/.+"
+        path_regexp: "third_party/blink/renderer/platform/graphics/.+"
+      }
+    }
+
+    buckets {
+      name: "master.tryserver.chromium.android"
+      builders {
+        name: "android_compile_x64_dbg"
+        path_regexp: "sandbox/linux/.*(bpd_dsl|seccomp-bpf|secomp-bpf-helpers|system_headers|tests).*"
+      }
+      builders {
+        name: "android_compile_x86_dbg"
+        path_regexp: "sandbox/linux/.*(bpd_dsl|seccomp-bpf|secomp-bpf-helpers|system_headers|tests).*"
+      }
+      builders {
+        name: "android_cronet_tester"
+        # TODO(crbug.com/881860): Add "components/cronet/<anything except "ios">"
+        path_regexp: "components/grpc_support/.+"
+      }
     }
   }
 
diff --git a/ios/chrome/browser/find_in_page/find_in_page_js_unittest.mm b/ios/chrome/browser/find_in_page/find_in_page_js_unittest.mm
index 9689429..43f0314 100644
--- a/ios/chrome/browser/find_in_page/find_in_page_js_unittest.mm
+++ b/ios/chrome/browser/find_in_page/find_in_page_js_unittest.mm
@@ -221,9 +221,26 @@
   NSString* result = ExecuteJavaScript([NSString
       stringWithFormat:@"__gCrWeb.findInPage.highlightWord('%@', false, 1000)",
                        kNonAscii]);
-  DCHECK(result);
+  ASSERT_TRUE(result);
   AssertJavaScriptValue(kJavaScriptIndex, 0);
   AssertJavaScriptValue(kJavaScriptSpansLength, 1);
 }
 
+TEST_F(FindInPageJsTest, SearchForWhitespace) {
+  LoadHtml(
+      @"<html><body> <div> </div> <h1> </h1><p> <span> </span> </p> "
+      @"</body></html>");
+  // Assert the index and span count contain their initialized values.
+  AssertJavaScriptValue(kJavaScriptIndex, -1);
+  AssertJavaScriptValue(kJavaScriptSpansLength, 0);
+
+  // Search for space. Performing the search sets the index to
+  // point to the first visible occurrence of the whitespace.
+  NSString* result =
+      ExecuteJavaScript(@"__gCrWeb.findInPage.highlightWord(' ', false, 1000)");
+  ASSERT_TRUE(result);
+  AssertJavaScriptValue(kJavaScriptIndex, 0);
+  AssertJavaScriptValue(kJavaScriptSpansLength, 8);
+}
+
 }  // namespace
diff --git a/ios/chrome/browser/find_in_page/resources/find_in_page.js b/ios/chrome/browser/find_in_page/resources/find_in_page.js
index 0ae4fec..142b49e 100644
--- a/ios/chrome/browser/find_in_page/resources/find_in_page.js
+++ b/ios/chrome/browser/find_in_page/resources/find_in_page.js
@@ -171,7 +171,7 @@
     // Clean up a previous run.
     __gCrWeb['findInPage']['clearHighlight']();
   }
-  if (!findText || !findText.replace(/\u00a0|\s/g, '')) {
+  if (!findText) {
     // No searching for emptyness.
     return __gCrWeb['findInPage'].NO_RESULTS;
   }
diff --git a/ios/chrome/browser/translate/translate_service_ios.cc b/ios/chrome/browser/translate/translate_service_ios.cc
index 9a9c93f..852b2c7 100644
--- a/ios/chrome/browser/translate/translate_service_ios.cc
+++ b/ios/chrome/browser/translate/translate_service_ios.cc
@@ -22,7 +22,7 @@
           nullptr,
           base::BindOnce(&ApplicationContext::GetNetworkConnectionTracker,
                          base::Unretained(GetApplicationContext()))) {
-  resource_request_allowed_notifier_.Init(this, false /* leaky */);
+  resource_request_allowed_notifier_.Init(this, true /* leaky */);
 }
 
 TranslateServiceIOS::~TranslateServiceIOS() {
diff --git a/ios/chrome/browser/ui/history/BUILD.gn b/ios/chrome/browser/ui/history/BUILD.gn
index 2fc683c1..6c4753c 100644
--- a/ios/chrome/browser/ui/history/BUILD.gn
+++ b/ios/chrome/browser/ui/history/BUILD.gn
@@ -25,6 +25,7 @@
     "//ios/chrome/browser/history",
     "//ios/chrome/browser/sync",
     "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/context_menu",
     "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
     "//ios/chrome/browser/ui/table_view",
   ]
diff --git a/ios/chrome/browser/ui/history/history_coordinator.mm b/ios/chrome/browser/ui/history/history_coordinator.mm
index 59b0548..61a1c0a 100644
--- a/ios/chrome/browser/ui/history/history_coordinator.mm
+++ b/ios/chrome/browser/ui/history/history_coordinator.mm
@@ -9,6 +9,7 @@
 #include "components/keyed_service/core/service_access_type.h"
 #include "ios/chrome/browser/history/history_service_factory.h"
 #include "ios/chrome/browser/sync/profile_sync_service_factory.h"
+#import "ios/chrome/browser/ui/context_menu/context_menu_coordinator.h"
 #import "ios/chrome/browser/ui/history/history_clear_browsing_data_coordinator.h"
 #include "ios/chrome/browser/ui/history/history_local_commands.h"
 #import "ios/chrome/browser/ui/history/history_mediator.h"
@@ -32,6 +33,9 @@
 @property(nonatomic, strong)
     TableViewNavigationController* historyNavigationController;
 
+@property(nonatomic, strong)
+    HistoryTableViewController* historyTableViewController;
+
 // Mediator being managed by this Coordinator.
 @property(nonatomic, strong) HistoryMediator* mediator;
 
@@ -56,32 +60,33 @@
 
 - (void)start {
   // Initialize and configure HistoryTableViewController.
-  HistoryTableViewController* historyTableViewController =
-      [[HistoryTableViewController alloc] init];
-  historyTableViewController.browserState = self.browserState;
-  historyTableViewController.loader = self.loader;
+  self.historyTableViewController = [[HistoryTableViewController alloc] init];
+  self.historyTableViewController.browserState = self.browserState;
+  self.historyTableViewController.loader = self.loader;
 
   // Initialize and set HistoryMediator
   self.mediator =
       [[HistoryMediator alloc] initWithBrowserState:self.browserState];
-  historyTableViewController.imageDataSource = self.mediator;
+  self.historyTableViewController.imageDataSource = self.mediator;
 
   // Initialize and configure HistoryServices.
   _browsingHistoryDriver = std::make_unique<IOSBrowsingHistoryDriver>(
-      self.browserState, historyTableViewController);
+      self.browserState, self.historyTableViewController);
   _browsingHistoryService = std::make_unique<history::BrowsingHistoryService>(
       _browsingHistoryDriver.get(),
       ios::HistoryServiceFactory::GetForBrowserState(
           self.browserState, ServiceAccessType::EXPLICIT_ACCESS),
       ProfileSyncServiceFactory::GetForBrowserState(self.browserState));
-  historyTableViewController.historyService = _browsingHistoryService.get();
+  self.historyTableViewController.historyService =
+      _browsingHistoryService.get();
 
   // Configure and present HistoryNavigationController.
   self.historyNavigationController = [[TableViewNavigationController alloc]
-      initWithTable:historyTableViewController];
+      initWithTable:self.historyTableViewController];
   self.historyNavigationController.toolbarHidden = NO;
-  historyTableViewController.localDispatcher = self;
-  historyTableViewController.presentationDelegate = self.presentationDelegate;
+  self.historyTableViewController.localDispatcher = self;
+  self.historyTableViewController.presentationDelegate =
+      self.presentationDelegate;
   self.historyTransitioningDelegate =
       [[HistoryTransitioningDelegate alloc] init];
   self.historyNavigationController.transitioningDelegate =
@@ -102,6 +107,11 @@
 - (void)stopWithCompletion:(ProceduralBlock)completionHandler {
   if (self.historyNavigationController) {
     void (^dismissHistoryNavigation)(void) = ^void() {
+      // Make sure to stop
+      // |self.historyTableViewController.contextMenuCoordinator| before
+      // dismissing, or |self.historyNavigationController| will dismiss that
+      // instead of itself.
+      [self.historyTableViewController.contextMenuCoordinator stop];
       [self.historyNavigationController
           dismissViewControllerAnimated:YES
                              completion:completionHandler];
diff --git a/ios/chrome/browser/ui/history/history_table_view_controller.h b/ios/chrome/browser/ui/history/history_table_view_controller.h
index d1a455a..0aab21168 100644
--- a/ios/chrome/browser/ui/history/history_table_view_controller.h
+++ b/ios/chrome/browser/ui/history/history_table_view_controller.h
@@ -13,10 +13,11 @@
 class ChromeBrowserState;
 }
 
+@class ContextMenuCoordinator;
+@protocol HistoryImageDataSource;
 @protocol HistoryLocalCommands;
 @protocol HistoryPresentationDelegate;
 @protocol UrlLoader;
-@protocol HistoryImageDataSource;
 
 // ChromeTableViewController for displaying history items.
 @interface HistoryTableViewController
@@ -34,6 +35,8 @@
 @property(nonatomic, weak) id<HistoryPresentationDelegate> presentationDelegate;
 // Data source for favicon images.
 @property(nonatomic, weak) id<HistoryImageDataSource> imageDataSource;
+// Coordinator for displaying context menus for history entries.
+@property(nonatomic, strong) ContextMenuCoordinator* contextMenuCoordinator;
 
 // Initializers.
 - (instancetype)init NS_DESIGNATED_INITIALIZER;
diff --git a/ios/chrome/browser/ui/history/history_table_view_controller.mm b/ios/chrome/browser/ui/history/history_table_view_controller.mm
index d75fb66..140e525 100644
--- a/ios/chrome/browser/ui/history/history_table_view_controller.mm
+++ b/ios/chrome/browser/ui/history/history_table_view_controller.mm
@@ -83,8 +83,6 @@
 
 // Object to manage insertion of history entries into the table view model.
 @property(nonatomic, strong) HistoryEntryInserter* entryInserter;
-// Coordinator for displaying context menus for history entries.
-@property(nonatomic, strong) ContextMenuCoordinator* contextMenuCoordinator;
 // The current query for visible history entries.
 @property(nonatomic, copy) NSString* currentQuery;
 // The current status message for the tableView, it might be nil.
@@ -1028,17 +1026,10 @@
       base::SysUTF16ToNSString(url_formatter::FormatUrl(entry.URL));
   params.menu_title = [menuTitle copy];
 
-  // Present sheet/popover using controller that is added to view hierarchy.
-  // TODO(crbug.com/754642): Remove TopPresentedViewController().
-  UIViewController* topController =
-      top_view_controller::TopPresentedViewController();
+  self.contextMenuCoordinator = [[ContextMenuCoordinator alloc]
+      initWithBaseViewController:self.navigationController
+                          params:params];
 
-  self.contextMenuCoordinator =
-      [[ContextMenuCoordinator alloc] initWithBaseViewController:topController
-                                                          params:params];
-
-  // TODO(crbug.com/606503): Refactor context menu creation code to be shared
-  // with BrowserViewController.
   // Add "Open in New Tab" option.
   NSString* openInNewTabTitle =
       l10n_util::GetNSStringWithFixup(IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWTAB);
diff --git a/ios/chrome/browser/ui/omnibox/popup/BUILD.gn b/ios/chrome/browser/ui/omnibox/popup/BUILD.gn
index b42e3c3..d92c3c5f 100644
--- a/ios/chrome/browser/ui/omnibox/popup/BUILD.gn
+++ b/ios/chrome/browser/ui/omnibox/popup/BUILD.gn
@@ -32,6 +32,7 @@
     "//ios/chrome/browser/ui/ntp:util",
     "//ios/chrome/browser/ui/omnibox:omnibox_popup_shared",
     "//ios/chrome/browser/ui/omnibox:omnibox_util",
+    "//ios/chrome/browser/ui/omnibox/popup/shortcuts",
     "//ios/chrome/browser/ui/toolbar/buttons",
     "//ios/chrome/browser/ui/toolbar/public:feature_flags",
     "//ios/chrome/browser/ui/toolbar/public:public",
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm
index 97d4aa7c..189072e3 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm
@@ -15,6 +15,7 @@
 #import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_presenter.h"
 #import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.h"
 #include "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_ios.h"
+#include "ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_coordinator.h"
 #include "ios/chrome/browser/ui/ui_util.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
@@ -29,6 +30,7 @@
 
 @property(nonatomic, strong) OmniboxPopupViewController* popupViewController;
 @property(nonatomic, strong) OmniboxPopupMediator* mediator;
+@property(nonatomic, strong) ShortcutsCoordinator* shortcutsCoordinator;
 
 @end
 
@@ -76,9 +78,20 @@
                    forProtocol:@protocol(OmniboxSuggestionCommands)];
 
   _popupView->SetMediator(self.mediator);
+
+  if (base::FeatureList::IsEnabled(
+          omnibox::kOmniboxPopupShortcutIconsInZeroState)) {
+    self.shortcutsCoordinator = [[ShortcutsCoordinator alloc]
+        initWithBaseViewController:self.popupViewController
+                      browserState:self.browserState];
+    [self.shortcutsCoordinator start];
+    self.popupViewController.shortcutsViewController =
+        self.shortcutsCoordinator.viewController;
+  }
 }
 
 - (void)stop {
+  [self.shortcutsCoordinator stop];
   _popupView.reset();
   [self.dispatcher
       stopDispatchingForProtocol:@protocol(OmniboxSuggestionCommands)];
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.h b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.h
index 0cdf86ba..14157789 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.h
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.h
@@ -23,10 +23,13 @@
     : UIViewController<AutocompleteResultConsumer, OmniboxSuggestionCommands>
 
 // When enabled, this view controller will display shortcuts when no suggestions
-// are available.
+// are available. When enabling this, |shortcutsViewController| must be set.
 // This can be toggled at runtime, for example to only show shortcuts on regular
 // pages and not show them on NTP.
 @property(nonatomic, assign) BOOL shortcutsEnabled;
+// The view controller to display when no suggestions is available. See also:
+// |shortcutsEnabled|.
+@property(nonatomic, weak) UIViewController* shortcutsViewController;
 
 @property(nonatomic, assign) BOOL incognito;
 @property(nonatomic, weak) id<AutocompleteResultConsumerDelegate> delegate;
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.mm
index 0cff6487..16bb342 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.mm
@@ -17,6 +17,7 @@
 #import "ios/chrome/browser/ui/toolbar/buttons/toolbar_configuration.h"
 #include "ios/chrome/browser/ui/ui_util.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
+#include "ios/chrome/common/ui_util/constraints_ui_util.h"
 #include "ios/chrome/grit/ios_theme_resources.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -72,6 +73,10 @@
 // changes size and table view issues a scroll event.
 @property(nonatomic, assign) BOOL forwardsScrollEvents;
 
+// The cell with shortcuts to display when no results are available (only if
+// this is enabled with |shortcutsEnabled|). Lazily instantiated.
+@property(nonatomic, strong) UITableViewCell* shortcutsCell;
+
 @end
 
 @implementation OmniboxPopupViewController
@@ -217,10 +222,31 @@
     return;
   }
 
+  DCHECK(!shortcutsEnabled || self.shortcutsViewController);
+
   _shortcutsEnabled = shortcutsEnabled;
   [self.tableView reloadData];
 }
 
+- (UITableViewCell*)shortcutsCell {
+  if (_shortcutsCell) {
+    return _shortcutsCell;
+  }
+
+  DCHECK(self.shortcutsEnabled);
+  DCHECK(self.shortcutsViewController);
+
+  UITableViewCell* cell = [[UITableViewCell alloc] init];
+  [self.shortcutsViewController willMoveToParentViewController:self];
+  [self addChildViewController:self.shortcutsViewController];
+  [cell.contentView addSubview:self.shortcutsViewController.view];
+  self.shortcutsViewController.view.translatesAutoresizingMaskIntoConstraints =
+      NO;
+  AddSameConstraints(self.shortcutsViewController.view, cell.contentView);
+  [self.shortcutsViewController didMoveToParentViewController:self];
+  return cell;
+}
+
 #pragma mark - AutocompleteResultConsumer
 
 - (void)updateMatches:(NSArray<id<AutocompleteSuggestion>>*)result
@@ -648,12 +674,7 @@
 
   if (self.shortcutsEnabled && indexPath.row == 0 &&
       _currentResult.count == 0) {
-    // This is a placeholder cell.
-    UITableViewCell* cell =
-        [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
-                               reuseIdentifier:nil];
-    cell.textLabel.text = @"Shortcuts placeholder";
-    return cell;
+    return self.shortcutsCell;
   }
 
   DCHECK_LT((NSUInteger)indexPath.row, _currentResult.count);
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller_unittest.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller_unittest.mm
index 7e709d9..3117c0e 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller_unittest.mm
@@ -32,6 +32,9 @@
       (id<UITableViewDataSource>)popup_view_controller_;
   UITableView* tableView = [[UITableView alloc] init];
 
+  // A stub view controller.
+  UIViewController* shortcutsViewController = [[UIViewController alloc] init];
+
   // Shortcuts are not enabled by default.
   EXPECT_FALSE(popup_view_controller_.shortcutsEnabled);
 
@@ -39,7 +42,9 @@
   [popup_view_controller_ updateMatches:@[] withAnimation:NO];
   EXPECT_EQ([datasource tableView:tableView numberOfRowsInSection:0], 0);
 
-  // Enable shortcuts and verify they appear.
+  // Enable shortcuts and verify they appear. When enabling, the view controller
+  // has to be non-nil.
+  popup_view_controller_.shortcutsViewController = shortcutsViewController;
   popup_view_controller_.shortcutsEnabled = YES;
   EXPECT_EQ([datasource tableView:tableView numberOfRowsInSection:0], 1);
 
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_ios.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_ios.mm
index 250c2cb4..3d1ae51 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_ios.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_ios.mm
@@ -67,7 +67,7 @@
 }
 
 bool OmniboxPopupViewIOS::IsOpen() const {
-  return [mediator_ isOpen];
+  return [mediator_ hasResults];
 }
 
 OmniboxPopupModel* OmniboxPopupViewIOS::model() const {
diff --git a/ios/chrome/browser/ui/omnibox/popup/shortcuts/BUILD.gn b/ios/chrome/browser/ui/omnibox/popup/shortcuts/BUILD.gn
new file mode 100644
index 0000000..394534a3b
--- /dev/null
+++ b/ios/chrome/browser/ui/omnibox/popup/shortcuts/BUILD.gn
@@ -0,0 +1,34 @@
+# Copyright 2018 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.
+
+source_set("shortcuts") {
+  sources = [
+    "shortcuts_coordinator.h",
+    "shortcuts_coordinator.mm",
+    "shortcuts_view_controller.h",
+    "shortcuts_view_controller.mm",
+  ]
+  configs += [ "//build/config/compiler:enable_arc" ]
+
+  deps = [
+    "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
+  ]
+}
+
+source_set("unit_tests") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  testonly = true
+  sources = [
+    "shortcuts_coordinator_unittest.mm",
+    "shortcuts_view_controller_unittest.mm",
+  ]
+  deps = [
+    ":shortcuts",
+    "//base",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser",
+    "//testing/gtest",
+    "//ui/base",
+  ]
+}
diff --git a/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_coordinator.h b/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_coordinator.h
new file mode 100644
index 0000000..bb7985b3
--- /dev/null
+++ b/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_coordinator.h
@@ -0,0 +1,19 @@
+// Copyright 2018 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 IOS_CHROME_BROWSER_UI_OMNIBOX_POPUP_SHORTCUTS_SHORTCUTS_COORDINATOR_H_
+#define IOS_CHROME_BROWSER_UI_OMNIBOX_POPUP_SHORTCUTS_SHORTCUTS_COORDINATOR_H_
+
+#import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h"
+
+// The coordinator for the shortcuts.
+// Shortcuts are the tiles displayed in the omnibox in the zero state.
+@interface ShortcutsCoordinator : ChromeCoordinator
+
+// The view controller managed by this coordinator.
+@property(nonatomic, strong, readonly) UIViewController* viewController;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_OMNIBOX_POPUP_SHORTCUTS_SHORTCUTS_COORDINATOR_H_
diff --git a/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_coordinator.mm b/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_coordinator.mm
new file mode 100644
index 0000000..2c6b7f6
--- /dev/null
+++ b/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_coordinator.mm
@@ -0,0 +1,30 @@
+// Copyright 2018 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.
+
+#import "ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_coordinator.h"
+
+#import "ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_view_controller.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@interface ShortcutsCoordinator ()
+
+// Redefined as readwrite and as ShortcutsViewController.
+@property(nonatomic, strong, readwrite) ShortcutsViewController* viewController;
+
+@end
+
+@implementation ShortcutsCoordinator
+
+- (void)start {
+  self.viewController = [[ShortcutsViewController alloc] init];
+}
+
+- (void)stop {
+  self.viewController = nil;
+}
+
+@end
diff --git a/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_coordinator_unittest.mm b/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_coordinator_unittest.mm
new file mode 100644
index 0000000..4a14abeb
--- /dev/null
+++ b/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_coordinator_unittest.mm
@@ -0,0 +1,9 @@
+// Copyright 2018 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.
+
+#import "ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_coordinator.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
diff --git a/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_view_controller.h b/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_view_controller.h
new file mode 100644
index 0000000..fc8cb8d
--- /dev/null
+++ b/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_view_controller.h
@@ -0,0 +1,15 @@
+// Copyright 2018 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 IOS_CHROME_BROWSER_UI_OMNIBOX_POPUP_SHORTCUTS_SHORTCUTS_VIEW_CONTROLLER_H_
+#define IOS_CHROME_BROWSER_UI_OMNIBOX_POPUP_SHORTCUTS_SHORTCUTS_VIEW_CONTROLLER_H_
+
+#import <UIKit/UIKit.h>
+
+// The view controller displaying the omnibox shortcuts in the zero state.
+@interface ShortcutsViewController : UIViewController
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_OMNIBOX_POPUP_SHORTCUTS_SHORTCUTS_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_view_controller.mm b/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_view_controller.mm
new file mode 100644
index 0000000..e812b9cf
--- /dev/null
+++ b/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_view_controller.mm
@@ -0,0 +1,20 @@
+// Copyright 2018 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.
+
+#import "ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_view_controller.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@implementation ShortcutsViewController
+
+- (void)viewDidLoad {
+  [super viewDidLoad];
+  // Just a placeholder to see if this is really displayed.
+  self.view.backgroundColor =
+      [UIColor colorWithRed:0.5 green:0.9 blue:0.9 alpha:0.7];
+}
+
+@end
diff --git a/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_view_controller_unittest.mm b/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_view_controller_unittest.mm
new file mode 100644
index 0000000..3b0a558
--- /dev/null
+++ b/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_view_controller_unittest.mm
@@ -0,0 +1,9 @@
+// Copyright 2018 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.
+
+#import "ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_view_controller.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
diff --git a/media/audio/win/core_audio_util_win.cc b/media/audio/win/core_audio_util_win.cc
index 59869e9..b9c47d9a 100644
--- a/media/audio/win/core_audio_util_win.cc
+++ b/media/audio/win/core_audio_util_win.cc
@@ -180,15 +180,6 @@
   return os;
 }
 
-bool LoadAudiosesDll() {
-  static const wchar_t* const kAudiosesDLL =
-      L"%WINDIR%\\system32\\audioses.dll";
-
-  wchar_t path[MAX_PATH] = {0};
-  ExpandEnvironmentStringsW(kAudiosesDLL, path, arraysize(path));
-  return (LoadLibraryExW(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) != NULL);
-}
-
 std::string GetDeviceID(IMMDevice* device) {
   ScopedCoMem<WCHAR> device_id_com;
   std::string device_id;
@@ -286,18 +277,7 @@
     return false;
   }
 
-  // The audio core APIs are implemented in the Mmdevapi.dll and
-  // Audioses.dll system components. Dependency Walker shows that it is
-  // enough to verify possibility to load the Audioses DLL since it depends
-  // on Mmdevapi.dll. See http://crbug.com/166397 why this extra step is
-  // required to guarantee Core Audio support.
-  if (!LoadAudiosesDll())
-    return false;
-
-  // Being able to load the Audioses.dll does not seem to be sufficient for
-  // all devices to guarantee Core Audio support. To be 100%, we also verify
-  // that it is possible to a create the IMMDeviceEnumerator interface. If
-  // this works as well we should be home free.
+  // Verify that it is possible to a create the IMMDeviceEnumerator interface.
   ComPtr<IMMDeviceEnumerator> device_enumerator =
       CreateDeviceEnumeratorInternal(false,
                                      base::BindRepeating(&LogUMAEmptyCb));
diff --git a/media/base/mime_util.cc b/media/base/mime_util.cc
index 1409e8ec..4189766 100644
--- a/media/base/mime_util.cc
+++ b/media/base/mime_util.cc
@@ -29,28 +29,31 @@
   return GetMimeUtil()->IsSupportedMediaFormat(mime_type, codecs, true);
 }
 
-void SplitCodecsToVector(const std::string& codecs,
-                         std::vector<std::string>* codecs_out,
-                         bool strip) {
-  GetMimeUtil()->SplitCodecsToVector(codecs, codecs_out, strip);
+void SplitCodecs(const std::string& codecs,
+                 std::vector<std::string>* codecs_out) {
+  GetMimeUtil()->SplitCodecs(codecs, codecs_out);
 }
 
-MEDIA_EXPORT bool ParseVideoCodecString(const std::string& mime_type,
-                                        const std::string& codec_id,
-                                        bool* ambiguous_codec_string,
-                                        VideoCodec* out_codec,
-                                        VideoCodecProfile* out_profile,
-                                        uint8_t* out_level,
-                                        VideoColorSpace* out_colorspace) {
+void StripCodecs(std::vector<std::string>* codecs) {
+  GetMimeUtil()->StripCodecs(codecs);
+}
+
+bool ParseVideoCodecString(const std::string& mime_type,
+                           const std::string& codec_id,
+                           bool* ambiguous_codec_string,
+                           VideoCodec* out_codec,
+                           VideoCodecProfile* out_profile,
+                           uint8_t* out_level,
+                           VideoColorSpace* out_colorspace) {
   return GetMimeUtil()->ParseVideoCodecString(
       mime_type, codec_id, ambiguous_codec_string, out_codec, out_profile,
       out_level, out_colorspace);
 }
 
-MEDIA_EXPORT bool ParseAudioCodecString(const std::string& mime_type,
-                                        const std::string& codec_id,
-                                        bool* ambiguous_codec_string,
-                                        AudioCodec* out_codec) {
+bool ParseAudioCodecString(const std::string& mime_type,
+                           const std::string& codec_id,
+                           bool* ambiguous_codec_string,
+                           AudioCodec* out_codec) {
   return GetMimeUtil()->ParseAudioCodecString(
       mime_type, codec_id, ambiguous_codec_string, out_codec);
 }
diff --git a/media/base/mime_util.h b/media/base/mime_util.h
index 33f01fe..31be3bc 100644
--- a/media/base/mime_util.h
+++ b/media/base/mime_util.h
@@ -18,14 +18,17 @@
 // supported/recognized MIME types.
 MEDIA_EXPORT bool IsSupportedMediaMimeType(const std::string& mime_type);
 
-// Splits various codecs into |codecs_out|, conditionally stripping the profile
-// and level info when |strip| == true. For example, passed "aaa.b.c,dd.eee", if
-// |strip| == true |codecs_out| will contain {"aaa", "dd"}, if |strip| == false
-// |codecs_out| will contain {"aaa.b.c", "dd.eee"}.
+// Splits |codecs| separated by comma into |codecs_out|. Codecs in |codecs| may
+// or may not be quoted. For example, "\"aaa.b.c,dd.eee\"" and "aaa.b.c,dd.eee"
+// will both be split into {"aaa.b.c", "dd.eee"}.
 // See http://www.ietf.org/rfc/rfc4281.txt.
-MEDIA_EXPORT void SplitCodecsToVector(const std::string& codecs,
-                                      std::vector<std::string>* codecs_out,
-                                      bool strip);
+MEDIA_EXPORT void SplitCodecs(const std::string& codecs,
+                              std::vector<std::string>* codecs_out);
+
+// Strips the profile and level info from |codecs| in place.  For example,
+// {"aaa.b.c", "dd.eee"} will be strip into {"aaa", "dd"}.
+// See http://www.ietf.org/rfc/rfc4281.txt.
+MEDIA_EXPORT void StripCodecs(std::vector<std::string>* codecs);
 
 // Returns true if successfully parsed the given |mime_type| and |codec_id|,
 // setting |out_*| arguments to the parsed video codec, profile, and level.
diff --git a/media/base/mime_util_internal.cc b/media/base/mime_util_internal.cc
index 507384d..e95d82a 100644
--- a/media/base/mime_util_internal.cc
+++ b/media/base/mime_util_internal.cc
@@ -394,9 +394,8 @@
          media_format_map_.end();
 }
 
-void MimeUtil::SplitCodecsToVector(const std::string& codecs,
-                                   std::vector<std::string>* codecs_out,
-                                   bool strip) {
+void MimeUtil::SplitCodecs(const std::string& codecs,
+                           std::vector<std::string>* codecs_out) {
   *codecs_out =
       base::SplitString(base::TrimString(codecs, "\"", base::TRIM_ALL), ",",
                         base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
@@ -404,12 +403,11 @@
   // Convert empty or all-whitespace input to 0 results.
   if (codecs_out->size() == 1 && (*codecs_out)[0].empty())
     codecs_out->clear();
+}
 
-  if (!strip)
-    return;
-
+void MimeUtil::StripCodecs(std::vector<std::string>* codecs) {
   // Strip everything past the first '.'
-  for (auto it = codecs_out->begin(); it != codecs_out->end(); ++it) {
+  for (auto it = codecs->begin(); it != codecs->end(); ++it) {
     size_t found = it->find_first_of('.');
     if (found != std::string::npos)
       it->resize(found);
diff --git a/media/base/mime_util_internal.h b/media/base/mime_util_internal.h
index a8be8bb3..38fe068 100644
--- a/media/base/mime_util_internal.h
+++ b/media/base/mime_util_internal.h
@@ -69,9 +69,9 @@
 
   // See mime_util.h for more information on these methods.
   bool IsSupportedMediaMimeType(const std::string& mime_type) const;
-  void SplitCodecsToVector(const std::string& codecs,
-                           std::vector<std::string>* codecs_out,
-                           bool strip);
+  void SplitCodecs(const std::string& codecs,
+                   std::vector<std::string>* codecs_out);
+  void StripCodecs(std::vector<std::string>* codecs);
   bool ParseVideoCodecString(const std::string& mime_type,
                              const std::string& codec_id,
                              bool* out_is_ambiguous,
diff --git a/media/base/mime_util_unittest.cc b/media/base/mime_util_unittest.cc
index 53596fc..b66bbe1c 100644
--- a/media/base/mime_util_unittest.cc
+++ b/media/base/mime_util_unittest.cc
@@ -204,38 +204,44 @@
 
 // Note: codecs should only be a list of 2 or fewer; hence the restriction of
 // results' length to 2.
-TEST(MimeUtilTest, SplitCodecsToVector) {
+TEST(MimeUtilTest, SplitAndStripCodecs) {
   const struct {
     const char* const original;
     size_t expected_size;
-    const char* const results[2];
+    const char* const split_results[2];
+    const char* const strip_results[2];
   } tests[] = {
-    { "\"bogus\"",                  1, { "bogus" }            },
-    { "0",                          1, { "0" }                },
-    { "avc1.42E01E, mp4a.40.2",     2, { "avc1",   "mp4a" }   },
-    { "\"mp4v.20.240, mp4a.40.2\"", 2, { "mp4v",   "mp4a" }   },
-    { "mp4v.20.8, samr",            2, { "mp4v",   "samr" }   },
-    { "\"theora, vorbis\"",         2, { "theora", "vorbis" } },
-    { "",                           0, { }                    },
-    { "\"\"",                       0, { }                    },
-    { "\"   \"",                    0, { }                    },
-    { ",",                          2, { "", "" }             },
+      {"\"bogus\"", 1, {"bogus"}, {"bogus"}},
+      {"0", 1, {"0"}, {"0"}},
+      {"avc1.42E01E, mp4a.40.2",
+       2,
+       {"avc1.42E01E", "mp4a.40.2"},
+       {"avc1", "mp4a"}},
+      {"\"mp4v.20.240, mp4a.40.2\"",
+       2,
+       {"mp4v.20.240", "mp4a.40.2"},
+       {"mp4v", "mp4a"}},
+      {"mp4v.20.8, samr", 2, {"mp4v.20.8", "samr"}, {"mp4v", "samr"}},
+      {"\"theora, vorbis\"", 2, {"theora", "vorbis"}, {"theora", "vorbis"}},
+      {"", 0, {}, {}},
+      {"\"\"", 0, {}, {}},
+      {"\"   \"", 0, {}, {}},
+      {",", 2, {"", ""}, {"", ""}},
   };
 
   for (size_t i = 0; i < arraysize(tests); ++i) {
     std::vector<std::string> codecs_out;
-    SplitCodecsToVector(tests[i].original, &codecs_out, true);
+
+    SplitCodecs(tests[i].original, &codecs_out);
     ASSERT_EQ(tests[i].expected_size, codecs_out.size());
     for (size_t j = 0; j < tests[i].expected_size; ++j)
-      EXPECT_EQ(tests[i].results[j], codecs_out[j]);
-  }
+      EXPECT_EQ(tests[i].split_results[j], codecs_out[j]);
 
-  // Test without stripping the codec type.
-  std::vector<std::string> codecs_out;
-  SplitCodecsToVector("avc1.42E01E, mp4a.40.2", &codecs_out, false);
-  ASSERT_EQ(2u, codecs_out.size());
-  EXPECT_EQ("avc1.42E01E", codecs_out[0]);
-  EXPECT_EQ("mp4a.40.2", codecs_out[1]);
+    StripCodecs(&codecs_out);
+    ASSERT_EQ(tests[i].expected_size, codecs_out.size());
+    for (size_t j = 0; j < tests[i].expected_size; ++j)
+      EXPECT_EQ(tests[i].strip_results[j], codecs_out[j]);
+  }
 }
 
 // Basic smoke test for API. More exhaustive codec string testing found in
diff --git a/media/blink/key_system_config_selector.cc b/media/blink/key_system_config_selector.cc
index 63e13bf..f46c73dd 100644
--- a/media/blink/key_system_config_selector.cc
+++ b/media/blink/key_system_config_selector.cc
@@ -156,7 +156,7 @@
            << ", use_aes_decryptor=" << use_aes_decryptor;
 
   std::vector<std::string> codec_vector;
-  SplitCodecsToVector(codecs, &codec_vector, false);
+  SplitCodecs(codecs, &codec_vector);
 
   // AesDecryptor decrypts the stream in the demuxer before it reaches the
   // decoder so check whether the media format is supported when clear.
@@ -350,7 +350,8 @@
   // This check does not handle extended codecs, so extended codec information
   // is stripped (extended codec information was checked above).
   std::vector<std::string> stripped_codec_vector;
-  SplitCodecsToVector(codecs, &stripped_codec_vector, true);
+  SplitCodecs(codecs, &stripped_codec_vector);
+  StripCodecs(&stripped_codec_vector);
   EmeConfigRule codecs_rule = key_systems_->GetContentTypeConfigRule(
       key_system, media_type, container_lower, stripped_codec_vector);
   if (!config_state->IsRuleSupported(codecs_rule)) {
diff --git a/media/blink/key_system_config_selector_unittest.cc b/media/blink/key_system_config_selector_unittest.cc
index 5de42a0..7e6b354 100644
--- a/media/blink/key_system_config_selector_unittest.cc
+++ b/media/blink/key_system_config_selector_unittest.cc
@@ -136,7 +136,7 @@
     return false;
 
   std::vector<std::string> codec_vector;
-  SplitCodecsToVector(codecs, &codec_vector, false);
+  SplitCodecs(codecs, &codec_vector);
   for (const std::string& codec : codec_vector) {
     DCHECK_NE(codec, kExtendedVideoCodecStripped)
         << "codecs passed into this function should not be stripped";
diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc
index 40fdc0f4..b7be470 100644
--- a/media/filters/chunk_demuxer.cc
+++ b/media/filters/chunk_demuxer.cc
@@ -66,7 +66,7 @@
     const std::string& codecs,
     media::MediaLog* media_log) {
   std::vector<std::string> parsed_codec_ids;
-  media::SplitCodecsToVector(codecs, &parsed_codec_ids, false);
+  media::SplitCodecs(codecs, &parsed_codec_ids);
   return media::StreamParserFactory::Create(content_type, parsed_codec_ids,
                                             media_log);
 }
diff --git a/media/filters/source_buffer_state.cc b/media/filters/source_buffer_state.cc
index b13de7b..4e723a0 100644
--- a/media/filters/source_buffer_state.cc
+++ b/media/filters/source_buffer_state.cc
@@ -545,7 +545,7 @@
   expected_video_codecs_.clear();
 
   std::vector<std::string> expected_codecs_parsed;
-  SplitCodecsToVector(expected_codecs, &expected_codecs_parsed, false);
+  SplitCodecs(expected_codecs, &expected_codecs_parsed);
 
   std::vector<AudioCodec> expected_acodecs;
   std::vector<VideoCodec> expected_vcodecs;
diff --git a/media/gpu/BUILD.gn b/media/gpu/BUILD.gn
index 0e653af..07bfdef 100644
--- a/media/gpu/BUILD.gn
+++ b/media/gpu/BUILD.gn
@@ -154,6 +154,7 @@
       "android/android_video_decode_accelerator.h",
       "android/android_video_encode_accelerator.cc",
       "android/android_video_encode_accelerator.h",
+      "android/android_video_surface_chooser.cc",
       "android/android_video_surface_chooser.h",
       "android/android_video_surface_chooser_impl.cc",
       "android/android_video_surface_chooser_impl.h",
diff --git a/media/gpu/android/android_video_decode_accelerator.cc b/media/gpu/android/android_video_decode_accelerator.cc
index 2e659ccd..63cc3792 100644
--- a/media/gpu/android/android_video_decode_accelerator.cc
+++ b/media/gpu/android/android_video_decode_accelerator.cc
@@ -283,7 +283,8 @@
           std::move(surface_chooser),
           base::CommandLine::ForCurrentProcess()->HasSwitch(
               switches::kForceVideoOverlays),
-          base::FeatureList::IsEnabled(media::kUseAndroidOverlayAggressively)),
+          base::FeatureList::IsEnabled(media::kUseAndroidOverlayAggressively),
+          false /* always_use_texture_owner */),
       device_info_(device_info),
       force_defer_surface_creation_for_testing_(false),
       force_allow_software_decoding_for_testing_(false),
diff --git a/media/gpu/android/android_video_surface_chooser.cc b/media/gpu/android/android_video_surface_chooser.cc
new file mode 100644
index 0000000..dc038a8
--- /dev/null
+++ b/media/gpu/android/android_video_surface_chooser.cc
@@ -0,0 +1,12 @@
+// Copyright 2018 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 "media/gpu/android/android_video_surface_chooser.h"
+
+namespace media {
+
+AndroidVideoSurfaceChooser::State::State() = default;
+AndroidVideoSurfaceChooser::State::~State() = default;
+
+}  // namespace media
diff --git a/media/gpu/android/android_video_surface_chooser.h b/media/gpu/android/android_video_surface_chooser.h
index fd8e2bd..f02c4c7d 100644
--- a/media/gpu/android/android_video_surface_chooser.h
+++ b/media/gpu/android/android_video_surface_chooser.h
@@ -21,6 +21,9 @@
  public:
   // Input state used for choosing the surface type.
   struct State {
+    State();
+    ~State();
+
     // Is an overlay required?
     bool is_required = false;
 
@@ -49,6 +52,11 @@
 
     // Hint to use for the initial position when transitioning to an overlay.
     gfx::Rect initial_position;
+
+    // Indicates that we should always use a TextureOwner. This is used with
+    // SurfaceControl where the TextureOwner can be promoted to an overlay
+    // dynamically by the compositor.
+    bool always_use_texture_owner = false;
   };
 
   // Notify the client that |overlay| is ready for use.  The client may get
diff --git a/media/gpu/android/android_video_surface_chooser_impl.cc b/media/gpu/android/android_video_surface_chooser_impl.cc
index 547f8fa..b0843a7e 100644
--- a/media/gpu/android/android_video_surface_chooser_impl.cc
+++ b/media/gpu/android/android_video_surface_chooser_impl.cc
@@ -149,6 +149,9 @@
   if (!overlay_factory_)
     new_overlay_state = kUsingTextureOwner;
 
+  if (current_state_.always_use_texture_owner)
+    new_overlay_state = kUsingTextureOwner;
+
   // Make sure that we're in |new_overlay_state_|.
   if (new_overlay_state == kUsingTextureOwner)
     SwitchToTextureOwner();
diff --git a/media/gpu/android/android_video_surface_chooser_impl_unittest.cc b/media/gpu/android/android_video_surface_chooser_impl_unittest.cc
index a14c7468..c5ac5a7 100644
--- a/media/gpu/android/android_video_surface_chooser_impl_unittest.cc
+++ b/media/gpu/android/android_video_surface_chooser_impl_unittest.cc
@@ -373,6 +373,19 @@
   overlay_callbacks_.PowerEfficientState.Run(false);
 }
 
+TEST_F(AndroidVideoSurfaceChooserImplTest, AlwaysUseTextureOwner) {
+  // Start with an overlay.
+  chooser_state_.is_fullscreen = true;
+  StartChooserAndProvideOverlay();
+  testing::Mock::VerifyAndClearExpectations(&client_);
+
+  // Change the state to force texture owner. It should use the TextureOwner
+  // instead.
+  chooser_state_.always_use_texture_owner = true;
+  EXPECT_CALL(client_, UseTextureOwner());
+  chooser_->UpdateState(base::nullopt, chooser_state_);
+}
+
 TEST_P(AndroidVideoSurfaceChooserImplTest, OverlayIsUsedOrNotBasedOnState) {
   // Provide a factory, and verify that it is used when the state says that it
   // should be.  If the overlay is used, then we also verify that it does not
diff --git a/media/gpu/android/codec_image.cc b/media/gpu/android/codec_image.cc
index 21efc38..30e71e3 100644
--- a/media/gpu/android/codec_image.cc
+++ b/media/gpu/android/codec_image.cc
@@ -235,4 +235,12 @@
   phase_ = Phase::kInvalidated;
 }
 
+std::unique_ptr<gl::GLImage::ScopedHardwareBuffer>
+CodecImage::GetAHardwareBuffer() {
+  DCHECK(texture_owner_);
+
+  RenderToTextureOwnerFrontBuffer(BindingsMode::kDontRestore);
+  return texture_owner_->GetAHardwareBuffer();
+}
+
 }  // namespace media
diff --git a/media/gpu/android/codec_image.h b/media/gpu/android/codec_image.h
index 55bf512..5835c4f 100644
--- a/media/gpu/android/codec_image.h
+++ b/media/gpu/android/codec_image.h
@@ -54,6 +54,7 @@
   void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
                     uint64_t process_tracing_id,
                     const std::string& dump_name) override;
+  std::unique_ptr<ScopedHardwareBuffer> GetAHardwareBuffer() override;
   // gpu::gles2::GLStreamTextureMatrix implementation
   void GetTextureMatrix(float xform[16]) override;
   void NotifyPromotionHint(bool promotion_hint,
diff --git a/media/gpu/android/codec_image_unittest.cc b/media/gpu/android/codec_image_unittest.cc
index 0a71d0d..b928929 100644
--- a/media/gpu/android/codec_image_unittest.cc
+++ b/media/gpu/android/codec_image_unittest.cc
@@ -290,4 +290,15 @@
                           hint2.screen_rect, gfx::RectF(), true, nullptr);
 }
 
+TEST_F(CodecImageTest, GetAHardwareBuffer) {
+  auto i = NewImage(kTextureOwner);
+  EXPECT_EQ(texture_owner_->get_a_hardware_buffer_count, 0);
+  EXPECT_FALSE(i->was_rendered_to_front_buffer());
+
+  EXPECT_CALL(*texture_owner_, UpdateTexImage());
+  i->GetAHardwareBuffer();
+  EXPECT_EQ(texture_owner_->get_a_hardware_buffer_count, 1);
+  EXPECT_TRUE(i->was_rendered_to_front_buffer());
+}
+
 }  // namespace media
diff --git a/media/gpu/android/image_reader_gl_owner.cc b/media/gpu/android/image_reader_gl_owner.cc
index 1b7ef78..a519e693 100644
--- a/media/gpu/android/image_reader_gl_owner.cc
+++ b/media/gpu/android/image_reader_gl_owner.cc
@@ -13,6 +13,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/posix/eintr_wrapper.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "gpu/ipc/common/android/android_image_reader_utils.h"
@@ -45,6 +46,26 @@
   ~FrameAvailableEvent_ImageReader() = default;
 };
 
+class ImageReaderGLOwner::ScopedHardwareBufferImpl
+    : public gl::GLImage::ScopedHardwareBuffer {
+ public:
+  ScopedHardwareBufferImpl(scoped_refptr<ImageReaderGLOwner> texture_owner,
+                           AImage* image,
+                           base::android::ScopedHardwareBufferHandle handle,
+                           base::ScopedFD fence_fd)
+      : gl::GLImage::ScopedHardwareBuffer(std::move(handle),
+                                          std::move(fence_fd)),
+        texture_owner_(std::move(texture_owner)),
+        image_(image) {}
+  ~ScopedHardwareBufferImpl() override {
+    texture_owner_->ReleaseRefOnImage(image_);
+  }
+
+ private:
+  scoped_refptr<ImageReaderGLOwner> texture_owner_;
+  AImage* image_;
+};
+
 ImageReaderGLOwner::ImageReaderGLOwner(GLuint texture_id)
     : current_image_(nullptr),
       texture_id_(texture_id),
@@ -55,6 +76,9 @@
   DCHECK(context_);
   DCHECK(surface_);
 
+  // TODO(khushalsagar): Need plumbing here to select the correct format and
+  // usage for secure media.
+
   // Set the width, height and format to some default value. This parameters
   // are/maybe overriden by the producer sending buffers to this imageReader's
   // Surface.
@@ -97,6 +121,7 @@
 ImageReaderGLOwner::~ImageReaderGLOwner() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(image_reader_);
+  DCHECK_EQ(external_image_refs_.size(), 0u);
 
   // Now we can stop listening to new images.
   loader_.AImageReader_setImageListener(image_reader_, NULL);
@@ -191,19 +216,90 @@
   }
 
   // If we have a new Image, delete the previously acquired image.
-  if (!gpu::DeleteAImageAsync(current_image_, &loader_))
+  if (!MaybeDeleteCurrentImage())
     return;
 
-  // Make the newly acuired image as current image.
+  // Make the newly acquired image as current image.
   current_image_ = image;
+  current_image_fence_ = std::move(scoped_acquire_fence_fd);
+  current_image_bound_ = false;
+
+  // TODO(khushalsagar): This should be on the public API so that we only bind
+  // the texture if we were going to render it without an overlay.
+  EnsureTexImageBound();
+}
+
+void ImageReaderGLOwner::EnsureTexImageBound() {
+  if (current_image_bound_)
+    return;
+
+  base::ScopedFD acquire_fence =
+      base::ScopedFD(HANDLE_EINTR(dup(current_image_fence_.get())));
 
   // Insert an EGL fence and make server wait for image to be available.
-  if (!gpu::InsertEglFenceAndWait(std::move(scoped_acquire_fence_fd)))
+  if (!gpu::InsertEglFenceAndWait(std::move(acquire_fence)))
     return;
 
   // Create EGL image from the AImage and bind it to the texture.
   if (!gpu::CreateAndBindEglImage(current_image_, texture_id_, &loader_))
     return;
+
+  current_image_bound_ = true;
+}
+
+bool ImageReaderGLOwner::MaybeDeleteCurrentImage() {
+  if (!current_image_)
+    return true;
+
+  if (external_image_refs_.count(current_image_) != 0)
+    return true;
+
+  // We should not need a fence if this image was never bound.
+  return gpu::DeleteAImageAsync(current_image_, &loader_);
+}
+
+std::unique_ptr<gl::GLImage::ScopedHardwareBuffer>
+ImageReaderGLOwner::GetAHardwareBuffer() {
+  if (!current_image_)
+    return nullptr;
+
+  AHardwareBuffer* buffer = nullptr;
+  loader_.AImage_getHardwareBuffer(current_image_, &buffer);
+  if (!buffer)
+    return nullptr;
+
+  auto fence_fd = base::ScopedFD(HANDLE_EINTR(dup(current_image_fence_.get())));
+
+  // Add a ref that the caller will release.
+  auto it = external_image_refs_.find(current_image_);
+  if (it == external_image_refs_.end())
+    external_image_refs_[current_image_] = 1;
+  else
+    it->second++;
+
+  return std::make_unique<ScopedHardwareBufferImpl>(
+      this, current_image_,
+      base::android::ScopedHardwareBufferHandle::Create(buffer),
+      std::move(fence_fd));
+}
+
+void ImageReaderGLOwner::ReleaseRefOnImage(AImage* image) {
+  auto it = external_image_refs_.find(image);
+  DCHECK(it != external_image_refs_.end());
+  DCHECK_GT(it->second, 0u);
+  it->second--;
+
+  if (it->second > 0)
+    return;
+  external_image_refs_.erase(it);
+
+  if (image == current_image_)
+    return;
+
+  // No refs on the image. If it is no longer current, delete it. Note that this
+  // can be deleted synchronously here since the caller ensures that any pending
+  // GPU work for the image is finished before marking it for release.
+  loader_.AImage_delete(image);
 }
 
 void ImageReaderGLOwner::GetTransformMatrix(float mtx[]) {
diff --git a/media/gpu/android/image_reader_gl_owner.h b/media/gpu/android/image_reader_gl_owner.h
index a359ad3..7fc0ad6 100644
--- a/media/gpu/android/image_reader_gl_owner.h
+++ b/media/gpu/android/image_reader_gl_owner.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/android/android_image_reader_compat.h"
+#include "base/containers/flat_map.h"
 #include "media/gpu/android/texture_owner.h"
 #include "ui/gl/gl_fence_egl.h"
 #include "ui/gl/gl_image_ahardwarebuffer.h"
@@ -35,22 +36,43 @@
   void IgnorePendingRelease() override;
   bool IsExpectingFrameAvailable() override;
   void WaitForFrameAvailable() override;
+  std::unique_ptr<gl::GLImage::ScopedHardwareBuffer> GetAHardwareBuffer()
+      override;
 
  private:
   friend class TextureOwner;
 
+  class ScopedHardwareBufferImpl;
+
   ImageReaderGLOwner(GLuint texture_id);
   ~ImageReaderGLOwner() override;
 
+  // Deletes the current image if it has no pending refs. Returns false on
+  // error.
+  bool MaybeDeleteCurrentImage();
+
+  void EnsureTexImageBound();
+  void ReleaseRefOnImage(AImage* image);
+
   // AImageReader instance
   AImageReader* image_reader_;
 
   // Most recently acquired image using image reader. This works like a cached
   // image until next new image is acquired which overwrites this.
   AImage* current_image_;
+  base::ScopedFD current_image_fence_;
   GLuint texture_id_;
   std::unique_ptr<AImageReader_ImageListener> listener_;
 
+  // Set to true if the current image is bound to |texture_id_|.
+  bool current_image_bound_ = false;
+
+  // A map consisting of pending external refs on an AImage. If an image has any
+  // external refs, it is automatically released once the ref-count is 0 and the
+  // image is no longer current.
+  using AImageRefMap = base::flat_map<AImage*, size_t>;
+  AImageRefMap external_image_refs_;
+
   // reference to the class instance which is used to dynamically
   // load the functions in android libraries at runtime.
   base::android::AndroidImageReader& loader_;
diff --git a/media/gpu/android/media_codec_video_decoder.cc b/media/gpu/android/media_codec_video_decoder.cc
index 45054c88..36dac20 100644
--- a/media/gpu/android/media_codec_video_decoder.cc
+++ b/media/gpu/android/media_codec_video_decoder.cc
@@ -100,6 +100,11 @@
   pump_cb.Run();
 }
 
+bool IsSurfaceControlEnabled(const gpu::GpuFeatureInfo& info) {
+  return info.status_values[gpu::GPU_FEATURE_TYPE_ANDROID_SURFACE_CONTROL] ==
+         gpu::kGpuFeatureStatusEnabled;
+}
+
 }  // namespace
 
 // static
@@ -115,6 +120,7 @@
 
 MediaCodecVideoDecoder::MediaCodecVideoDecoder(
     const gpu::GpuPreferences& gpu_preferences,
+    const gpu::GpuFeatureInfo& gpu_feature_info,
     DeviceInfo* device_info,
     CodecAllocator* codec_allocator,
     std::unique_ptr<AndroidVideoSurfaceChooser> surface_chooser,
@@ -123,11 +129,13 @@
     std::unique_ptr<VideoFrameFactory> video_frame_factory)
     : codec_allocator_(codec_allocator),
       request_overlay_info_cb_(std::move(request_overlay_info_cb)),
+      is_surface_control_enabled_(IsSurfaceControlEnabled(gpu_feature_info)),
       surface_chooser_helper_(
           std::move(surface_chooser),
           base::CommandLine::ForCurrentProcess()->HasSwitch(
               switches::kForceVideoOverlays),
-          base::FeatureList::IsEnabled(media::kUseAndroidOverlayAggressively)),
+          base::FeatureList::IsEnabled(media::kUseAndroidOverlayAggressively),
+          is_surface_control_enabled_),
       video_frame_factory_(std::move(video_frame_factory)),
       overlay_factory_cb_(std::move(overlay_factory_cb)),
       device_info_(device_info),
@@ -302,14 +310,20 @@
   DVLOG(2) << __func__;
   lazy_init_pending_ = false;
   codec_allocator_->StartThread(this);
+
+  // SurfaceControl allows TextureOwner to be promoted to an overlay in the
+  // compositing pipeline itself.
+  const bool use_texture_owner_as_overlays = is_surface_control_enabled_;
+
   // Only ask for promotion hints if we can actually switch surfaces, since we
-  // wouldn't be able to do anything with them.  Also, if threaded texture
-  // mailboxes are enabled, then we turn off overlays anyway.
+  // wouldn't be able to do anything with them. Also, if threaded texture
+  // mailboxes are enabled, then we turn off overlays anyway. And if texture
+  // owner can be used as an overlay, no promotion hints are necessary.
   const bool want_promotion_hints =
       device_info_->IsSetOutputSurfaceSupported() &&
-      !enable_threaded_texture_mailboxes_;
+      !enable_threaded_texture_mailboxes_ && !use_texture_owner_as_overlays;
   video_frame_factory_->Initialize(
-      want_promotion_hints,
+      want_promotion_hints, use_texture_owner_as_overlays,
       base::Bind(&MediaCodecVideoDecoder::OnVideoFrameFactoryInitialized,
                  weak_factory_.GetWeakPtr()));
 }
diff --git a/media/gpu/android/media_codec_video_decoder.h b/media/gpu/android/media_codec_video_decoder.h
index cd13054..f113d77 100644
--- a/media/gpu/android/media_codec_video_decoder.h
+++ b/media/gpu/android/media_codec_video_decoder.h
@@ -9,6 +9,7 @@
 #include "base/optional.h"
 #include "base/threading/thread_checker.h"
 #include "base/timer/elapsed_timer.h"
+#include "gpu/config/gpu_feature_info.h"
 #include "gpu/config/gpu_preferences.h"
 #include "media/base/android_overlay_mojo_factory.h"
 #include "media/base/overlay_info.h"
@@ -53,6 +54,7 @@
  public:
   MediaCodecVideoDecoder(
       const gpu::GpuPreferences& gpu_preferences,
+      const gpu::GpuFeatureInfo& gpu_feature_info,
       DeviceInfo* device_info,
       CodecAllocator* codec_allocator,
       std::unique_ptr<AndroidVideoSurfaceChooser> surface_chooser,
@@ -251,6 +253,9 @@
   // The current overlay info, which possibly specifies an overlay to render to.
   OverlayInfo overlay_info_;
 
+  // Set to true if the display compositor swap is done using SurfaceControl.
+  const bool is_surface_control_enabled_;
+
   // The helper which manages our surface chooser for us.
   SurfaceChooserHelper surface_chooser_helper_;
 
diff --git a/media/gpu/android/media_codec_video_decoder_unittest.cc b/media/gpu/android/media_codec_video_decoder_unittest.cc
index ceb6094..028a6cf 100644
--- a/media/gpu/android/media_codec_video_decoder_unittest.cc
+++ b/media/gpu/android/media_codec_video_decoder_unittest.cc
@@ -58,7 +58,10 @@
 
 class MockVideoFrameFactory : public VideoFrameFactory {
  public:
-  MOCK_METHOD2(Initialize, void(bool wants_promotion_hint, InitCb init_cb));
+  MOCK_METHOD3(Initialize,
+               void(bool wants_promotion_hint,
+                    bool use_texture_owner_as_overlay,
+                    InitCb init_cb));
   MOCK_METHOD1(MockSetSurfaceBundle, void(scoped_refptr<AVDASurfaceBundle>));
   MOCK_METHOD6(
       MockCreateVideoFrame,
@@ -143,12 +146,12 @@
     // Set up VFF to pass |texture_owner_| via its InitCb.
     const bool want_promotion_hint =
         device_info_->IsSetOutputSurfaceSupported();
-    ON_CALL(*video_frame_factory_, Initialize(want_promotion_hint, _))
-        .WillByDefault(RunCallback<1>(texture_owner));
+    ON_CALL(*video_frame_factory_, Initialize(want_promotion_hint, _, _))
+        .WillByDefault(RunCallback<2>(texture_owner));
 
     auto* observable_mcvd = new DestructionObservableMCVD(
-        gpu_preferences_, device_info_.get(), codec_allocator_.get(),
-        std::move(surface_chooser),
+        gpu_preferences_, gpu_feature_info_, device_info_.get(),
+        codec_allocator_.get(), std::move(surface_chooser),
         base::BindRepeating(&CreateAndroidOverlayCb),
         base::Bind(&MediaCodecVideoDecoderTest::RequestOverlayInfoCb,
                    base::Unretained(this)),
@@ -272,6 +275,7 @@
   ProvideOverlayInfoCB provide_overlay_info_cb_;
   bool restart_for_transitions_;
   gpu::GpuPreferences gpu_preferences_;
+  gpu::GpuFeatureInfo gpu_feature_info_;
   scoped_refptr<VideoFrame> most_recent_frame_;
 
   // This is not an actual media crypto object.
@@ -305,7 +309,7 @@
 
 TEST_P(MediaCodecVideoDecoderTest, InitializeDoesntInitSurfaceOrCodec) {
   CreateMcvd();
-  EXPECT_CALL(*video_frame_factory_, Initialize(_, _)).Times(0);
+  EXPECT_CALL(*video_frame_factory_, Initialize(_, _, _)).Times(0);
   EXPECT_CALL(*surface_chooser_, MockUpdateState()).Times(0);
   EXPECT_CALL(*codec_allocator_, MockCreateMediaCodecAsync(_, _)).Times(0);
   Initialize(TestVideoConfig::Large(codec_));
@@ -313,7 +317,7 @@
 
 TEST_P(MediaCodecVideoDecoderTest, FirstDecodeTriggersFrameFactoryInit) {
   Initialize(TestVideoConfig::Large(codec_));
-  EXPECT_CALL(*video_frame_factory_, Initialize(_, _));
+  EXPECT_CALL(*video_frame_factory_, Initialize(_, _, _));
   mcvd_->Decode(fake_decoder_buffer_, decode_cb_.Get());
 }
 
@@ -367,8 +371,8 @@
 
 TEST_P(MediaCodecVideoDecoderTest, FrameFactoryInitFailureIsAnError) {
   Initialize(TestVideoConfig::Large(codec_));
-  ON_CALL(*video_frame_factory_, Initialize(_, _))
-      .WillByDefault(RunCallback<1>(nullptr));
+  ON_CALL(*video_frame_factory_, Initialize(_, _, _))
+      .WillByDefault(RunCallback<2>(nullptr));
   EXPECT_CALL(decode_cb_, Run(DecodeStatus::DECODE_ERROR)).Times(1);
   EXPECT_CALL(*surface_chooser_, MockUpdateState()).Times(0);
   mcvd_->Decode(fake_decoder_buffer_, decode_cb_.Get());
diff --git a/media/gpu/android/mock_texture_owner.h b/media/gpu/android/mock_texture_owner.h
index 8f3d5e0..04756f6 100644
--- a/media/gpu/android/mock_texture_owner.h
+++ b/media/gpu/android/mock_texture_owner.h
@@ -33,6 +33,12 @@
   MOCK_METHOD0(IsExpectingFrameAvailable, bool());
   MOCK_METHOD0(WaitForFrameAvailable, void());
 
+  std::unique_ptr<gl::GLImage::ScopedHardwareBuffer> GetAHardwareBuffer()
+      override {
+    get_a_hardware_buffer_count++;
+    return nullptr;
+  }
+
   // Fake implementations that the mocks will call by default.
   void FakeSetReleaseTimeToNow() { expecting_frame_available = true; }
   void FakeIgnorePendingRelease() { expecting_frame_available = false; }
@@ -43,6 +49,7 @@
   gl::GLContext* fake_context;
   gl::GLSurface* fake_surface;
   bool expecting_frame_available;
+  int get_a_hardware_buffer_count = 0;
 
  protected:
   ~MockTextureOwner();
diff --git a/media/gpu/android/surface_chooser_helper.cc b/media/gpu/android/surface_chooser_helper.cc
index 504c64d..9093491a 100644
--- a/media/gpu/android/surface_chooser_helper.cc
+++ b/media/gpu/android/surface_chooser_helper.cc
@@ -33,6 +33,7 @@
     std::unique_ptr<AndroidVideoSurfaceChooser> surface_chooser,
     bool is_overlay_required,
     bool promote_aggressively,
+    bool always_use_texture_owner,
     std::unique_ptr<PromotionHintAggregator> promotion_hint_aggregator,
     const base::TickClock* tick_clock)
     : surface_chooser_(std::move(surface_chooser)),
@@ -45,6 +46,7 @@
                              : base::DefaultTickClock::GetInstance()) {
   surface_chooser_state_.is_required = is_overlay_required_;
   surface_chooser_state_.promote_aggressively = promote_aggressively;
+  surface_chooser_state_.always_use_texture_owner = always_use_texture_owner;
 }
 
 SurfaceChooserHelper::~SurfaceChooserHelper() {}
diff --git a/media/gpu/android/surface_chooser_helper.h b/media/gpu/android/surface_chooser_helper.h
index b696a46..33423de 100644
--- a/media/gpu/android/surface_chooser_helper.h
+++ b/media/gpu/android/surface_chooser_helper.h
@@ -29,10 +29,13 @@
   // |is_overlay_required| tells us to require overlays(!).
   // |promote_aggressively| causes us to use overlays whenever they're power-
   // efficient, which lets us catch fullscreen-div cases.
+  // |always_use_texture_owner| forces us to always use a texture owner,
+  // completely ignoring all other conditions.
   SurfaceChooserHelper(
       std::unique_ptr<AndroidVideoSurfaceChooser> surface_chooser,
       bool is_overlay_required,
       bool promote_aggressively,
+      bool always_use_texture_owner,
       std::unique_ptr<PromotionHintAggregator> promotion_hint_aggregator =
           nullptr,
       const base::TickClock* tick_clock = nullptr);
diff --git a/media/gpu/android/surface_chooser_helper_unittest.cc b/media/gpu/android/surface_chooser_helper_unittest.cc
index b07ec1a..de6790b 100644
--- a/media/gpu/android/surface_chooser_helper_unittest.cc
+++ b/media/gpu/android/surface_chooser_helper_unittest.cc
@@ -33,7 +33,9 @@
 
   void TearDown() override {}
 
-  void ReplaceHelper(bool is_overlay_required, bool promote_aggressively) {
+  void ReplaceHelper(bool is_overlay_required,
+                     bool promote_aggressively,
+                     bool always_use_texture_owner = false) {
     // Advance the clock so that time 0 isn't recent.
     tick_clock_.Advance(TimeDelta::FromSeconds(10000));
 
@@ -45,7 +47,7 @@
     aggregator_ = aggregator.get();
     helper_ = std::make_unique<SurfaceChooserHelper>(
         std::move(chooser), is_overlay_required, promote_aggressively,
-        std::move(aggregator), &tick_clock_);
+        always_use_texture_owner, std::move(aggregator), &tick_clock_);
   }
 
   // Convenience function.
@@ -150,6 +152,15 @@
   ASSERT_TRUE(chooser_->current_state_.promote_aggressively);
 }
 
+TEST_F(SurfaceChooserHelperTest, SetAlwaysUseTextureOwner) {
+  UpdateChooserState();
+  ASSERT_FALSE(chooser_->current_state_.always_use_texture_owner);
+
+  ReplaceHelper(false, true, true);
+  UpdateChooserState();
+  ASSERT_TRUE(chooser_->current_state_.always_use_texture_owner);
+}
+
 TEST_F(SurfaceChooserHelperTest, PromotionHintsForwardsHint) {
   // Make sure that NotifyPromotionHint relays the hint to the aggregator.
   PromotionHintAggregator::Hint hint(gfx::Rect(1, 2, 3, 4), false);
diff --git a/media/gpu/android/surface_texture_gl_owner.cc b/media/gpu/android/surface_texture_gl_owner.cc
index 483934c..9590589 100644
--- a/media/gpu/android/surface_texture_gl_owner.cc
+++ b/media/gpu/android/surface_texture_gl_owner.cc
@@ -145,4 +145,10 @@
   }
 }
 
+std::unique_ptr<gl::GLImage::ScopedHardwareBuffer>
+SurfaceTextureGLOwner::GetAHardwareBuffer() {
+  NOTREACHED() << "Don't use AHardwareBuffers with SurfaceTextureGLOwner";
+  return nullptr;
+}
+
 }  // namespace media
diff --git a/media/gpu/android/surface_texture_gl_owner.h b/media/gpu/android/surface_texture_gl_owner.h
index 1cc7d2c..d01b49f 100644
--- a/media/gpu/android/surface_texture_gl_owner.h
+++ b/media/gpu/android/surface_texture_gl_owner.h
@@ -35,6 +35,8 @@
   void IgnorePendingRelease() override;
   bool IsExpectingFrameAvailable() override;
   void WaitForFrameAvailable() override;
+  std::unique_ptr<gl::GLImage::ScopedHardwareBuffer> GetAHardwareBuffer()
+      override;
 
  private:
   friend class TextureOwner;
diff --git a/media/gpu/android/texture_owner.h b/media/gpu/android/texture_owner.h
index fe1584c..5bbf383 100644
--- a/media/gpu/android/texture_owner.h
+++ b/media/gpu/android/texture_owner.h
@@ -5,6 +5,8 @@
 #ifndef MEDIA_GPU_ANDROID_TEXTURE_OWNER_H_
 #define MEDIA_GPU_ANDROID_TEXTURE_OWNER_H_
 
+#include <android/hardware_buffer.h>
+
 #include "base/memory/ref_counted.h"
 #include "base/memory/ref_counted_delete_on_sequence.h"
 #include "base/single_thread_task_runner.h"
@@ -12,6 +14,7 @@
 #include "ui/gl/android/scoped_java_surface.h"
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_context.h"
+#include "ui/gl/gl_image.h"
 #include "ui/gl/gl_surface.h"
 
 namespace media {
@@ -69,6 +72,12 @@
   // released. This must only be called if IsExpectingFrameAvailable().
   virtual void WaitForFrameAvailable() = 0;
 
+  // Retrieves the AHardwareBuffer from the latest available image data.
+  // Note that the object must be used and destroyed on the same thread the
+  // TextureOwner is bound to.
+  virtual std::unique_ptr<gl::GLImage::ScopedHardwareBuffer>
+  GetAHardwareBuffer() = 0;
+
  protected:
   friend class base::RefCountedDeleteOnSequence<TextureOwner>;
   friend class base::DeleteHelper<TextureOwner>;
diff --git a/media/gpu/android/video_frame_factory.h b/media/gpu/android/video_frame_factory.h
index f4507e8d..c5120fd 100644
--- a/media/gpu/android/video_frame_factory.h
+++ b/media/gpu/android/video_frame_factory.h
@@ -38,9 +38,14 @@
 
   // Initializes the factory and runs |init_cb| on the current thread when it's
   // complete. If initialization fails, the returned texture owner will be
-  // null.  |wants_promotion_hint| tells us whether to mark VideoFrames for
-  // compositor overlay promotion hints or not.
-  virtual void Initialize(bool wants_promotion_hint, InitCb init_cb) = 0;
+  // null.
+  // |wants_promotion_hint| tells us whether to mark VideoFrames for compositor
+  // overlay promotion hints or not.
+  // |use_texture_owner_as_overlays| tells us whether TextureOwner can be used
+  // as an overlay, in which case java overlays will never be used.
+  virtual void Initialize(bool wants_promotion_hint,
+                          bool use_texture_owner_as_overlays,
+                          InitCb init_cb) = 0;
 
   // Notify us about the current surface bundle that subsequent video frames
   // should use.
diff --git a/media/gpu/android/video_frame_factory_impl.cc b/media/gpu/android/video_frame_factory_impl.cc
index 698d743..b9639db 100644
--- a/media/gpu/android/video_frame_factory_impl.cc
+++ b/media/gpu/android/video_frame_factory_impl.cc
@@ -51,6 +51,7 @@
 }
 
 void VideoFrameFactoryImpl::Initialize(bool wants_promotion_hint,
+                                       bool use_texture_owner_as_overlays,
                                        InitCb init_cb) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!gpu_video_frame_factory_);
@@ -59,7 +60,8 @@
       gpu_task_runner_.get(), FROM_HERE,
       base::Bind(&GpuVideoFrameFactory::Initialize,
                  base::Unretained(gpu_video_frame_factory_.get()),
-                 wants_promotion_hint, get_stub_cb_),
+                 wants_promotion_hint, use_texture_owner_as_overlays,
+                 get_stub_cb_),
       std::move(init_cb));
 }
 
@@ -129,9 +131,11 @@
 
 scoped_refptr<TextureOwner> GpuVideoFrameFactory::Initialize(
     bool wants_promotion_hint,
+    bool use_texture_owner_as_overlays,
     VideoFrameFactoryImpl::GetStubCb get_stub_cb) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   wants_promotion_hint_ = wants_promotion_hint;
+  use_texture_owner_as_overlays_ = use_texture_owner_as_overlays;
   stub_ = get_stub_cb.Run();
   if (!MakeContextCurrent(stub_))
     return nullptr;
@@ -273,10 +277,16 @@
   if (group->gpu_preferences().enable_threaded_texture_mailboxes)
     frame->metadata()->SetBoolean(VideoFrameMetadata::COPY_REQUIRED, true);
 
-  // We unconditionally mark the picture as overlayable, even if
-  // |!texture_owner_|, if we want to get hints.  It's required, else we won't
-  // get hints.
-  const bool allow_overlay = !texture_owner_ || wants_promotion_hint_;
+  bool allow_overlay = false;
+  if (use_texture_owner_as_overlays_) {
+    DCHECK(texture_owner_);
+    allow_overlay = true;
+  } else {
+    // We unconditionally mark the picture as overlayable, even if
+    // |!texture_owner_|, if we want to get hints.  It's required, else we won't
+    // get hints.
+    allow_overlay = !texture_owner_ || wants_promotion_hint_;
+  }
 
   frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY,
                                 allow_overlay);
diff --git a/media/gpu/android/video_frame_factory_impl.h b/media/gpu/android/video_frame_factory_impl.h
index b1ba011d..db02d0e 100644
--- a/media/gpu/android/video_frame_factory_impl.h
+++ b/media/gpu/android/video_frame_factory_impl.h
@@ -38,7 +38,9 @@
       GetStubCb get_stub_cb);
   ~VideoFrameFactoryImpl() override;
 
-  void Initialize(bool wants_promotion_hint, InitCb init_cb) override;
+  void Initialize(bool wants_promotion_hint,
+                  bool use_texture_owner_as_overlays,
+                  InitCb init_cb) override;
   void SetSurfaceBundle(
       scoped_refptr<AVDASurfaceBundle> surface_bundle) override;
   void CreateVideoFrame(
@@ -72,6 +74,7 @@
 
   scoped_refptr<TextureOwner> Initialize(
       bool wants_promotion_hint,
+      bool use_texture_owner_as_overlays,
       VideoFrameFactory::GetStubCb get_stub_cb);
 
   // Creates and returns a VideoFrame with its ReleaseMailboxCB.
@@ -116,6 +119,9 @@
   // Do we want promotion hints from the compositor?
   bool wants_promotion_hint_ = false;
 
+  // Indicates whether texture owner can be promoted to an overlay.
+  bool use_texture_owner_as_overlays_ = false;
+
   // A helper for creating textures. Only valid while |stub_| is valid.
   std::unique_ptr<GLES2DecoderHelper> decoder_helper_;
 
diff --git a/media/mojo/services/gpu_mojo_media_client.cc b/media/mojo/services/gpu_mojo_media_client.cc
index 3092875..43c3873 100644
--- a/media/mojo/services/gpu_mojo_media_client.cc
+++ b/media/mojo/services/gpu_mojo_media_client.cc
@@ -74,12 +74,14 @@
 GpuMojoMediaClient::GpuMojoMediaClient(
     const gpu::GpuPreferences& gpu_preferences,
     const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
+    const gpu::GpuFeatureInfo& gpu_feature_info,
     scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
     base::WeakPtr<MediaGpuChannelManager> media_gpu_channel_manager,
     AndroidOverlayMojoFactoryCB android_overlay_factory_cb,
     CdmProxyFactoryCB cdm_proxy_factory_cb)
     : gpu_preferences_(gpu_preferences),
       gpu_workarounds_(gpu_workarounds),
+      gpu_feature_info_(gpu_feature_info),
       gpu_task_runner_(std::move(gpu_task_runner)),
       media_gpu_channel_manager_(std::move(media_gpu_channel_manager)),
       android_overlay_factory_cb_(std::move(android_overlay_factory_cb)),
@@ -137,7 +139,7 @@
       base::Bind(&GetCommandBufferStub, media_gpu_channel_manager_,
                  command_buffer_id->channel_token, command_buffer_id->route_id);
   return std::make_unique<MediaCodecVideoDecoder>(
-      gpu_preferences_, DeviceInfo::GetInstance(),
+      gpu_preferences_, gpu_feature_info_, DeviceInfo::GetInstance(),
       CodecAllocator::GetInstance(gpu_task_runner_),
       std::make_unique<AndroidVideoSurfaceChooserImpl>(
           DeviceInfo::GetInstance()->IsSetOutputSurfaceSupported()),
diff --git a/media/mojo/services/gpu_mojo_media_client.h b/media/mojo/services/gpu_mojo_media_client.h
index 7ee963e..2860db3 100644
--- a/media/mojo/services/gpu_mojo_media_client.h
+++ b/media/mojo/services/gpu_mojo_media_client.h
@@ -12,6 +12,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/single_thread_task_runner.h"
 #include "gpu/config/gpu_driver_bug_workarounds.h"
+#include "gpu/config/gpu_feature_info.h"
 #include "gpu/config/gpu_preferences.h"
 #include "media/base/android_overlay_mojo_factory.h"
 #include "media/cdm/cdm_proxy.h"
@@ -30,6 +31,7 @@
   GpuMojoMediaClient(
       const gpu::GpuPreferences& gpu_preferences,
       const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
+      const gpu::GpuFeatureInfo& gpu_feature_info,
       scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
       base::WeakPtr<MediaGpuChannelManager> media_gpu_channel_manager,
       AndroidOverlayMojoFactoryCB android_overlay_factory_cb,
@@ -57,6 +59,7 @@
  private:
   gpu::GpuPreferences gpu_preferences_;
   gpu::GpuDriverBugWorkarounds gpu_workarounds_;
+  gpu::GpuFeatureInfo gpu_feature_info_;
   scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner_;
   base::WeakPtr<MediaGpuChannelManager> media_gpu_channel_manager_;
   AndroidOverlayMojoFactoryCB android_overlay_factory_cb_;
diff --git a/media/mojo/services/media_service_factory.cc b/media/mojo/services/media_service_factory.cc
index b789dfd..15063f7 100644
--- a/media/mojo/services/media_service_factory.cc
+++ b/media/mojo/services/media_service_factory.cc
@@ -32,13 +32,14 @@
 std::unique_ptr<service_manager::Service> CreateGpuMediaService(
     const gpu::GpuPreferences& gpu_preferences,
     const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
+    const gpu::GpuFeatureInfo& gpu_feature_info,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
     base::WeakPtr<MediaGpuChannelManager> media_gpu_channel_manager,
     AndroidOverlayMojoFactoryCB android_overlay_factory_cb,
     CdmProxyFactoryCB cdm_proxy_factory_cb) {
   return std::unique_ptr<service_manager::Service>(
       new MediaService(std::make_unique<GpuMojoMediaClient>(
-          gpu_preferences, gpu_workarounds, task_runner,
+          gpu_preferences, gpu_workarounds, gpu_feature_info, task_runner,
           media_gpu_channel_manager, std::move(android_overlay_factory_cb),
           std::move(cdm_proxy_factory_cb))));
 }
diff --git a/media/mojo/services/media_service_factory.h b/media/mojo/services/media_service_factory.h
index 3a35524..d1bca61 100644
--- a/media/mojo/services/media_service_factory.h
+++ b/media/mojo/services/media_service_factory.h
@@ -11,6 +11,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/single_thread_task_runner.h"
 #include "gpu/config/gpu_driver_bug_workarounds.h"
+#include "gpu/config/gpu_feature_info.h"
 #include "gpu/config/gpu_preferences.h"
 #include "media/base/android_overlay_mojo_factory.h"
 #include "media/cdm/cdm_proxy.h"
@@ -36,6 +37,7 @@
 CreateGpuMediaService(
     const gpu::GpuPreferences& gpu_preferences,
     const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
+    const gpu::GpuFeatureInfo& gpu_feature_info,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
     base::WeakPtr<MediaGpuChannelManager> media_gpu_channel_manager,
     AndroidOverlayMojoFactoryCB android_overlay_factory_cb,
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 9a2efd0..33d4e82 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -2681,6 +2681,10 @@
     "data/",
   ]
 
+  if (is_mac) {
+    libs = [ "Security.framework" ]
+  }
+
   if (is_ios) {
     deps += [ ":test_support_bundle_data" ]
   } else {
diff --git a/net/base/registry_controlled_domains/effective_tld_names.dat b/net/base/registry_controlled_domains/effective_tld_names.dat
index a210b9d6..49df459 100644
--- a/net/base/registry_controlled_domains/effective_tld_names.dat
+++ b/net/base/registry_controlled_domains/effective_tld_names.dat
@@ -385,8 +385,13 @@
 net.bm
 org.bm
 
-// bn : https://en.wikipedia.org/wiki/.bn
-*.bn
+// bn : http://www.bnnic.bn/faqs
+bn
+com.bn
+edu.bn
+gov.bn
+net.bn
+org.bn
 
 // bo : https://nic.bo/delegacion2015.php#h-1.10
 bo
@@ -550,6 +555,7 @@
 not.br
 ntr.br
 odo.br
+ong.br
 org.br
 osasco.br
 palmas.br
@@ -1118,8 +1124,18 @@
 net.gt
 org.gt
 
-// gu : http://gadao.gov.gu/registration.txt
-*.gu
+// gu : http://gadao.gov.gu/register.html
+// University of Guam : https://www.uog.edu
+// Submitted by uognoc@triton.uog.edu
+gu
+com.gu
+edu.gu
+gov.gu
+guam.gu
+info.gu
+net.gu
+org.gu
+web.gu
 
 // gw : https://en.wikipedia.org/wiki/.gw
 gw
@@ -1233,7 +1249,7 @@
 utazas.hu
 video.hu
 
-// id : https://register.pandi.or.id/
+// id : https://pandi.id/en/domain/registration-requirements/
 id
 ac.id
 biz.id
@@ -1244,6 +1260,7 @@
 my.id
 net.id
 or.id
+ponpes.id
 sch.id
 web.id
 
@@ -3686,8 +3703,16 @@
 seoul.kr
 ulsan.kr
 
-// kw : https://en.wikipedia.org/wiki/.kw
-*.kw
+// kw : https://www.nic.kw/policies/
+// Confirmed by registry <nic.tech@citra.gov.kw>
+kw
+com.kw
+edu.kw
+emb.kw
+gov.kw
+ind.kw
+net.kw
+org.kw
 
 // ky : http://www.icta.ky/da_ky_reg_dom.php
 // Confirmed by registry <kysupport@perimeterusa.com> 2008-06-17
@@ -8323,9 +8348,6 @@
 // goo : 2014-12-18 NTT Resonant Inc.
 goo
 
-// goodhands : 2015-07-31 Allstate Fire and Casualty Insurance Company
-goodhands
-
 // goodyear : 2015-07-02 The Goodyear Tire & Rubber Company
 goodyear
 
@@ -8602,9 +8624,6 @@
 // iveco : 2015-09-03 CNH Industrial N.V.
 iveco
 
-// iwc : 2014-06-23 Richemont DNS Inc.
-iwc
-
 // jaguar : 2014-11-13 Jaguar Land Rover Ltd
 jaguar
 
@@ -8629,9 +8648,6 @@
 // jio : 2015-04-02 Reliance Industries Limited
 jio
 
-// jlc : 2014-12-04 Richemont DNS Inc.
-jlc
-
 // jll : 2015-04-02 Jones Lang LaSalle Incorporated
 jll
 
@@ -8983,9 +8999,6 @@
 // menu : 2013-09-11 Wedding TLD2, LLC
 menu
 
-// meo : 2014-11-07 MEO Servicos de Comunicacoes e Multimedia, S.A.
-meo
-
 // merckmsd : 2016-07-14 MSD Registry Holdings, Inc.
 merckmsd
 
@@ -9277,9 +9290,6 @@
 // panasonic : 2015-07-30 Panasonic Corporation
 panasonic
 
-// panerai : 2014-11-07 Richemont DNS Inc.
-panerai
-
 // paris : 2014-01-30 City of Paris
 paris
 
@@ -9628,9 +9638,6 @@
 // sap : 2014-03-27 SAP AG
 sap
 
-// sapo : 2014-11-07 MEO Servicos de Comunicacoes e Multimedia, S.A.
-sapo
-
 // sarl : 2014-07-03 Binky Moon, LLC
 sarl
 
@@ -9985,9 +9992,6 @@
 // technology : 2013-09-13 Binky Moon, LLC
 technology
 
-// telecity : 2015-02-19 TelecityGroup International Limited
-telecity
-
 // telefonica : 2014-10-16 Telefónica S.A.
 telefonica
 
@@ -10195,9 +10199,6 @@
 // vision : 2013-12-05 Binky Moon, LLC
 vision
 
-// vista : 2014-09-18 Vistaprint Limited
-vista
-
 // vistaprint : 2014-09-18 Vistaprint Limited
 vistaprint
 
@@ -10636,9 +10637,6 @@
 // xn--zfr164b : 2013-11-08 China Organizational Name Administration Center
 政务
 
-// xperia : 2015-05-14 Sony Mobile Communications AB
-xperia
-
 // xyz : 2013-12-05 XYZ.COM LLC
 xyz
 
@@ -10731,6 +10729,7 @@
 // Amazon Elastic Beanstalk : https://aws.amazon.com/elasticbeanstalk/
 // Submitted by Luke Wells <psl-maintainers@amazon.com>
 cn-north-1.eb.amazonaws.com.cn
+cn-northwest-1.eb.amazonaws.com.cn
 elasticbeanstalk.com
 ap-northeast-1.elasticbeanstalk.com
 ap-northeast-2.elasticbeanstalk.com
@@ -10817,6 +10816,10 @@
 t3l3p0rt.net
 tele.amune.org
 
+// Apigee : https://apigee.com/
+// Submitted by Apigee Security Team <security@apigee.com>
+apigee.io
+
 // Aptible : https://www.aptible.com/
 // Submitted by Thomas Orozco <thomas@aptible.com>
 on-aptible.com
@@ -11010,6 +11013,10 @@
 // Submitted by Stefan Dimitrov <contact@cloudeity.com>
 cloudeity.net
 
+// CNPY : https://cnpy.gdn
+// Submitted by Angelo Gladding <angelo@lahacker.net>
+cnpy.gdn
+
 // CoDNS B.V.
 co.nl
 co.no
@@ -11660,6 +11667,10 @@
 freebox-os.fr
 freeboxos.fr
 
+// freedesktop.org : https://www.freedesktop.org
+// Submitted by Daniel Stone <daniel@fooishbar.org>
+freedesktop.org
+
 // Futureweb OG : http://www.futureweb.at
 // Submitted by Andreas Schnederle-Wagner <schnederle@futureweb.at>
 *.futurecms.at
@@ -11790,6 +11801,7 @@
 
 // Hasura : https://hasura.io
 // Submitted by Shahidh K Muhammed <shahidh@hasura.io>
+hasura.app
 hasura-app.io
 
 // Hepforge : https://www.hepforge.org
@@ -12223,6 +12235,10 @@
 // Submitted by Andrew Sampson <andrew@ulterius.io>
 cya.gg
 
+// Omnibond Systems, LLC. : https://www.omnibond.com
+// Submitted by Cole Estep <cole@omnibond.com>
+cloudycluster.net
+
 // One Fold Media : http://www.onefoldmedia.com/
 // Submitted by Eddie Jones <eddie@onefoldmedia.com>
 nid.io
@@ -12300,7 +12316,7 @@
 protonet.io
 
 // Publication Presse Communication SARL : https://ppcom.fr
-// Submitted by Yaacov Akiba Slama <admin@chirurfgiens-dentistes-en-france.fr>
+// Submitted by Yaacov Akiba Slama <admin@chirurgiens-dentistes-en-france.fr>
 chirurgiens-dentistes-en-france.fr
 byen.site
 
@@ -12433,10 +12449,6 @@
 // Submitted by Stefan Neufeind <info@speedpartner.de>
 customer.speedpartner.de
 
-// Stackspace : https://www.stackspace.io/
-// Submitted by Lina He <info@stackspace.io>
-stackspace.space
-
 // Storj Labs Inc. : https://storj.io/
 // Submitted by Philip Hutchins <hostmaster@storj.io>
 storj.farm
@@ -12515,7 +12527,7 @@
 webspace.rocks
 lima.zone
 
-// TransIP : htts://www.transip.nl
+// TransIP : https://www.transip.nl
 // Submitted by Rory Breuk <rbreuk@transip.nl>
 *.transurl.be
 *.transurl.eu
@@ -12640,4 +12652,4 @@
 // Submitted by Su Hendro <admin@zone.id>
 zone.id
 
-// ===END PRIVATE DOMAINS===
+// ===END PRIVATE DOMAINS===
\ No newline at end of file
diff --git a/net/base/registry_controlled_domains/effective_tld_names.gperf b/net/base/registry_controlled_domains/effective_tld_names.gperf
index f1a5a5b..79452b7 100644
--- a/net/base/registry_controlled_domains/effective_tld_names.gperf
+++ b/net/base/registry_controlled_domains/effective_tld_names.gperf
@@ -336,6 +336,7 @@
 ap.leg.br, 4
 aparecida.br, 0
 apartments, 0
+apigee.io, 4
 app, 0
 app.lmpm.com, 4
 app.os.fedoraproject.org, 4
@@ -822,7 +823,7 @@
 bmoattachments.org, 4
 bms, 0
 bmw, 0
-bn, 2
+bn, 0
 bn.it, 0
 bnl, 0
 bnpparibas, 0
@@ -1248,6 +1249,7 @@
 cloudns.pro, 4
 cloudns.pw, 4
 cloudns.us, 4
+cloudycluster.net, 4
 club, 0
 club.aero, 0
 club.tw, 0
@@ -1255,11 +1257,13 @@
 cm, 0
 cn, 0
 cn-north-1.eb.amazonaws.com.cn, 4
+cn-northwest-1.eb.amazonaws.com.cn, 4
 cn.com, 4
 cn.eu.org, 4
 cn.it, 0
 cn.ua, 0
 cng.br, 0
+cnpy.gdn, 4
 cns.joyent.com, 6
 cnt.br, 0
 co, 0
@@ -1361,6 +1365,7 @@
 com.bh, 0
 com.bi, 0
 com.bm, 0
+com.bn, 0
 com.bo, 0
 com.br, 0
 com.bs, 0
@@ -1392,6 +1397,7 @@
 com.gp, 0
 com.gr, 0
 com.gt, 0
+com.gu, 0
 com.gy, 0
 com.hk, 0
 com.hn, 0
@@ -1406,6 +1412,7 @@
 com.ki, 0
 com.km, 0
 com.kp, 0
+com.kw, 0
 com.ky, 0
 com.kz, 0
 com.la, 0
@@ -1873,6 +1880,7 @@
 edu.bh, 0
 edu.bi, 0
 edu.bm, 0
+edu.bn, 0
 edu.bo, 0
 edu.br, 0
 edu.bs, 0
@@ -1900,6 +1908,7 @@
 edu.gp, 0
 edu.gr, 0
 edu.gt, 0
+edu.gu, 0
 edu.gy, 0
 edu.hk, 0
 edu.hn, 0
@@ -1915,6 +1924,7 @@
 edu.kn, 0
 edu.kp, 0
 edu.krd, 4
+edu.kw, 0
 edu.ky, 0
 edu.kz, 0
 edu.la, 0
@@ -2010,6 +2020,7 @@
 elvendrell.museum, 0
 elverum.no, 0
 email, 0
+emb.kw, 0
 embaixada.st, 0
 embetsu.hokkaido.jp, 0
 embroidery.museum, 0
@@ -2297,6 +2308,7 @@
 freeboxos.fr, 4
 freeddns.org, 4
 freeddns.us, 4
+freedesktop.org, 4
 freemasonry.museum, 0
 freesite.host, 4
 freetls.fastly.net, 4
@@ -2614,7 +2626,6 @@
 gon.pk, 0
 gonohe.aomori.jp, 0
 goo, 0
-goodhands, 0
 goodyear, 0
 goog, 0
 google, 0
@@ -2659,6 +2670,7 @@
 gov.bf, 0
 gov.bh, 0
 gov.bm, 0
+gov.bn, 0
 gov.br, 0
 gov.bs, 0
 gov.bt, 0
@@ -2684,6 +2696,7 @@
 gov.gi, 0
 gov.gn, 0
 gov.gr, 0
+gov.gu, 0
 gov.gy, 0
 gov.hk, 0
 gov.ie, 0
@@ -2699,6 +2712,7 @@
 gov.km, 0
 gov.kn, 0
 gov.kp, 0
+gov.kw, 0
 gov.ky, 0
 gov.kz, 0
 gov.la, 0
@@ -2829,8 +2843,9 @@
 gs.vf.no, 0
 gsm.pl, 0
 gt, 0
-gu, 2
+gu, 0
 gu.us, 0
+guam.gu, 0
 guardian, 0
 gub.uy, 0
 gucci, 0
@@ -2923,6 +2938,7 @@
 hashimoto.wakayama.jp, 0
 hasuda.saitama.jp, 0
 hasura-app.io, 4
+hasura.app, 4
 hasvik.no, 0
 hatogaya.saitama.jp, 0
 hatoyama.saitama.jp, 0
@@ -3274,6 +3290,7 @@
 ind.br, 0
 ind.gt, 0
 ind.in, 0
+ind.kw, 0
 ind.tn, 0
 inderoy.no, 0
 indian.museum, 0
@@ -3299,6 +3316,7 @@
 info.cx, 4
 info.ec, 0
 info.et, 0
+info.gu, 0
 info.ht, 0
 info.hu, 0
 info.ke, 0
@@ -3513,7 +3531,6 @@
 iwate.iwate.jp, 0
 iwate.jp, 0
 iwatsuki.saitama.jp, 0
-iwc, 0
 iwi.nz, 0
 iyo.ehime.jp, 0
 iz.hr, 0
@@ -3560,7 +3577,6 @@
 jinsekikogen.hiroshima.jp, 0
 jio, 0
 jl.cn, 0
-jlc, 0
 jll, 0
 jm, 2
 jmp, 0
@@ -4058,7 +4074,7 @@
 kvinnherad.no, 0
 kviteseid.no, 0
 kvitsoy.no, 0
-kw, 2
+kw, 0
 kwp.gov.pl, 0
 kwpsp.gov.pl, 0
 ky, 0
@@ -4503,7 +4519,6 @@
 memset.net, 4
 men, 0
 menu, 0
-meo, 0
 meraker.no, 0
 merckmsd, 0
 merseine.nu, 4
@@ -5084,6 +5099,7 @@
 net.bb, 0
 net.bh, 0
 net.bm, 0
+net.bn, 0
 net.bo, 0
 net.br, 0
 net.bs, 0
@@ -5110,6 +5126,7 @@
 net.gp, 0
 net.gr, 0
 net.gt, 0
+net.gu, 0
 net.gy, 0
 net.hk, 0
 net.hn, 0
@@ -5126,6 +5143,7 @@
 net.kg, 0
 net.ki, 0
 net.kn, 0
+net.kw, 0
 net.ky, 0
 net.kz, 0
 net.la, 0
@@ -5586,6 +5604,7 @@
 onagawa.miyagi.jp, 0
 one, 0
 ong, 0
+ong.br, 0
 onga.fukuoka.jp, 0
 onion, 0
 onjuku.chiba.jp, 0
@@ -5649,6 +5668,7 @@
 org.bh, 0
 org.bi, 0
 org.bm, 0
+org.bn, 0
 org.bo, 0
 org.br, 0
 org.bs, 0
@@ -5678,6 +5698,7 @@
 org.gp, 0
 org.gr, 0
 org.gt, 0
+org.gu, 0
 org.gy, 0
 org.hk, 0
 org.hn, 0
@@ -5696,6 +5717,7 @@
 org.km, 0
 org.kn, 0
 org.kp, 0
+org.kw, 0
 org.ky, 0
 org.kz, 0
 org.la, 0
@@ -5880,7 +5902,6 @@
 palmsprings.museum, 0
 panama.museum, 0
 panasonic, 0
-panerai, 0
 pantheonsite.io, 4
 parachuting.aero, 0
 paragliding.aero, 0
@@ -6026,6 +6047,7 @@
 poltava.ua, 0
 pomorskie.pl, 0
 pomorze.pl, 0
+ponpes.id, 0
 pordenone.it, 0
 porn, 0
 porsanger.no, 0
@@ -6505,7 +6527,6 @@
 saogonca.br, 0
 saotome.st, 0
 sap, 0
-sapo, 0
 sapporo.jp, 2
 sar.it, 0
 sardegna.it, 0
@@ -6960,7 +6981,6 @@
 ssl.origin.cdn77-secure.org, 4
 st, 0
 st.no, 0
-stackspace.space, 4
 stada, 0
 stadt.museum, 0
 stage.nodeart.io, 4
@@ -7227,7 +7247,6 @@
 tel, 0
 tel.tr, 0
 tele.amune.org, 4
-telecity, 0
 telefonica, 0
 telekommunikation.museum, 0
 television.museum, 0
@@ -7804,7 +7823,6 @@
 virtuel.museum, 0
 visa, 0
 vision, 0
-vista, 0
 vistaprint, 0
 viterbo.it, 0
 viva, 0
@@ -7890,6 +7908,7 @@
 web.bo, 0
 web.co, 0
 web.do, 0
+web.gu, 0
 web.id, 0
 web.lk, 0
 web.nf, 0
@@ -8439,7 +8458,6 @@
 xn--zf0avx.hk, 0
 xn--zfr164b, 0
 xnbay.com, 4
-xperia, 0
 xs4all.space, 4
 xxx, 0
 xyz, 0
diff --git a/services/media_session/BUILD.gn b/services/media_session/BUILD.gn
index 7831146e..974c1d3 100644
--- a/services/media_session/BUILD.gn
+++ b/services/media_session/BUILD.gn
@@ -42,6 +42,8 @@
   sources = [
     "audio_focus_manager_unittest.cc",
     "media_session_service_unittest.cc",
+    "mock_media_session.cc",
+    "mock_media_session.h",
   ]
 
   deps = [
diff --git a/services/media_session/audio_focus_manager.h b/services/media_session/audio_focus_manager.h
index cd9f845..42b79f8 100644
--- a/services/media_session/audio_focus_manager.h
+++ b/services/media_session/audio_focus_manager.h
@@ -23,6 +23,10 @@
 
 namespace media_session {
 
+namespace test {
+class MockMediaSession;
+}  // namespace test
+
 class AudioFocusManager : public mojom::AudioFocusManager,
                           public mojom::AudioFocusManagerDebug {
  public:
@@ -59,6 +63,7 @@
  private:
   friend struct base::DefaultSingletonTraits<AudioFocusManager>;
   friend class AudioFocusManagerTest;
+  friend class test::MockMediaSession;
 
   // StackRow is an AudioFocusRequestClient and allows a media session to
   // control its audio focus.
diff --git a/services/media_session/audio_focus_manager_unittest.cc b/services/media_session/audio_focus_manager_unittest.cc
index 3f441ab0..a146c8e 100644
--- a/services/media_session/audio_focus_manager_unittest.cc
+++ b/services/media_session/audio_focus_manager_unittest.cc
@@ -18,6 +18,7 @@
 #include "mojo/public/cpp/bindings/interface_request.h"
 #include "services/media_session/audio_focus_manager_metrics_helper.h"
 #include "services/media_session/media_session_service.h"
+#include "services/media_session/mock_media_session.h"
 #include "services/media_session/public/cpp/switches.h"
 #include "services/media_session/public/cpp/test/audio_focus_test_util.h"
 #include "services/media_session/public/mojom/audio_focus.mojom.h"
@@ -26,114 +27,11 @@
 
 namespace media_session {
 
-class AudioFocusManagerTest;
-
 namespace {
 
-const char kExampleDebugInfoName[] = "name";
-const char kExampleDebugInfoOwner[] = "owner";
-const char kExampleDebugInfoState[] = "state";
-
 const char kExampleSourceName[] = "test";
 const char kExampleSourceName2[] = "test2";
 
-class MockMediaSession : public mojom::MediaSession {
- public:
-  MockMediaSession() = default;
-  explicit MockMediaSession(bool force_duck) : force_duck_(force_duck) {}
-
-  ~MockMediaSession() override {}
-
-  void Suspend(SuspendType suspend_type) override {
-    DCHECK_EQ(SuspendType::kSystem, suspend_type);
-    SetState(mojom::MediaSessionInfo::SessionState::kSuspended);
-  }
-
-  void Resume(SuspendType suspend_type) override {
-    DCHECK_EQ(SuspendType::kSystem, suspend_type);
-    SetState(mojom::MediaSessionInfo::SessionState::kActive);
-  }
-
-  void StartDucking() override {
-    is_ducking_ = true;
-    NotifyObservers();
-  }
-
-  void StopDucking() override {
-    is_ducking_ = false;
-    NotifyObservers();
-  }
-
-  void GetMediaSessionInfo(GetMediaSessionInfoCallback callback) override {
-    std::move(callback).Run(GetSessionInfoSync());
-  }
-
-  void AddObserver(mojom::MediaSessionObserverPtr observer) override {}
-
-  void GetDebugInfo(GetDebugInfoCallback callback) override {
-    mojom::MediaSessionDebugInfoPtr debug_info(
-        mojom::MediaSessionDebugInfo::New());
-
-    debug_info->name = kExampleDebugInfoName;
-    debug_info->owner = kExampleDebugInfoOwner;
-    debug_info->state = kExampleDebugInfoState;
-
-    std::move(callback).Run(std::move(debug_info));
-  }
-
-  void BindToMojoRequest(mojo::InterfaceRequest<mojom::MediaSession> request) {
-    bindings_.AddBinding(this, std::move(request));
-  }
-
- protected:
-  // Audio Focus methods should be called from AudioFocusManagerTest.
-  friend class media_session::AudioFocusManagerTest;
-
-  mojom::AudioFocusRequestClient* audio_focus_request() {
-    return afr_client_.get();
-  }
-
-  bool HasAudioFocusRequest() const { return afr_client_.is_bound(); }
-
-  void ResetAudioFocusRequest() { afr_client_.reset(); }
-
-  void SetAudioFocusRequestClient(
-      mojom::AudioFocusRequestClientPtr afr_client) {
-    afr_client_ = std::move(afr_client);
-  }
-
-  void FlushForTesting() { afr_client_.FlushForTesting(); }
-
- private:
-  void SetState(mojom::MediaSessionInfo::SessionState state) {
-    state_ = state;
-    NotifyObservers();
-  }
-
-  void NotifyObservers() {
-    if (afr_client_.is_bound())
-      afr_client_->MediaSessionInfoChanged(GetSessionInfoSync());
-  }
-
-  mojom::MediaSessionInfoPtr GetSessionInfoSync() {
-    mojom::MediaSessionInfoPtr info(mojom::MediaSessionInfo::New());
-    info->force_duck = force_duck_;
-    info->state = state_;
-    if (is_ducking_)
-      info->state = mojom::MediaSessionInfo::SessionState::kDucking;
-    return info;
-  }
-
-  mojom::AudioFocusRequestClientPtr afr_client_;
-
-  const bool force_duck_ = false;
-  bool is_ducking_ = false;
-  mojom::MediaSessionInfo::SessionState state_ =
-      mojom::MediaSessionInfo::SessionState::kInactive;
-
-  mojo::BindingSet<mojom::MediaSession> bindings_;
-};
-
 }  // anonymous namespace
 
 // This tests the Audio Focus Manager API. The parameter determines whether
@@ -192,57 +90,17 @@
     return GetCountForType(mojom::AudioFocusType::kGainTransientMayDuck);
   }
 
-  void AbandonAudioFocus(MockMediaSession* session) {
-    AbandonAudioFocusNoReset(session);
-    session->ResetAudioFocusRequest();
-  }
-
-  void AbandonAudioFocusNoReset(MockMediaSession* session) {
-    DCHECK(session->HasAudioFocusRequest());
+  void AbandonAudioFocusNoReset(test::MockMediaSession* session) {
     session->audio_focus_request()->AbandonAudioFocus();
     session->FlushForTesting();
-
     FlushForTesting();
   }
 
   AudioFocusManager::RequestId RequestAudioFocus(
-      MockMediaSession* session,
+      test::MockMediaSession* session,
       mojom::AudioFocusType audio_focus_type) {
-    bool result;
-    base::OnceClosure callback =
-        base::BindOnce([](bool* out_result) { *out_result = true; }, &result);
-
-    if (session->HasAudioFocusRequest()) {
-      // Request audio focus through the existing request.
-      session->audio_focus_request()->RequestAudioFocus(
-          test::GetMediaSessionInfoSync(session), audio_focus_type,
-          std::move(callback));
-
-      session->FlushForTesting();
-    } else {
-      // Build a new audio focus request.
-      mojom::AudioFocusRequestClientPtr afr_client;
-
-      mojom::MediaSessionPtr media_session;
-      session->BindToMojoRequest(mojo::MakeRequest(&media_session));
-
-      GetService()->RequestAudioFocus(mojo::MakeRequest(&afr_client),
-                                      std::move(media_session),
-                                      test::GetMediaSessionInfoSync(session),
-                                      audio_focus_type, std::move(callback));
-
-      session->SetAudioFocusRequestClient(std::move(afr_client));
-
-      audio_focus_ptr_.FlushForTesting();
-    }
-
-    // If the audio focus was granted then we should set the session state to
-    // active.
-    if (result)
-      session->SetState(mojom::MediaSessionInfo::SessionState::kActive);
-
-    FlushForTestingIfEnabled();
-    return GetRequestIdForSession(session);
+    return session->RequestAudioFocusFromService(audio_focus_ptr_,
+                                                 audio_focus_type);
   }
 
   mojom::MediaSessionDebugInfoPtr GetDebugInfo(
@@ -264,9 +122,9 @@
     return result;
   }
 
-  mojom::MediaSessionInfo::SessionState GetState(MockMediaSession* session) {
-    mojom::MediaSessionInfo::SessionState state =
-        test::GetMediaSessionInfoSync(session)->state;
+  mojom::MediaSessionInfo::SessionState GetState(
+      test::MockMediaSession* session) {
+    mojom::MediaSessionInfo::SessionState state = session->GetState();
 
     if (!GetParam()) {
       // If audio focus enforcement is disabled then we should never see these
@@ -352,21 +210,6 @@
     return result;
   }
 
-  AudioFocusManager::RequestId GetRequestIdForSession(
-      MockMediaSession* session) {
-    DCHECK(session->HasAudioFocusRequest());
-    AudioFocusManager::RequestId id = base::UnguessableToken::Null();
-
-    session->audio_focus_request()->GetRequestId(base::BindOnce(
-        [](AudioFocusManager::RequestId* id,
-           const base::UnguessableToken& received_id) { *id = received_id; },
-        &id));
-
-    session->FlushForTesting();
-    EXPECT_NE(base::UnguessableToken::Null(), id);
-    return id;
-  }
-
   mojom::AudioFocusManager* GetService() const {
     return audio_focus_ptr_.get();
   }
@@ -407,9 +250,9 @@
 }
 
 TEST_P(AudioFocusManagerTest, RequestAudioFocusGain_ReplaceFocusedEntry) {
-  MockMediaSession media_session_1;
-  MockMediaSession media_session_2;
-  MockMediaSession media_session_3;
+  test::MockMediaSession media_session_1;
+  test::MockMediaSession media_session_2;
+  test::MockMediaSession media_session_3;
 
   EXPECT_EQ(base::UnguessableToken::Null(), GetAudioFocusedSession());
   EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kInactive,
@@ -441,7 +284,7 @@
 }
 
 TEST_P(AudioFocusManagerTest, RequestAudioFocusGain_Duplicate) {
-  MockMediaSession media_session;
+  test::MockMediaSession media_session;
 
   EXPECT_EQ(base::UnguessableToken::Null(), GetAudioFocusedSession());
 
@@ -454,7 +297,7 @@
 }
 
 TEST_P(AudioFocusManagerTest, RequestAudioFocusGain_FromTransient) {
-  MockMediaSession media_session;
+  test::MockMediaSession media_session;
 
   AudioFocusManager::RequestId request_id =
       RequestAudioFocus(&media_session, mojom::AudioFocusType::kGainTransient);
@@ -467,7 +310,7 @@
 }
 
 TEST_P(AudioFocusManagerTest, RequestAudioFocusGain_FromTransientMayDuck) {
-  MockMediaSession media_session;
+  test::MockMediaSession media_session;
 
   AudioFocusManager::RequestId request_id = RequestAudioFocus(
       &media_session, mojom::AudioFocusType::kGainTransientMayDuck);
@@ -480,7 +323,7 @@
 }
 
 TEST_P(AudioFocusManagerTest, RequestAudioFocusTransient_FromGain) {
-  MockMediaSession media_session;
+  test::MockMediaSession media_session;
 
   AudioFocusManager::RequestId request_id =
       RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain);
@@ -496,7 +339,7 @@
 }
 
 TEST_P(AudioFocusManagerTest, RequestAudioFocusTransientMayDuck_FromGain) {
-  MockMediaSession media_session;
+  test::MockMediaSession media_session;
 
   AudioFocusManager::RequestId request_id =
       RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain);
@@ -513,8 +356,8 @@
 }
 
 TEST_P(AudioFocusManagerTest, RequestAudioFocusTransient_FromGainWhileDucking) {
-  MockMediaSession media_session_1;
-  MockMediaSession media_session_2;
+  test::MockMediaSession media_session_1;
+  test::MockMediaSession media_session_2;
 
   RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain);
   EXPECT_EQ(0, GetTransientMaybeDuckCount());
@@ -537,8 +380,8 @@
 
 TEST_P(AudioFocusManagerTest,
        RequestAudioFocusTransientMayDuck_FromGainWhileDucking) {
-  MockMediaSession media_session_1;
-  MockMediaSession media_session_2;
+  test::MockMediaSession media_session_1;
+  test::MockMediaSession media_session_2;
 
   RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain);
   EXPECT_EQ(0, GetTransientMaybeDuckCount());
@@ -559,18 +402,18 @@
 }
 
 TEST_P(AudioFocusManagerTest, AbandonAudioFocus_RemovesFocusedEntry) {
-  MockMediaSession media_session;
+  test::MockMediaSession media_session;
 
   AudioFocusManager::RequestId request_id =
       RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain);
   EXPECT_EQ(request_id, GetAudioFocusedSession());
 
-  AbandonAudioFocus(&media_session);
+  media_session.AbandonAudioFocusFromClient();
   EXPECT_EQ(base::UnguessableToken::Null(), GetAudioFocusedSession());
 }
 
 TEST_P(AudioFocusManagerTest, AbandonAudioFocus_MultipleCalls) {
-  MockMediaSession media_session;
+  test::MockMediaSession media_session;
 
   AudioFocusManager::RequestId request_id =
       RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain);
@@ -579,14 +422,14 @@
   AbandonAudioFocusNoReset(&media_session);
 
   std::unique_ptr<test::TestAudioFocusObserver> observer = CreateObserver();
-  AbandonAudioFocus(&media_session);
+  media_session.AbandonAudioFocusFromClient();
 
   EXPECT_EQ(base::UnguessableToken::Null(), GetAudioFocusedSession());
   EXPECT_TRUE(observer->focus_lost_session_.is_null());
 }
 
 TEST_P(AudioFocusManagerTest, AbandonAudioFocus_RemovesTransientMayDuckEntry) {
-  MockMediaSession media_session;
+  test::MockMediaSession media_session;
 
   RequestAudioFocus(&media_session,
                     mojom::AudioFocusType::kGainTransientMayDuck);
@@ -594,7 +437,7 @@
 
   {
     std::unique_ptr<test::TestAudioFocusObserver> observer = CreateObserver();
-    AbandonAudioFocus(&media_session);
+    media_session.AbandonAudioFocusFromClient();
 
     EXPECT_EQ(0, GetTransientMaybeDuckCount());
     EXPECT_TRUE(observer->focus_lost_session_.Equals(
@@ -603,14 +446,14 @@
 }
 
 TEST_P(AudioFocusManagerTest, AbandonAudioFocus_RemovesTransientEntry) {
-  MockMediaSession media_session;
+  test::MockMediaSession media_session;
 
   RequestAudioFocus(&media_session, mojom::AudioFocusType::kGainTransient);
   EXPECT_EQ(1, GetTransientCount());
 
   {
     std::unique_ptr<test::TestAudioFocusObserver> observer = CreateObserver();
-    AbandonAudioFocus(&media_session);
+    media_session.AbandonAudioFocusFromClient();
 
     EXPECT_EQ(0, GetTransientCount());
     EXPECT_TRUE(observer->focus_lost_session_.Equals(
@@ -619,8 +462,8 @@
 }
 
 TEST_P(AudioFocusManagerTest, AbandonAudioFocus_WhileDuckingThenResume) {
-  MockMediaSession media_session_1;
-  MockMediaSession media_session_2;
+  test::MockMediaSession media_session_1;
+  test::MockMediaSession media_session_2;
 
   RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain);
   EXPECT_EQ(0, GetTransientMaybeDuckCount());
@@ -633,10 +476,10 @@
   EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking),
             GetState(&media_session_1));
 
-  AbandonAudioFocus(&media_session_1);
+  media_session_1.AbandonAudioFocusFromClient();
   EXPECT_EQ(1, GetTransientMaybeDuckCount());
 
-  AbandonAudioFocus(&media_session_2);
+  media_session_2.AbandonAudioFocusFromClient();
   EXPECT_EQ(0, GetTransientMaybeDuckCount());
 
   RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain);
@@ -645,8 +488,8 @@
 }
 
 TEST_P(AudioFocusManagerTest, AbandonAudioFocus_StopsDucking) {
-  MockMediaSession media_session_1;
-  MockMediaSession media_session_2;
+  test::MockMediaSession media_session_1;
+  test::MockMediaSession media_session_2;
 
   RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain);
   EXPECT_EQ(0, GetTransientMaybeDuckCount());
@@ -659,15 +502,15 @@
   EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking),
             GetState(&media_session_1));
 
-  AbandonAudioFocus(&media_session_2);
+  media_session_2.AbandonAudioFocusFromClient();
   EXPECT_EQ(0, GetTransientMaybeDuckCount());
   EXPECT_NE(mojom::MediaSessionInfo::SessionState::kDucking,
             GetState(&media_session_1));
 }
 
 TEST_P(AudioFocusManagerTest, AbandonAudioFocus_ResumesPlayback) {
-  MockMediaSession media_session_1;
-  MockMediaSession media_session_2;
+  test::MockMediaSession media_session_1;
+  test::MockMediaSession media_session_2;
 
   RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain);
   EXPECT_EQ(0, GetTransientCount());
@@ -680,15 +523,15 @@
       GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended),
       GetState(&media_session_1));
 
-  AbandonAudioFocus(&media_session_2);
+  media_session_2.AbandonAudioFocusFromClient();
   EXPECT_EQ(0, GetTransientCount());
   EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive,
             GetState(&media_session_1));
 }
 
 TEST_P(AudioFocusManagerTest, DuckWhilePlaying) {
-  MockMediaSession media_session_1;
-  MockMediaSession media_session_2;
+  test::MockMediaSession media_session_1;
+  test::MockMediaSession media_session_2;
 
   RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain);
   EXPECT_NE(mojom::MediaSessionInfo::SessionState::kDucking,
@@ -701,8 +544,8 @@
 }
 
 TEST_P(AudioFocusManagerTest, GainSuspendsTransient) {
-  MockMediaSession media_session_1;
-  MockMediaSession media_session_2;
+  test::MockMediaSession media_session_1;
+  test::MockMediaSession media_session_2;
 
   RequestAudioFocus(&media_session_2, mojom::AudioFocusType::kGainTransient);
 
@@ -713,8 +556,8 @@
 }
 
 TEST_P(AudioFocusManagerTest, GainSuspendsTransientMayDuck) {
-  MockMediaSession media_session_1;
-  MockMediaSession media_session_2;
+  test::MockMediaSession media_session_1;
+  test::MockMediaSession media_session_2;
 
   RequestAudioFocus(&media_session_2,
                     mojom::AudioFocusType::kGainTransientMayDuck);
@@ -726,10 +569,10 @@
 }
 
 TEST_P(AudioFocusManagerTest, DuckWithMultipleTransientMayDucks) {
-  MockMediaSession media_session_1;
-  MockMediaSession media_session_2;
-  MockMediaSession media_session_3;
-  MockMediaSession media_session_4;
+  test::MockMediaSession media_session_1;
+  test::MockMediaSession media_session_2;
+  test::MockMediaSession media_session_3;
+  test::MockMediaSession media_session_4;
 
   RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain);
   EXPECT_NE(mojom::MediaSessionInfo::SessionState::kDucking,
@@ -753,13 +596,13 @@
   EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking),
             GetState(&media_session_2));
 
-  AbandonAudioFocus(&media_session_3);
+  media_session_3.AbandonAudioFocusFromClient();
   EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking),
             GetState(&media_session_1));
   EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking),
             GetState(&media_session_2));
 
-  AbandonAudioFocus(&media_session_4);
+  media_session_4.AbandonAudioFocusFromClient();
   EXPECT_NE(mojom::MediaSessionInfo::SessionState::kDucking,
             GetState(&media_session_1));
   EXPECT_NE(mojom::MediaSessionInfo::SessionState::kDucking,
@@ -768,7 +611,7 @@
 
 TEST_P(AudioFocusManagerTest, MediaSessionDestroyed_ReleasesFocus) {
   {
-    MockMediaSession media_session;
+    test::MockMediaSession media_session;
 
     AudioFocusManager::RequestId request_id =
         RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain);
@@ -777,7 +620,7 @@
 
   // If the media session is destroyed without abandoning audio focus we do not
   // know until we next interact with the manager.
-  MockMediaSession media_session;
+  test::MockMediaSession media_session;
   RequestAudioFocus(&media_session,
                     mojom::AudioFocusType::kGainTransientMayDuck);
   EXPECT_EQ(base::UnguessableToken::Null(), GetAudioFocusedSession());
@@ -785,21 +628,21 @@
 
 TEST_P(AudioFocusManagerTest, MediaSessionDestroyed_ReleasesTransient) {
   {
-    MockMediaSession media_session;
+    test::MockMediaSession media_session;
     RequestAudioFocus(&media_session, mojom::AudioFocusType::kGainTransient);
     EXPECT_EQ(1, GetTransientCount());
   }
 
   // If the media session is destroyed without abandoning audio focus we do not
   // know until we next interact with the manager.
-  MockMediaSession media_session;
+  test::MockMediaSession media_session;
   RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain);
   EXPECT_EQ(0, GetTransientCount());
 }
 
 TEST_P(AudioFocusManagerTest, MediaSessionDestroyed_ReleasesTransientMayDucks) {
   {
-    MockMediaSession media_session;
+    test::MockMediaSession media_session;
     RequestAudioFocus(&media_session,
                       mojom::AudioFocusType::kGainTransientMayDuck);
     EXPECT_EQ(1, GetTransientMaybeDuckCount());
@@ -807,14 +650,14 @@
 
   // If the media session is destroyed without abandoning audio focus we do not
   // know until we next interact with the manager.
-  MockMediaSession media_session;
+  test::MockMediaSession media_session;
   RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain);
   EXPECT_EQ(0, GetTransientMaybeDuckCount());
 }
 
 TEST_P(AudioFocusManagerTest, GainDucksForceDuck) {
-  MockMediaSession media_session_1(true /* force_duck */);
-  MockMediaSession media_session_2;
+  test::MockMediaSession media_session_1(true /* force_duck */);
+  test::MockMediaSession media_session_2;
 
   RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain);
 
@@ -828,9 +671,9 @@
 
 TEST_P(AudioFocusManagerTest,
        AbandoningGainFocusRevokesTopMostForceDuckSession) {
-  MockMediaSession media_session_1(true /* force_duck */);
-  MockMediaSession media_session_2;
-  MockMediaSession media_session_3;
+  test::MockMediaSession media_session_1(true /* force_duck */);
+  test::MockMediaSession media_session_2;
+  test::MockMediaSession media_session_3;
 
   AudioFocusManager::RequestId request_id_1 =
       RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain);
@@ -847,12 +690,12 @@
   EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking),
             GetState(&media_session_1));
 
-  AbandonAudioFocus(&media_session_3);
+  media_session_3.AbandonAudioFocusFromClient();
   EXPECT_EQ(GetParam() ? request_id_1 : request_id_2, GetAudioFocusedSession());
 }
 
 TEST_P(AudioFocusManagerTest, AudioFocusObserver_RequestNoop) {
-  MockMediaSession media_session;
+  test::MockMediaSession media_session;
   AudioFocusManager::RequestId request_id;
 
   {
@@ -875,7 +718,7 @@
 }
 
 TEST_P(AudioFocusManagerTest, AudioFocusObserver_TransientMayDuck) {
-  MockMediaSession media_session;
+  test::MockMediaSession media_session;
 
   {
     std::unique_ptr<test::TestAudioFocusObserver> observer = CreateObserver();
@@ -890,7 +733,7 @@
 
   {
     std::unique_ptr<test::TestAudioFocusObserver> observer = CreateObserver();
-    AbandonAudioFocus(&media_session);
+    media_session.AbandonAudioFocusFromClient();
 
     EXPECT_EQ(0, GetTransientMaybeDuckCount());
     EXPECT_TRUE(observer->focus_lost_session_.Equals(
@@ -899,14 +742,14 @@
 }
 
 TEST_P(AudioFocusManagerTest, GetDebugInfo) {
-  MockMediaSession media_session;
+  test::MockMediaSession media_session;
   AudioFocusManager::RequestId request_id =
       RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain);
 
   mojom::MediaSessionDebugInfoPtr debug_info = GetDebugInfo(request_id);
-  EXPECT_EQ(kExampleDebugInfoName, debug_info->name);
-  EXPECT_EQ(kExampleDebugInfoOwner, debug_info->owner);
-  EXPECT_EQ(kExampleDebugInfoState, debug_info->state);
+  EXPECT_FALSE(debug_info->name.empty());
+  EXPECT_FALSE(debug_info->owner.empty());
+  EXPECT_FALSE(debug_info->state.empty());
 }
 
 TEST_P(AudioFocusManagerTest, GetDebugInfo_BadRequestId) {
@@ -917,8 +760,8 @@
 
 TEST_P(AudioFocusManagerTest,
        RequestAudioFocusTransient_FromGainWhileSuspended) {
-  MockMediaSession media_session_1;
-  MockMediaSession media_session_2;
+  test::MockMediaSession media_session_1;
+  test::MockMediaSession media_session_2;
 
   RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain);
   EXPECT_EQ(0, GetTransientCount());
@@ -939,8 +782,8 @@
 
 TEST_P(AudioFocusManagerTest,
        RequestAudioFocusTransientMayDuck_FromGainWhileSuspended) {
-  MockMediaSession media_session_1;
-  MockMediaSession media_session_2;
+  test::MockMediaSession media_session_1;
+  test::MockMediaSession media_session_2;
 
   RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain);
   EXPECT_EQ(0, GetTransientCount());
@@ -970,13 +813,13 @@
   new_ptr->SetSourceName(kExampleSourceName2);
   new_ptr.FlushForTesting();
 
-  MockMediaSession media_session;
+  test::MockMediaSession media_session;
   RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain);
   EXPECT_EQ(kExampleSourceName, GetSourceNameForLastRequest());
 }
 
 TEST_P(AudioFocusManagerTest, SourceName_Empty) {
-  MockMediaSession media_session;
+  test::MockMediaSession media_session;
   RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain);
   EXPECT_TRUE(GetSourceNameForLastRequest().empty());
 }
@@ -984,7 +827,7 @@
 TEST_P(AudioFocusManagerTest, SourceName_Updated) {
   SetSourceName(kExampleSourceName);
 
-  MockMediaSession media_session;
+  test::MockMediaSession media_session;
   RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain);
   EXPECT_EQ(kExampleSourceName, GetSourceNameForLastRequest());
 
@@ -996,7 +839,7 @@
   EXPECT_EQ(0, GetAudioFocusHistogramCount());
 
   SetSourceName(kExampleSourceName);
-  MockMediaSession media_session;
+  test::MockMediaSession media_session;
   RequestAudioFocus(&media_session, mojom::AudioFocusType::kGainTransient);
 
   {
@@ -1046,7 +889,7 @@
 
   EXPECT_EQ(2, GetAudioFocusHistogramCount());
 
-  AbandonAudioFocus(&media_session);
+  media_session.AbandonAudioFocusFromClient();
 
   {
     std::unique_ptr<base::HistogramSamples> samples(
@@ -1065,11 +908,11 @@
   SetSourceName(kExampleSourceName);
 
   {
-    MockMediaSession media_session;
+    test::MockMediaSession media_session;
     RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain);
   }
 
-  MockMediaSession media_session;
+  test::MockMediaSession media_session;
   RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain);
 
   {
@@ -1084,7 +927,7 @@
 }
 
 TEST_P(AudioFocusManagerTest, RecordUmaMetrics_NoSourceName) {
-  MockMediaSession media_session;
+  test::MockMediaSession media_session;
   RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain);
 
   EXPECT_EQ(0, GetAudioFocusHistogramCount());
diff --git a/services/media_session/mock_media_session.cc b/services/media_session/mock_media_session.cc
new file mode 100644
index 0000000..b881381d
--- /dev/null
+++ b/services/media_session/mock_media_session.cc
@@ -0,0 +1,144 @@
+// Copyright 2018 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/media_session/mock_media_session.h"
+
+#include <utility>
+
+#include "services/media_session/audio_focus_manager.h"
+#include "services/media_session/public/cpp/switches.h"
+
+namespace media_session {
+namespace test {
+
+MockMediaSession::MockMediaSession() = default;
+
+MockMediaSession::MockMediaSession(bool force_duck) : force_duck_(force_duck) {}
+
+MockMediaSession::~MockMediaSession() {}
+
+void MockMediaSession::Suspend(SuspendType suspend_type) {
+  DCHECK_EQ(SuspendType::kSystem, suspend_type);
+  SetState(mojom::MediaSessionInfo::SessionState::kSuspended);
+}
+
+void MockMediaSession::Resume(SuspendType suspend_type) {
+  DCHECK_EQ(SuspendType::kSystem, suspend_type);
+  SetState(mojom::MediaSessionInfo::SessionState::kActive);
+}
+
+void MockMediaSession::StartDucking() {
+  is_ducking_ = true;
+  NotifyObservers();
+}
+
+void MockMediaSession::StopDucking() {
+  is_ducking_ = false;
+  NotifyObservers();
+}
+
+void MockMediaSession::GetMediaSessionInfo(
+    GetMediaSessionInfoCallback callback) {
+  std::move(callback).Run(GetMediaSessionInfoSync());
+}
+
+void MockMediaSession::AddObserver(mojom::MediaSessionObserverPtr observer) {}
+
+void MockMediaSession::GetDebugInfo(GetDebugInfoCallback callback) {
+  mojom::MediaSessionDebugInfoPtr debug_info(
+      mojom::MediaSessionDebugInfo::New());
+
+  debug_info->name = "name";
+  debug_info->owner = "owner";
+  debug_info->state = "state";
+
+  std::move(callback).Run(std::move(debug_info));
+}
+
+void MockMediaSession::AbandonAudioFocusFromClient() {
+  DCHECK(afr_client_.is_bound());
+  afr_client_->AbandonAudioFocus();
+  afr_client_.FlushForTesting();
+  afr_client_.reset();
+}
+
+base::UnguessableToken MockMediaSession::GetRequestIdFromClient() {
+  DCHECK(afr_client_.is_bound());
+  base::UnguessableToken id = base::UnguessableToken::Null();
+
+  afr_client_->GetRequestId(base::BindOnce(
+      [](base::UnguessableToken* id,
+         const base::UnguessableToken& received_id) { *id = received_id; },
+      &id));
+
+  afr_client_.FlushForTesting();
+  DCHECK_NE(base::UnguessableToken::Null(), id);
+  return id;
+}
+
+base::UnguessableToken MockMediaSession::RequestAudioFocusFromService(
+    mojom::AudioFocusManagerPtr& service,
+    mojom::AudioFocusType audio_focus_type) {
+  bool result;
+  base::OnceClosure callback =
+      base::BindOnce([](bool* out_result) { *out_result = true; }, &result);
+
+  if (afr_client_.is_bound()) {
+    // Request audio focus through the existing request.
+    afr_client_->RequestAudioFocus(GetMediaSessionInfoSync(), audio_focus_type,
+                                   std::move(callback));
+
+    afr_client_.FlushForTesting();
+  } else {
+    // Build a new audio focus request.
+    mojom::MediaSessionPtr media_session;
+    bindings_.AddBinding(this, mojo::MakeRequest(&media_session));
+
+    service->RequestAudioFocus(
+        mojo::MakeRequest(&afr_client_), std::move(media_session),
+        GetMediaSessionInfoSync(), audio_focus_type, std::move(callback));
+
+    service.FlushForTesting();
+  }
+
+  // If the audio focus was granted then we should set the session state to
+  // active.
+  if (result)
+    SetState(mojom::MediaSessionInfo::SessionState::kActive);
+
+  if (IsAudioFocusEnforcementEnabled())
+    AudioFocusManager::GetInstance()->FlushForTesting();
+
+  return GetRequestIdFromClient();
+}
+
+mojom::MediaSessionInfo::SessionState MockMediaSession::GetState() const {
+  return GetMediaSessionInfoSync()->state;
+}
+
+void MockMediaSession::FlushForTesting() {
+  afr_client_.FlushForTesting();
+}
+
+void MockMediaSession::SetState(mojom::MediaSessionInfo::SessionState state) {
+  state_ = state;
+  NotifyObservers();
+}
+
+void MockMediaSession::NotifyObservers() {
+  if (afr_client_.is_bound())
+    afr_client_->MediaSessionInfoChanged(GetMediaSessionInfoSync());
+}
+
+mojom::MediaSessionInfoPtr MockMediaSession::GetMediaSessionInfoSync() const {
+  mojom::MediaSessionInfoPtr info(mojom::MediaSessionInfo::New());
+  info->force_duck = force_duck_;
+  info->state = state_;
+  if (is_ducking_)
+    info->state = mojom::MediaSessionInfo::SessionState::kDucking;
+  return info;
+}
+
+}  // namespace test
+}  // namespace media_session
diff --git a/services/media_session/mock_media_session.h b/services/media_session/mock_media_session.h
new file mode 100644
index 0000000..6b6a6072
--- /dev/null
+++ b/services/media_session/mock_media_session.h
@@ -0,0 +1,72 @@
+// Copyright 2018 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_MEDIA_SESSION_MOCK_MEDIA_SESSION_H_
+#define SERVICES_MEDIA_SESSION_MOCK_MEDIA_SESSION_H_
+
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/media_session/public/mojom/audio_focus.mojom.h"
+#include "services/media_session/public/mojom/media_session.mojom.h"
+
+namespace base {
+class UnguessableToken;
+}  // namespace base
+
+namespace media_session {
+namespace test {
+
+// A mock MediaSession that can be used for interacting with the Media Session
+// service during tests.
+class MockMediaSession : public mojom::MediaSession {
+ public:
+  MockMediaSession();
+  explicit MockMediaSession(bool force_duck);
+
+  ~MockMediaSession() override;
+
+  // mojom::MediaSession overrides.
+  void Suspend(SuspendType) override;
+  void Resume(SuspendType) override;
+  void StartDucking() override;
+  void StopDucking() override;
+  void GetMediaSessionInfo(GetMediaSessionInfoCallback) override;
+  void AddObserver(mojom::MediaSessionObserverPtr) override;
+  void GetDebugInfo(GetDebugInfoCallback) override;
+
+  void AbandonAudioFocusFromClient();
+  base::UnguessableToken GetRequestIdFromClient();
+
+  base::UnguessableToken RequestAudioFocusFromService(
+      mojom::AudioFocusManagerPtr&,
+      mojom::AudioFocusType);
+
+  mojom::MediaSessionInfo::SessionState GetState() const;
+
+  mojom::AudioFocusRequestClient* audio_focus_request() const {
+    return afr_client_.get();
+  }
+  void FlushForTesting();
+
+ private:
+  void SetState(mojom::MediaSessionInfo::SessionState);
+  void NotifyObservers();
+  mojom::MediaSessionInfoPtr GetMediaSessionInfoSync() const;
+
+  mojom::AudioFocusRequestClientPtr afr_client_;
+
+  const bool force_duck_ = false;
+  bool is_ducking_ = false;
+
+  mojom::MediaSessionInfo::SessionState state_ =
+      mojom::MediaSessionInfo::SessionState::kInactive;
+
+  mojo::BindingSet<mojom::MediaSession> bindings_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockMediaSession);
+};
+
+}  // namespace test
+}  // namespace media_session
+
+#endif  // SERVICES_MEDIA_SESSION_MOCK_MEDIA_SESSION_H_
diff --git a/services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.cc b/services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.cc
index 683d875..ee129155 100644
--- a/services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.cc
+++ b/services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.cc
@@ -76,16 +76,16 @@
   mojom::LifecycleState old_state = lifecycle_state_;
   lifecycle_state_ = state;
 
+  // Notify parents of this change.
   if (process_coordination_unit_)
     process_coordination_unit_->OnFrameLifecycleStateChanged(this, old_state);
+  if (page_coordination_unit_)
+    page_coordination_unit_->OnFrameLifecycleStateChanged(this, old_state);
+}
 
-  // The page will have the same lifecycle state as the main frame.
-  if (IsMainFrame() && GetPageCoordinationUnit()) {
-    // TODO(fdoray): Store the lifecycle state as a member on the
-    // PageCoordinationUnit rather than a non-typed property.
-    GetPageCoordinationUnit()->SetProperty(mojom::PropertyType::kLifecycleState,
-                                           static_cast<int64_t>(state));
-  }
+void FrameCoordinationUnitImpl::SetHasNonEmptyBeforeUnload(
+    bool has_nonempty_beforeunload) {
+  has_nonempty_beforeunload_ = has_nonempty_beforeunload;
 }
 
 void FrameCoordinationUnitImpl::OnAlertFired() {
diff --git a/services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.h b/services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.h
index 5a8dc2f..b3f43c6 100644
--- a/services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.h
+++ b/services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.h
@@ -35,6 +35,7 @@
   void SetAudibility(bool audible) override;
   void SetNetworkAlmostIdle(bool idle) override;
   void SetLifecycleState(mojom::LifecycleState state) override;
+  void SetHasNonEmptyBeforeUnload(bool has_nonempty_beforeunload) override;
   void OnAlertFired() override;
   void OnNonPersistentNotificationCreated() override;
 
@@ -45,6 +46,7 @@
 
   mojom::LifecycleState lifecycle_state() const { return lifecycle_state_; }
   base::TimeTicks last_audible_time() const { return last_audible_time_; }
+  bool has_nonempty_beforeunload() const { return has_nonempty_beforeunload_; }
 
   const std::set<FrameCoordinationUnitImpl*>&
   child_frame_coordination_units_for_testing() const {
@@ -83,6 +85,7 @@
   std::set<FrameCoordinationUnitImpl*> child_frame_coordination_units_;
 
   mojom::LifecycleState lifecycle_state_ = mojom::LifecycleState::kRunning;
+  bool has_nonempty_beforeunload_ = false;
   base::TimeTicks last_audible_time_;
 
   DISALLOW_COPY_AND_ASSIGN(FrameCoordinationUnitImpl);
diff --git a/services/resource_coordinator/coordination_unit/frame_coordination_unit_impl_unittest.cc b/services/resource_coordinator/coordination_unit/frame_coordination_unit_impl_unittest.cc
index 779c8fb..e03341d 100644
--- a/services/resource_coordinator/coordination_unit/frame_coordination_unit_impl_unittest.cc
+++ b/services/resource_coordinator/coordination_unit/frame_coordination_unit_impl_unittest.cc
@@ -155,34 +155,43 @@
 
   // Freezing a child frame should not affect the page state.
   cu_graph.child_frame->SetLifecycleState(mojom::LifecycleState::kFrozen);
-  // Verify that the frame is frozen.
-  EXPECT_EQ(mojom::LifecycleState::kFrozen,
-            cu_graph.child_frame->lifecycle_state());
-  // But all pages remain active.
   EXPECT_RUNNING(cu_graph.page);
   EXPECT_RUNNING(cu_graph.other_page);
 
-  // Freezing a page main frame should freeze that page.
+  // Freezing the only frame in a page should freeze that page.
   cu_graph.frame->SetLifecycleState(mojom::LifecycleState::kFrozen);
-  EXPECT_EQ(mojom::LifecycleState::kFrozen, cu_graph.frame->lifecycle_state());
   EXPECT_FROZEN(cu_graph.page);
+  EXPECT_RUNNING(cu_graph.other_page);
 
-  // Freezing the other page main frame.
-  cu_graph.other_frame->SetLifecycleState(mojom::LifecycleState::kFrozen);
-  EXPECT_EQ(mojom::LifecycleState::kFrozen,
-            cu_graph.other_frame->lifecycle_state());
-  EXPECT_FROZEN(cu_graph.other_page);
-
-  // Unfreezing subframe should have no effect.
+  // Unfreeze the child frame in the other page.
   cu_graph.child_frame->SetLifecycleState(mojom::LifecycleState::kRunning);
-  // Verify that the frame is unfrozen.
-  EXPECT_EQ(mojom::LifecycleState::kRunning,
-            cu_graph.child_frame->lifecycle_state());
-  // But the page is still frozen
+  EXPECT_FROZEN(cu_graph.page);
+  EXPECT_RUNNING(cu_graph.other_page);
+
+  // Freezing the main frame in the other page should not alter that pages
+  // state, as there is still a child frame that is running.
+  cu_graph.other_frame->SetLifecycleState(mojom::LifecycleState::kFrozen);
+  EXPECT_FROZEN(cu_graph.page);
+  EXPECT_RUNNING(cu_graph.other_page);
+
+  // Refreezing the child frame should freeze the page.
+  cu_graph.child_frame->SetLifecycleState(mojom::LifecycleState::kFrozen);
+  EXPECT_FROZEN(cu_graph.page);
   EXPECT_FROZEN(cu_graph.other_page);
 
-  // Unfreezing the main frame should unfreeze the page.
+  // Unfreezing a main frame should unfreeze the associated page.
+  cu_graph.frame->SetLifecycleState(mojom::LifecycleState::kRunning);
+  EXPECT_RUNNING(cu_graph.page);
+  EXPECT_FROZEN(cu_graph.other_page);
+
+  // Unfreezing the child frame should unfreeze the associated page.
+  cu_graph.child_frame->SetLifecycleState(mojom::LifecycleState::kRunning);
+  EXPECT_RUNNING(cu_graph.page);
+  EXPECT_RUNNING(cu_graph.other_page);
+
+  // Unfreezing the main frame shouldn't change anything.
   cu_graph.other_frame->SetLifecycleState(mojom::LifecycleState::kRunning);
+  EXPECT_RUNNING(cu_graph.page);
   EXPECT_RUNNING(cu_graph.other_page);
 }
 
diff --git a/services/resource_coordinator/coordination_unit/page_coordination_unit_impl.cc b/services/resource_coordinator/coordination_unit/page_coordination_unit_impl.cc
index 9ccd80d..268b9af 100644
--- a/services/resource_coordinator/coordination_unit/page_coordination_unit_impl.cc
+++ b/services/resource_coordinator/coordination_unit/page_coordination_unit_impl.cc
@@ -145,6 +145,21 @@
   return nullptr;
 }
 
+void PageCoordinationUnitImpl::OnFrameLifecycleStateChanged(
+    FrameCoordinationUnitImpl* frame_cu,
+    mojom::LifecycleState old_state) {
+  DCHECK(base::ContainsKey(frame_coordination_units_, frame_cu));
+  DCHECK_NE(old_state, frame_cu->lifecycle_state());
+
+  int delta = 0;
+  if (old_state == mojom::LifecycleState::kFrozen)
+    delta = -1;
+  else if (frame_cu->lifecycle_state() == mojom::LifecycleState::kFrozen)
+    delta = 1;
+  if (delta != 0)
+    OnNumFrozenFramesStateChange(delta);
+}
+
 void PageCoordinationUnitImpl::OnEventReceived(mojom::Event event) {
   for (auto& observer : observers())
     observer.OnPageEventReceived(this, event);
@@ -160,14 +175,62 @@
 }
 
 bool PageCoordinationUnitImpl::AddFrame(FrameCoordinationUnitImpl* frame_cu) {
-  return frame_coordination_units_.count(frame_cu)
-             ? false
-             : frame_coordination_units_.insert(frame_cu).second;
+  const bool inserted = frame_coordination_units_.insert(frame_cu).second;
+  if (inserted) {
+    OnNumFrozenFramesStateChange(
+        frame_cu->lifecycle_state() == mojom::LifecycleState::kFrozen ? 1 : 0);
+  }
+  return inserted;
 }
 
 bool PageCoordinationUnitImpl::RemoveFrame(
     FrameCoordinationUnitImpl* frame_cu) {
-  return frame_coordination_units_.erase(frame_cu) > 0;
+  bool removed = frame_coordination_units_.erase(frame_cu) > 0;
+  if (removed) {
+    OnNumFrozenFramesStateChange(
+        frame_cu->lifecycle_state() == mojom::LifecycleState::kFrozen ? -1 : 0);
+  }
+  return removed;
+}
+
+void PageCoordinationUnitImpl::OnNumFrozenFramesStateChange(
+    int num_frozen_frames_delta) {
+  num_frozen_frames_ += num_frozen_frames_delta;
+  DCHECK_GE(num_frozen_frames_, 0u);
+  DCHECK_LE(num_frozen_frames_, frame_coordination_units_.size());
+
+  const int64_t kRunning =
+      static_cast<int64_t>(mojom::LifecycleState::kRunning);
+  const int64_t kFrozen = static_cast<int64_t>(mojom::LifecycleState::kFrozen);
+
+  // We are interested in knowing when we have transitioned to or from
+  // "fully frozen". A page with no frames is considered to be running by
+  // default.
+  bool was_fully_frozen =
+      GetPropertyOrDefault(mojom::PropertyType::kLifecycleState, kRunning) ==
+      kFrozen;
+  bool is_fully_frozen = frame_coordination_units_.size() > 0 &&
+                         num_frozen_frames_ == frame_coordination_units_.size();
+  if (was_fully_frozen == is_fully_frozen)
+    return;
+
+  if (is_fully_frozen) {
+    // Aggregate the beforeunload handler information from the entire frame
+    // tree.
+    bool has_nonempty_beforeunload = false;
+    for (auto* frame : frame_coordination_units_) {
+      if (frame->has_nonempty_beforeunload()) {
+        has_nonempty_beforeunload = true;
+        break;
+      }
+    }
+    set_has_nonempty_beforeunload(has_nonempty_beforeunload);
+  }
+
+  // TODO(fdoray): Store the lifecycle state as a member on the
+  // PageCoordinationUnit rather than as a non-typed property.
+  SetProperty(mojom::PropertyType::kLifecycleState,
+              is_fully_frozen ? kFrozen : kRunning);
 }
 
 }  // namespace resource_coordinator
diff --git a/services/resource_coordinator/coordination_unit/page_coordination_unit_impl.h b/services/resource_coordinator/coordination_unit/page_coordination_unit_impl.h
index 89d8fcd..db05abe 100644
--- a/services/resource_coordinator/coordination_unit/page_coordination_unit_impl.h
+++ b/services/resource_coordinator/coordination_unit/page_coordination_unit_impl.h
@@ -86,10 +86,17 @@
       uint64_t private_footprint_kb_estimate) {
     private_footprint_kb_estimate_ = private_footprint_kb_estimate;
   }
+  void set_has_nonempty_beforeunload(bool has_nonempty_beforeunload) {
+    has_nonempty_beforeunload_ = has_nonempty_beforeunload;
+  }
 
   const std::string& main_frame_url() const { return main_frame_url_; }
   int64_t navigation_id() const { return navigation_id_; }
 
+  // Invoked when the state of a frame in this page changes.
+  void OnFrameLifecycleStateChanged(FrameCoordinationUnitImpl* frame_cu,
+                                    mojom::LifecycleState old_state);
+
  private:
   friend class FrameCoordinationUnitImpl;
 
@@ -101,6 +108,13 @@
   bool AddFrame(FrameCoordinationUnitImpl* frame_cu);
   bool RemoveFrame(FrameCoordinationUnitImpl* frame_cu);
 
+  // This is called whenever |num_frozen_frames_| changes, or whenever
+  // |frame_coordination_units_.size()| changes. It is used to synthesize the
+  // value of |has_nonempty_beforeunload| and to update the LifecycleState of
+  // the page. Calling this with |num_frozen_frames_delta == 0| implies that the
+  // number of frames itself has changed.
+  void OnNumFrozenFramesStateChange(int num_frozen_frames_delta);
+
   std::set<FrameCoordinationUnitImpl*> frame_coordination_units_;
 
   base::TimeTicks visibility_change_time_;
@@ -120,6 +134,15 @@
   // The most current memory footprint estimate.
   uint64_t private_footprint_kb_estimate_ = 0;
 
+  // Counts the number of frames in a page that are frozen.
+  size_t num_frozen_frames_ = 0;
+
+  // Indicates whether or not this page has a non-empty beforeunload handler.
+  // This is an aggregation of the same value on each frame in the page's frame
+  // tree. The aggregation is made at the moment all frames associated with a
+  // page have transition to frozen.
+  bool has_nonempty_beforeunload_ = false;
+
   // The URL the main frame last committed a navigation to and the unique ID of
   // the associated navigation handle.
   std::string main_frame_url_;
diff --git a/services/resource_coordinator/coordination_unit/page_coordination_unit_impl_unittest.cc b/services/resource_coordinator/coordination_unit/page_coordination_unit_impl_unittest.cc
index 491bd0d..140d7a2 100644
--- a/services/resource_coordinator/coordination_unit/page_coordination_unit_impl_unittest.cc
+++ b/services/resource_coordinator/coordination_unit/page_coordination_unit_impl_unittest.cc
@@ -217,4 +217,36 @@
   EXPECT_EQ(0u, loading);
 }
 
+TEST_F(PageCoordinationUnitImplTest, OnAllFramesInPageFrozen) {
+  const int64_t kRunning =
+      static_cast<int64_t>(mojom::LifecycleState::kRunning);
+  const int64_t kFrozen = static_cast<int64_t>(mojom::LifecycleState::kFrozen);
+
+  MockSinglePageWithMultipleProcessesCoordinationUnitGraph cu_graph(
+      coordination_unit_graph());
+
+  EXPECT_EQ(kRunning, cu_graph.page->GetPropertyOrDefault(
+                          mojom::PropertyType::kLifecycleState, kRunning));
+
+  // 1/2 frames in the page is frozen. Expect the page to still be running.
+  cu_graph.frame->SetLifecycleState(mojom::LifecycleState::kFrozen);
+  EXPECT_EQ(kRunning, cu_graph.page->GetPropertyOrDefault(
+                          mojom::PropertyType::kLifecycleState, kRunning));
+
+  // 2/2 frames in the process are frozen. We expect the page to be frozen.
+  cu_graph.child_frame->SetLifecycleState(mojom::LifecycleState::kFrozen);
+  EXPECT_EQ(kFrozen, cu_graph.page->GetPropertyOrDefault(
+                         mojom::PropertyType::kLifecycleState, kRunning));
+
+  // Unfreeze a frame and expect the page to be running again.
+  cu_graph.frame->SetLifecycleState(mojom::LifecycleState::kRunning);
+  EXPECT_EQ(kRunning, cu_graph.page->GetPropertyOrDefault(
+                          mojom::PropertyType::kLifecycleState, kRunning));
+
+  // Refreeze that frame and expect the page to be frozen again.
+  cu_graph.frame->SetLifecycleState(mojom::LifecycleState::kFrozen);
+  EXPECT_EQ(kFrozen, cu_graph.page->GetPropertyOrDefault(
+                         mojom::PropertyType::kLifecycleState, kRunning));
+}
+
 }  // namespace resource_coordinator
diff --git a/services/resource_coordinator/public/mojom/coordination_unit.mojom b/services/resource_coordinator/public/mojom/coordination_unit.mojom
index 73e1ca0..e43d364 100644
--- a/services/resource_coordinator/public/mojom/coordination_unit.mojom
+++ b/services/resource_coordinator/public/mojom/coordination_unit.mojom
@@ -63,6 +63,7 @@
   SetAudibility(bool audible);
   SetNetworkAlmostIdle(bool idle);
   SetLifecycleState(LifecycleState state);
+  SetHasNonEmptyBeforeUnload(bool has_nonempty_beforeunload);
 
   // Event signals.
   OnAlertFired();
diff --git a/services/ws/event_test_utils.cc b/services/ws/event_test_utils.cc
index 7d317356..05c1300 100644
--- a/services/ws/event_test_utils.cc
+++ b/services/ws/event_test_utils.cc
@@ -6,6 +6,7 @@
 
 #include "ui/events/event.h"
 #include "ui/events/event_constants.h"
+#include "ui/events/event_utils.h"
 #include "ui/gfx/geometry/point.h"
 
 namespace ws {
@@ -44,7 +45,7 @@
     default:
       break;
   }
-  return "<unexpected-type>";
+  return std::string(EventTypeName(event->type()));
 }
 
 std::string LocatedEventToEventTypeAndLocation(const ui::Event* event) {
diff --git a/services/ws/window_tree.cc b/services/ws/window_tree.cc
index 339a76e9..bcf62ca 100644
--- a/services/ws/window_tree.cc
+++ b/services/ws/window_tree.cc
@@ -191,14 +191,13 @@
   for (WindowServiceObserver& observer : window_service_->observers())
     observer.OnWillSendEventToClient(client_id_, event_id);
 
+  std::unique_ptr<ui::Event> event_to_send = ui::Event::Clone(event);
   // Translate the root location for located events. Event's root location
   // should be in the coordinate of the root window, however the root for the
   // target window in the client can be different from the one in the server,
   // thus the root location needs to be converted from the original coordinate
   // to the one used in the client. See also 'WindowTreeTest.EventLocation' test
   // case.
-  std::unique_ptr<ui::Event> event_to_send =
-      PointerWatcher::CreateEventForClient(event);
   if (event.IsLocatedEvent()) {
     ClientRoot* client_root = FindClientRootContaining(window);
     // The |client_root| may have been removed on shutdown.
diff --git a/services/ws/window_tree_unittest.cc b/services/ws/window_tree_unittest.cc
index b8cad5e..4a4f943 100644
--- a/services/ws/window_tree_unittest.cc
+++ b/services/ws/window_tree_unittest.cc
@@ -579,22 +579,22 @@
 
   ui::test::EventGenerator event_generator(setup.root());
   event_generator.MoveMouseTo(50, 50);
-  EXPECT_EQ("POINTER_MOVED 40,40",
+  EXPECT_EQ("MOUSE_MOVED 40,40",
             LocatedEventToEventTypeAndLocation(
                 window_tree_client->PopInputEvent().event.get()));
 
   event_generator.PressLeftButton();
-  EXPECT_EQ("POINTER_DOWN 40,40",
+  EXPECT_EQ("MOUSE_PRESSED 40,40",
             LocatedEventToEventTypeAndLocation(
                 window_tree_client->PopInputEvent().event.get()));
 
   event_generator.MoveMouseTo(0, 0);
-  EXPECT_EQ("POINTER_MOVED -10,-10",
+  EXPECT_EQ("MOUSE_DRAGGED -10,-10",
             LocatedEventToEventTypeAndLocation(
                 window_tree_client->PopInputEvent().event.get()));
 
   event_generator.ReleaseLeftButton();
-  EXPECT_EQ("POINTER_UP -10,-10",
+  EXPECT_EQ("MOUSE_RELEASED -10,-10",
             LocatedEventToEventTypeAndLocation(
                 window_tree_client->PopInputEvent().event.get()));
 }
@@ -625,17 +625,17 @@
   ui::test::EventGenerator event_generator(setup.root());
   event_generator.set_current_location(gfx::Point(50, 51));
   event_generator.PressTouch();
-  EXPECT_EQ("POINTER_DOWN 40,40",
+  EXPECT_EQ("ET_TOUCH_PRESSED 40,40",
             LocatedEventToEventTypeAndLocation(
                 window_tree_client->PopInputEvent().event.get()));
 
   event_generator.MoveTouch(gfx::Point(5, 6));
-  EXPECT_EQ("POINTER_MOVED -5,-5",
+  EXPECT_EQ("ET_TOUCH_MOVED -5,-5",
             LocatedEventToEventTypeAndLocation(
                 window_tree_client->PopInputEvent().event.get()));
 
   event_generator.ReleaseTouch();
-  EXPECT_EQ("POINTER_UP -5,-5",
+  EXPECT_EQ("ET_TOUCH_RELEASED -5,-5",
             LocatedEventToEventTypeAndLocation(
                 window_tree_client->PopInputEvent().event.get()));
 }
@@ -689,7 +689,7 @@
 
   ui::test::EventGenerator event_generator(setup.root());
   event_generator.MoveMouseTo(50, 50);
-  EXPECT_EQ("POINTER_MOVED 40,40",
+  EXPECT_EQ("MOUSE_MOVED 40,40",
             LocatedEventToEventTypeAndLocation(
                 window_tree_client->PopInputEvent().event.get()));
 
@@ -702,7 +702,7 @@
   // Move the mouse over the non-client area.
   // The event is still sent to the client, and the delegate.
   event_generator.MoveMouseTo(15, 16);
-  EXPECT_EQ("POINTER_MOVED 5,6",
+  EXPECT_EQ("MOUSE_MOVED 5,6",
             LocatedEventToEventTypeAndLocation(
                 window_tree_client->PopInputEvent().event.get()));
 
@@ -732,7 +732,7 @@
             EventToEventType(window_delegate.PopEvent().get()));
 
   event_generator.MoveMouseTo(26, 50);
-  EXPECT_EQ("POINTER_MOVED 16,40",
+  EXPECT_EQ("MOUSE_MOVED 16,40",
             LocatedEventToEventTypeAndLocation(
                 window_tree_client->PopInputEvent().event.get()));
 
@@ -742,7 +742,7 @@
 
   // Press in client area. Only the client should get the event.
   event_generator.PressLeftButton();
-  EXPECT_EQ("POINTER_DOWN 16,40",
+  EXPECT_EQ("MOUSE_PRESSED 16,40",
             LocatedEventToEventTypeAndLocation(
                 window_tree_client->PopInputEvent().event.get()));
 
@@ -775,7 +775,7 @@
   // should get the event.
   ui::test::EventGenerator event_generator(setup.root());
   event_generator.MoveMouseTo(15, 16);
-  EXPECT_EQ("POINTER_MOVED 5,6",
+  EXPECT_EQ("MOUSE_MOVED 5,6",
             LocatedEventToEventTypeAndLocation(
                 window_tree_client->PopInputEvent().event.get()));
   EXPECT_TRUE(window_tree_client->input_events().empty());
@@ -853,7 +853,7 @@
 
   // Events in the hit test insets are seen by the delegate and client.
   event_generator.MoveMouseTo(50, 80);
-  EXPECT_EQ("POINTER_MOVED 40,70",
+  EXPECT_EQ("MOUSE_MOVED 40,70",
             LocatedEventToEventTypeAndLocation(
                 window_tree_client->PopInputEvent().event.get()));
   EXPECT_EQ("MOUSE_ENTERED 40,70", LocatedEventToEventTypeAndLocation(
@@ -931,7 +931,7 @@
   TestWindowTreeClient::InputEvent press_input =
       window_tree_client->PopInputEvent();
   ASSERT_TRUE(press_input.event);
-  EXPECT_EQ("POINTER_DOWN 40,40",
+  EXPECT_EQ("MOUSE_PRESSED 40,40",
             LocatedEventToEventTypeAndLocation(press_input.event.get()));
   EXPECT_TRUE(press_input.matches_pointer_watcher);
   // Because the event matches a pointer event there should be no observed
@@ -1007,7 +1007,7 @@
   event_generator.MoveMouseTo(8, 8);
   // Now the event should go to the client and not local.
   EXPECT_TRUE(window_delegate.events().empty());
-  EXPECT_EQ("POINTER_MOVED",
+  EXPECT_EQ("MOUSE_MOVED",
             EventToEventType(
                 setup.window_tree_client()->PopInputEvent().event.get()));
   EXPECT_TRUE(setup.window_tree_client()->input_events().empty());
@@ -1043,7 +1043,7 @@
   EXPECT_TRUE(setup.window_tree_client()->input_events().empty());
   EXPECT_TRUE(window_delegate.events().empty());
   EXPECT_EQ(
-      "POINTER_MOVED",
+      "MOUSE_MOVED",
       EventToEventType(
           embedding_helper->window_tree_client.PopInputEvent().event.get()));
   EXPECT_TRUE(embedding_helper->window_tree_client.input_events().empty());
@@ -1051,7 +1051,7 @@
   // Set capture from the parent, only the parent should get the event now.
   EXPECT_TRUE(setup.window_tree_test_helper()->SetCapture(top_level));
   event_generator.MoveMouseTo(8, 8);
-  EXPECT_EQ("POINTER_MOVED",
+  EXPECT_EQ("MOUSE_MOVED",
             EventToEventType(
                 setup.window_tree_client()->PopInputEvent().event.get()));
   EXPECT_TRUE(setup.window_tree_client()->input_events().empty());
@@ -1177,7 +1177,7 @@
   auto drag_event = setup.window_tree_client()->PopInputEvent();
   EXPECT_EQ(setup.window_tree_test_helper()->TransportIdForWindow(window),
             drag_event.window_id);
-  EXPECT_EQ("POINTER_MOVED -4,-4",
+  EXPECT_EQ("MOUSE_DRAGGED -4,-4",
             LocatedEventToEventTypeAndLocation(drag_event.event.get()));
 }
 
@@ -2042,10 +2042,10 @@
   // never be forwarded to the client, as it's assumed the client runs its own
   // gesture recognizer.
   event_generator.GestureTapAt(gfx::Point(10, 10));
-  EXPECT_EQ("POINTER_DOWN",
+  EXPECT_EQ("ET_TOUCH_PRESSED",
             EventToEventType(
                 setup.window_tree_client()->PopInputEvent().event.get()));
-  EXPECT_EQ("POINTER_UP",
+  EXPECT_EQ("ET_TOUCH_RELEASED",
             EventToEventType(
                 setup.window_tree_client()->PopInputEvent().event.get()));
   EXPECT_TRUE(setup.window_tree_client()->input_events().empty());
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index d9dbb36..9a74758 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -78,6 +78,19 @@
         "test": "cc_unittests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1",
+              "os": "Ubuntu-14.04",
+              "pool": "Chrome-CrOS-VM"
+            }
+          ]
+        },
+        "test": "chrome_all_tast_tests"
+      },
+      {
         "args": [
           "--dbus-stub",
           "--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.chromeos_unittests.filter"
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index c1266ab2..5004d85 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -3099,21 +3099,6 @@
           "hard_timeout": 3600,
           "io_timeout": 3600
         },
-        "test": "chrome_all_tast_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "kvm": "1",
-              "os": "Ubuntu-14.04",
-              "pool": "Chrome-CrOS-VM"
-            }
-          ],
-          "hard_timeout": 3600,
-          "io_timeout": 3600
-        },
         "test": "chrome_login_tast_tests"
       },
       {
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 7686218c..3c4b6397 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -371,6 +371,7 @@
         ],
       },
       'cc_unittests': {},
+      'chrome_all_tast_tests': {},
       'chromeos_unittests': {
         'args': [
           # TODO(crbug.com/865693): Don't stub out dbus clients.
@@ -425,7 +426,6 @@
 
     'chromeos_gtests_experimental': {
       'base_unittests': {},
-      'chrome_all_tast_tests': {},
       'chrome_login_tast_tests': {},
       'chromeos_unittests': {
         'args': [
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index bcec7a0f..944357d 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2802,6 +2802,24 @@
             ]
         }
     ],
+    "NupPrinting": [
+        {
+            "platforms": [
+                "chromeos",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "NupPrinting"
+                    ]
+                }
+            ]
+        }
+    ],
     "OfferUploadCreditCards": [
         {
             "platforms": [
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index 0594882..be73206 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -86,8 +86,6 @@
 crbug.com/591099 external/wpt/css/css-text/white-space/pre-wrap-002.html [ Pass ]
 crbug.com/40634 external/wpt/css/css-text/white-space/trailing-space-before-br-001.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-text/word-break/word-break-break-all-004.html [ Pass ]
-crbug.com/591099 external/wpt/css/css-transforms/transform-transformed-tr-percent-height-child.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-transitions/AnimationEffect-getComputedTiming.tentative.html [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-transitions/properties-value-003.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-transitions/properties-value-implicit-001.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-ui/text-overflow-010.html [ Pass ]
@@ -236,16 +234,11 @@
 crbug.com/591099 external/wpt/fetch/api/redirect/redirect-count.any.worker.html [ Pass ]
 crbug.com/591099 external/wpt/fetch/api/request/request-keepalive-quota.html?include=slow-2 [ Pass ]
 crbug.com/591099 external/wpt/fetch/http-cache/basic-auth-cache-test.html [ Timeout ]
-crbug.com/591099 external/wpt/html-media-capture/capture_audio_cancel-manual.html [ Failure ]
-crbug.com/591099 external/wpt/html-media-capture/capture_image_cancel-manual.html [ Failure ]
-crbug.com/591099 external/wpt/html-media-capture/capture_video_cancel-manual.html [ Failure ]
 crbug.com/591099 external/wpt/html/browsers/history/joint-session-history/joint-session-history-remove-iframe.html [ Timeout ]
 crbug.com/591099 external/wpt/html/browsers/the-window-object/window-open-noopener.html?_parent [ Timeout ]
 crbug.com/591099 external/wpt/html/browsers/the-window-object/window-open-noopener.html?_self [ Timeout ]
 crbug.com/591099 external/wpt/html/interaction/focus/sequential-focus-navigation-and-the-tabindex-attribute/focus-tabindex-positive.html [ Timeout ]
-crbug.com/591099 external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-vertical.html [ Failure ]
-crbug.com/591099 external/wpt/html/rendering/non-replaced-elements/the-hr-element-0/color.html [ Failure ]
-crbug.com/591099 external/wpt/html/rendering/non-replaced-elements/the-page/body-margin-2j.html [ Failure ]
+crbug.com/850504 external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-vertical.html [ Failure ]
 crbug.com/591099 external/wpt/html/semantics/embedded-content/media-elements/interfaces/TextTrack/addCue.html [ Pass ]
 crbug.com/591099 external/wpt/html/semantics/embedded-content/media-elements/interfaces/TextTrack/removeCue.html [ Pass ]
 crbug.com/591099 external/wpt/html/semantics/embedded-content/media-elements/interfaces/TextTrackCue/endTime.html [ Pass ]
@@ -254,82 +247,14 @@
 crbug.com/591099 external/wpt/html/semantics/embedded-content/media-elements/interfaces/TextTrackCue/startTime.html [ Pass ]
 crbug.com/591099 external/wpt/html/semantics/embedded-content/media-elements/interfaces/TextTrackCue/track.html [ Pass ]
 crbug.com/591099 external/wpt/html/semantics/embedded-content/media-elements/track/track-element/cloneNode.html [ Pass ]
-crbug.com/591099 external/wpt/html/semantics/embedded-content/the-embed-element/embed-represent-nothing-02.html [ Failure ]
-crbug.com/591099 external/wpt/html/semantics/grouping-content/the-li-element/grouping-li-reftest-list-owner-menu.html [ Failure ]
 crbug.com/591099 external/wpt/html/semantics/scripting-1/the-script-element/async_010.htm [ Pass ]
-crbug.com/591099 external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-module.html [ Failure ]
-crbug.com/591099 external/wpt/html/user-activation/activation-api-iframe.tenative.html [ Failure ]
-crbug.com/591099 external/wpt/infrastructure/reftest/reftest_ref_timeout.html [ Timeout ]
-crbug.com/591099 external/wpt/media-source/mediasource-avtracks.html [ Failure ]
-crbug.com/591099 external/wpt/media-source/mediasource-config-change-mp4-av-audio-bitrate.html [ Failure ]
-crbug.com/591099 external/wpt/media-source/mediasource-config-change-mp4-av-video-bitrate.html [ Failure ]
-crbug.com/591099 external/wpt/media-source/mediasource-config-change-mp4-v-bitrate.html [ Failure ]
-crbug.com/591099 external/wpt/offscreen-canvas/convert-to-blob/offscreencanvas.convert.to.blob.html [ Pass ]
-crbug.com/591099 external/wpt/performance-timeline/po-observe.html [ Timeout ]
 crbug.com/591099 external/wpt/picture-in-picture/request-picture-in-picture-twice.html [ Pass ]
-crbug.com/591099 external/wpt/pointerevents/pointerevent_click_during_capture-manual.html [ Crash Timeout ]
 crbug.com/591099 external/wpt/quirks/line-height-calculation.html [ Failure ]
 crbug.com/591099 external/wpt/requestidlecallback/callback-iframe.html [ Pass ]
-crbug.com/591099 external/wpt/requestidlecallback/callback-timeout-when-busy.html [ Timeout ]
-crbug.com/591099 external/wpt/requestidlecallback/callback-timeout.html [ Timeout ]
-crbug.com/591099 external/wpt/service-workers/service-worker/navigation-preload/broken-chunked-encoding.https.html [ Failure ]
-crbug.com/591099 external/wpt/speech-api/SpeechSynthesis-speak-twice.html [ Timeout ]
-crbug.com/591099 external/wpt/svg/painting/reftests/paint-context-001.svg [ Failure ]
-crbug.com/591099 external/wpt/svg/painting/reftests/paint-context-002.svg [ Failure ]
-crbug.com/591099 external/wpt/svg/path/bearing/zero.svg [ Failure ]
 crbug.com/591099 external/wpt/webrtc/RTCDTMFSender-ontonechange.https.html [ Pass ]
 crbug.com/591099 external/wpt/webrtc/RTCPeerConnection-setLocalDescription-answer.html [ Pass ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/2_cues_overlapping_partially_move_down.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/2_tracks.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/align_start.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/bidi/u05D0_first.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/evil/9_cues_overlapping_completely.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/evil/single_quote.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/evil/size_99.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/line_50_percent.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/line_integer_and_percent_mixed_overlap.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/navigate_cue_position.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/one_line_cue_plus_wrapped_cue.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/repaint.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue/color_hsla.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue/white-space_pre-wrap_wrapped.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/background_box.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/background_shorthand.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/bold_object/bold_animation_with_timestamp.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/bold_object/bold_background_properties.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/bold_object/bold_background_shorthand.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/bold_object/bold_font_properties.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/bold_object/bold_font_shorthand.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/bold_object/bold_white-space_normal_wrapped.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/bold_object/bold_white-space_pre-wrap_wrapped.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/class_object/class_outline_shorthand.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/color_rgba.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/id_color.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/italic_object/italic_background_properties.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/italic_object/italic_background_shorthand.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/italic_object/italic_font_shorthand.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/italic_object/italic_white-space_normal_wrapped.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/italic_object/italic_white-space_pre-line_wrapped.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/italic_object/italic_white-space_pre-wrap_wrapped.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/italic_object/italic_white-space_pre_wrapped.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/not_allowed_properties.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/not_root_selector.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/outline_properties.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/root_namespace.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/text-decoration_overline.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/text-shadow.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/underline_object/underline_font_properties.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/underline_object/underline_font_shorthand.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/voice_object/voice_font_properties.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/voice_object/voice_outline_properties.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/voice_object/voice_outline_shorthand.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/voice_object/voice_white-space_normal_wrapped.html [ Failure ]
 crbug.com/591099 external/wpt/workers/Worker_ErrorEvent_error.htm [ Pass ]
-crbug.com/591099 external/wpt/workers/Worker_terminate_event_queue.htm [ Timeout ]
 crbug.com/591099 external/wpt/workers/baseurl/alpha/worker-in-worker.html [ Pass ]
-crbug.com/591099 external/wpt/workers/constructors/Worker/same-origin.html [ Timeout ]
-crbug.com/591099 external/wpt/workers/semantics/interface-objects/004.html [ Failure ]
-crbug.com/591099 external/wpt/xhr/send-authentication-prompt-2-manual.htm [ Failure ]
 crbug.com/591099 external/wpt/xhr/send-content-type-string.htm [ Pass ]
 crbug.com/591099 external/wpt/xhr/send-entity-body-document.htm [ Pass ]
 crbug.com/591099 fast/backgrounds/quirks-mode-line-box-backgrounds.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index a3931d2..be1388b 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -4707,9 +4707,9 @@
 
 # Sheriff 2018-03-29
 crbug.com/827088 bluetooth/requestDevice/chooser/new-scan-device-added.html [ Pass Crash ]
-crbug.com/827209 [ Win Linux ] fast/events/middleClickAutoscroll-latching.html [ Pass Failure ]
-crbug.com/827209 [ Win Linux ] virtual/mouseevent_fractional/fast/events/middleClickAutoscroll-latching.html [ Pass Failure ]
-crbug.com/827209 [ Win Linux ] virtual/user-activation-v2/fast/events/middleClickAutoscroll-latching.html [ Pass Failure ]
+crbug.com/827209 [ Win Linux ] fast/events/middleClickAutoscroll-latching.html [ Pass Timeout Failure ]
+crbug.com/827209 [ Win Linux ] virtual/mouseevent_fractional/fast/events/middleClickAutoscroll-latching.html [ Pass Timeout Failure ]
+crbug.com/827209 [ Win Linux ] virtual/user-activation-v2/fast/events/middleClickAutoscroll-latching.html [ Pass Timeout Failure ]
 
 # Utility for manual testing, not intended to be run as part of layout tests.
 crbug.com/785955 http/tests/credentialmanager/tools/virtual-authenticator-environment-manual.html [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/color-space/canvas-colorManaged-convertToBlob-roundtrip.html b/third_party/WebKit/LayoutTests/fast/canvas/color-space/canvas-colorManaged-convertToBlob-roundtrip.html
index bf859c9..1a9c4c8 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/color-space/canvas-colorManaged-convertToBlob-roundtrip.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/color-space/canvas-colorManaged-convertToBlob-roundtrip.html
@@ -13,18 +13,17 @@
 
 function testPixels(actualPixels, refPixels, testScenario)
 {
-    // Plain testing requires a tolerance as high as 26 for 8-8-8-8, which does
-    // not leave that much to test. Instead, we narrow down the source of
-    // expected error.
-    // - Alpha values should always match.
-    // - Color components should be acceptably close, except for the red
-    //   channel of the green pixel. Green has the largest change in what's
-    //   representable between sRGB and P3/2020.
-    //   Red channel of the green pixel is R channel of the second pixel.
-
     if (testScenario.canvasColorParam.pixelFormat == '8-8-8-8') {
-        let tolerance_color = 10;
-        let tolerance_r_green = 26;
+        // Narrowing down the source of expected error:
+        // - Alpha values should always match.
+        // - Color components should be acceptably close. All tests locally pass
+        //   with a tolerance of 4.
+        // - The red channel of the green pixel has the largest error since green
+        //   has the largest change in what's representable between sRGB and
+        //   P3/2020. Red channel of the green pixel is R channel of the second
+        //   pixel. All tests locally pass with a tolerance of 8.
+        let tolerance_color = 4;
+        let tolerance_r_green = 8;
         for (let i = 0; i < actualPixels.length; i++) {
             // Alpha channel
             if (i % 4 == 3)
@@ -36,7 +35,8 @@
                 assert_approx_equals(actualPixels[i], refPixels[i], tolerance_color);
         }
     } else {
-        let tolerance_color = 0.02;
+        // For half float backed canvas, we expect the error < 0.01.
+        let tolerance_color = 0.01;
         for (let i = 0; i < actualPixels.length; i++) {
             // Alpha channel
             if (i % 4 == 3)
@@ -118,8 +118,7 @@
 
     var mimeTypes = ['image/png', 'image/jpeg', 'image/webp'];
     var blobColorSpaces = ['srgb', 'rec2020', 'display-p3'];
-    // uint16 pixel format is not supported yet. crbug.com/840372.
-    var blobPixelFormats = ['8-8-8-8'];
+    var blobPixelFormats = ['8-8-8-8', 'uint16'];
 
     var encodeOptionsSet = [];
     for (var i = 0; i < mimeTypes.length; i++)
@@ -140,9 +139,7 @@
         {colorSpace: 'srgb', pixelFormat: 'float16'},
         {colorSpace: 'rec2020', pixelFormat: 'float16'},
         {colorSpace: 'p3', pixelFormat: 'float16'}];
-    // crbug.com/859102
-    // var alphaValues = [0.5, 1];
-    var alphaValues = [1];
+    var alphaValues = [0.5, 1];
 
     // The *correct* way to test convertToBlob() is to directly examine the
     // image file for the expected color space and pixels. Since this is not
diff --git a/third_party/WebKit/LayoutTests/fast/events/middleClickAutoscroll-latching.html b/third_party/WebKit/LayoutTests/fast/events/middleClickAutoscroll-latching.html
index 20739a2..62c525f 100644
--- a/third_party/WebKit/LayoutTests/fast/events/middleClickAutoscroll-latching.html
+++ b/third_party/WebKit/LayoutTests/fast/events/middleClickAutoscroll-latching.html
@@ -17,6 +17,8 @@
 <script>
 setAnimationRequiresRaster();
 var testBubble = async_test("Tests that middleClickAutoscroll finds the correct ancestor layoutobject when starting in an unscrollable direction.")
+var testIFrame = async_test("Tests that middleClickAutoscroll finds the correct ancestor layoutobject when starting in an iframe, and the latching is correctly implemented.")
+
 testBubble.step(function() {
   if (!window.eventSender)
     return;
@@ -47,16 +49,11 @@
         assert_equals(div.scrollLeft, 0);
         eventSender.mouseUp(1);
         testBubble.done();
-        // TODO(crbug.com/888571): This call to testIFrame doesn't get hit after
-        // testBubble.done() gets called.
-        testIFrame();
       }
     }
   };
 });
 
-function testIFrame() {
-var testIFrame = async_test("Tests that middleClickAutoscroll finds the correct ancestor layoutobject when starting in an iframe, and the latching is correctly implemented.")
 testIFrame.step(function() {
   if (!window.eventSender)
     return;
@@ -79,5 +76,4 @@
     testIFrame.done();
   };
 });
-}
 </script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/loading/307-after-303-after-post-expected.txt b/third_party/WebKit/LayoutTests/http/tests/loading/307-after-303-after-post-expected.txt
index 639c53a..7b513fe 100644
--- a/third_party/WebKit/LayoutTests/http/tests/loading/307-after-303-after-post-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/loading/307-after-303-after-post-expected.txt
@@ -4,8 +4,8 @@
 main frame - didFinishDocumentLoadForFrame
 main frame - didHandleOnloadEventsForFrame
 main frame - didFinishLoadForFrame
-main frame - didStartProvisionalLoadForFrame
 http://127.0.0.1:8000/loading/resources/post-to-303-target.php - willSendRequest <NSURLRequest URL http://127.0.0.1:8000/loading/resources/post-to-303-target.php, main document URL http://127.0.0.1:8000/loading/resources/post-to-303-target.php, http method POST>
+main frame - didStartProvisionalLoadForFrame
 http://127.0.0.1:8000/loading/resources/303-to-307-target.php - willSendRequest <NSURLRequest URL http://127.0.0.1:8000/loading/resources/303-to-307-target.php, main document URL http://127.0.0.1:8000/loading/resources/303-to-307-target.php, http method GET>
 http://127.0.0.1:8000/loading/resources/307-post-output-target.php - willSendRequest <NSURLRequest URL http://127.0.0.1:8000/loading/resources/307-post-output-target.php, main document URL http://127.0.0.1:8000/loading/resources/307-post-output-target.php, http method GET>
 http://127.0.0.1:8000/loading/resources/307-post-output-target.php - didReceiveResponse <NSURLResponse http://127.0.0.1:8000/loading/resources/307-post-output-target.php, http status code 200>
diff --git a/third_party/WebKit/LayoutTests/http/tests/loading/bad-server-subframe-expected.txt b/third_party/WebKit/LayoutTests/http/tests/loading/bad-server-subframe-expected.txt
index 1653bc1..ac8966b2 100644
--- a/third_party/WebKit/LayoutTests/http/tests/loading/bad-server-subframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/loading/bad-server-subframe-expected.txt
@@ -4,6 +4,7 @@
 frame "f1" - didStartProvisionalLoadForFrame
 main frame - didReceiveTitle: 
 main frame - didFinishDocumentLoadForFrame
+frame "f1" - didFailProvisionalLoadWithError
 frame "f1" - didStartProvisionalLoadForFrame
 frame "f1" - didCommitLoadForFrame
 frame "f1" - didReceiveTitle: Error
diff --git a/third_party/WebKit/LayoutTests/http/tests/loading/redirect-methods-expected.txt b/third_party/WebKit/LayoutTests/http/tests/loading/redirect-methods-expected.txt
index da998e2..1dfb926 100644
--- a/third_party/WebKit/LayoutTests/http/tests/loading/redirect-methods-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/loading/redirect-methods-expected.txt
@@ -11,16 +11,16 @@
 frame "0" - didFinishDocumentLoadForFrame
 frame "0" - didHandleOnloadEventsForFrame
 frame "0" - didFinishLoadForFrame
-frame "0" - didStartProvisionalLoadForFrame
 http://127.0.0.1:8000/loading/resources/redirect-methods-form.html - willSendRequest <NSURLRequest URL http://127.0.0.1:8000/loading/resources/redirect-methods-form.html, main document URL http://127.0.0.1:8000/loading/redirect-methods.html, http method GET>
+frame "0" - didStartProvisionalLoadForFrame
 http://127.0.0.1:8000/loading/resources/redirect-methods-form.html - didReceiveResponse <NSURLResponse http://127.0.0.1:8000/loading/resources/redirect-methods-form.html, http status code 200>
 frame "0" - didCommitLoadForFrame
 frame "0" - didReceiveTitle: 
 frame "0" - didFinishDocumentLoadForFrame
 frame "0" - didHandleOnloadEventsForFrame
 frame "0" - didFinishLoadForFrame
-frame "0" - didStartProvisionalLoadForFrame
 http://127.0.0.1:8000/loading/resources/redirect-methods-result.php - willSendRequest <NSURLRequest URL http://127.0.0.1:8000/loading/resources/redirect-methods-result.php, main document URL http://127.0.0.1:8000/loading/redirect-methods.html, http method POST>
+frame "0" - didStartProvisionalLoadForFrame
 http://127.0.0.1:8000/loading/resources/redirect-methods-result.php?redirected=true - willSendRequest <NSURLRequest URL http://127.0.0.1:8000/loading/resources/redirect-methods-result.php?redirected=true, main document URL http://127.0.0.1:8000/loading/redirect-methods.html, http method GET>
 http://127.0.0.1:8000/loading/resources/redirect-methods-result.php?redirected=true - didReceiveResponse <NSURLResponse http://127.0.0.1:8000/loading/resources/redirect-methods-result.php?redirected=true, http status code 200>
 frame "0" - didCommitLoadForFrame
@@ -35,16 +35,16 @@
 frame "1" - didFinishLoadForFrame
 frame "0" - didHandleOnloadEventsForFrame
 frame "0" - didFinishLoadForFrame
-frame "1" - didStartProvisionalLoadForFrame
 http://127.0.0.1:8000/loading/resources/redirect-methods-form.html - willSendRequest <NSURLRequest URL http://127.0.0.1:8000/loading/resources/redirect-methods-form.html, main document URL http://127.0.0.1:8000/loading/redirect-methods.html, http method GET>
+frame "1" - didStartProvisionalLoadForFrame
 http://127.0.0.1:8000/loading/resources/redirect-methods-form.html - didReceiveResponse <NSURLResponse http://127.0.0.1:8000/loading/resources/redirect-methods-form.html, http status code 200>
 frame "1" - didCommitLoadForFrame
 frame "1" - didReceiveTitle: 
 frame "1" - didFinishDocumentLoadForFrame
 frame "1" - didHandleOnloadEventsForFrame
 frame "1" - didFinishLoadForFrame
-frame "1" - didStartProvisionalLoadForFrame
 http://127.0.0.1:8000/loading/resources/redirect-methods-result.php - willSendRequest <NSURLRequest URL http://127.0.0.1:8000/loading/resources/redirect-methods-result.php, main document URL http://127.0.0.1:8000/loading/redirect-methods.html, http method POST>
+frame "1" - didStartProvisionalLoadForFrame
 http://127.0.0.1:8000/loading/resources/redirect-methods-result.php?redirected=true - willSendRequest <NSURLRequest URL http://127.0.0.1:8000/loading/resources/redirect-methods-result.php?redirected=true, main document URL http://127.0.0.1:8000/loading/redirect-methods.html, http method GET>
 http://127.0.0.1:8000/loading/resources/redirect-methods-result.php?redirected=true - didReceiveResponse <NSURLResponse http://127.0.0.1:8000/loading/resources/redirect-methods-result.php?redirected=true, http status code 200>
 frame "1" - didCommitLoadForFrame
@@ -59,16 +59,16 @@
 frame "2" - didFinishLoadForFrame
 frame "1" - didHandleOnloadEventsForFrame
 frame "1" - didFinishLoadForFrame
-frame "2" - didStartProvisionalLoadForFrame
 http://127.0.0.1:8000/loading/resources/redirect-methods-form.html - willSendRequest <NSURLRequest URL http://127.0.0.1:8000/loading/resources/redirect-methods-form.html, main document URL http://127.0.0.1:8000/loading/redirect-methods.html, http method GET>
+frame "2" - didStartProvisionalLoadForFrame
 http://127.0.0.1:8000/loading/resources/redirect-methods-form.html - didReceiveResponse <NSURLResponse http://127.0.0.1:8000/loading/resources/redirect-methods-form.html, http status code 200>
 frame "2" - didCommitLoadForFrame
 frame "2" - didReceiveTitle: 
 frame "2" - didFinishDocumentLoadForFrame
 frame "2" - didHandleOnloadEventsForFrame
 frame "2" - didFinishLoadForFrame
-frame "2" - didStartProvisionalLoadForFrame
 http://127.0.0.1:8000/loading/resources/redirect-methods-result.php - willSendRequest <NSURLRequest URL http://127.0.0.1:8000/loading/resources/redirect-methods-result.php, main document URL http://127.0.0.1:8000/loading/redirect-methods.html, http method POST>
+frame "2" - didStartProvisionalLoadForFrame
 http://127.0.0.1:8000/loading/resources/redirect-methods-result.php?redirected=true - willSendRequest <NSURLRequest URL http://127.0.0.1:8000/loading/resources/redirect-methods-result.php?redirected=true, main document URL http://127.0.0.1:8000/loading/redirect-methods.html, http method GET>
 http://127.0.0.1:8000/loading/resources/redirect-methods-result.php?redirected=true - didReceiveResponse <NSURLResponse http://127.0.0.1:8000/loading/resources/redirect-methods-result.php?redirected=true, http status code 200>
 frame "2" - didCommitLoadForFrame
@@ -83,16 +83,16 @@
 frame "3" - didFinishLoadForFrame
 frame "2" - didHandleOnloadEventsForFrame
 frame "2" - didFinishLoadForFrame
-frame "3" - didStartProvisionalLoadForFrame
 http://127.0.0.1:8000/loading/resources/redirect-methods-form.html - willSendRequest <NSURLRequest URL http://127.0.0.1:8000/loading/resources/redirect-methods-form.html, main document URL http://127.0.0.1:8000/loading/redirect-methods.html, http method GET>
+frame "3" - didStartProvisionalLoadForFrame
 http://127.0.0.1:8000/loading/resources/redirect-methods-form.html - didReceiveResponse <NSURLResponse http://127.0.0.1:8000/loading/resources/redirect-methods-form.html, http status code 200>
 frame "3" - didCommitLoadForFrame
 frame "3" - didReceiveTitle: 
 frame "3" - didFinishDocumentLoadForFrame
 frame "3" - didHandleOnloadEventsForFrame
 frame "3" - didFinishLoadForFrame
-frame "3" - didStartProvisionalLoadForFrame
 http://127.0.0.1:8000/loading/resources/redirect-methods-result.php - willSendRequest <NSURLRequest URL http://127.0.0.1:8000/loading/resources/redirect-methods-result.php, main document URL http://127.0.0.1:8000/loading/redirect-methods.html, http method POST>
+frame "3" - didStartProvisionalLoadForFrame
 http://127.0.0.1:8000/loading/resources/redirect-methods-result.php?redirected=true - willSendRequest <NSURLRequest URL http://127.0.0.1:8000/loading/resources/redirect-methods-result.php?redirected=true, main document URL http://127.0.0.1:8000/loading/redirect-methods.html, http method POST>
 http://127.0.0.1:8000/loading/resources/redirect-methods-result.php?redirected=true - didReceiveResponse <NSURLResponse http://127.0.0.1:8000/loading/resources/redirect-methods-result.php?redirected=true, http status code 200>
 frame "3" - didCommitLoadForFrame
diff --git a/third_party/WebKit/LayoutTests/http/tests/navigation/resources/testcode.js b/third_party/WebKit/LayoutTests/http/tests/navigation/resources/testcode.js
index d6ac2ff..b0430e20 100644
--- a/third_party/WebKit/LayoutTests/http/tests/navigation/resources/testcode.js
+++ b/third_party/WebKit/LayoutTests/http/tests/navigation/resources/testcode.js
@@ -73,7 +73,7 @@
             testRunner.queueNonLoadingScript("fillTestForm()");
             testRunner.queueLoadingScript("submitFormWithPostRedirect()");
         } else if (extraStep == "relativeanchor") {
-            testRunner.queueNonLoadingScript("jumpToAnchor()");
+            testRunner.queueLoadingScript("jumpToAnchor()");
         }
     }
 }
@@ -100,7 +100,7 @@
         } else if (extraStep == "postredirect") {
             testRunner.queueLoadingScript("submitFormWithPostRedirect()");
         } else if (extraStep == "relativeanchor") {
-            testRunner.queueNonLoadingScript("jumpToAnchor()");
+            testRunner.queueLoadingScript("jumpToAnchor()");
         }
         testRunner.queueLoad("resources/otherpage.html");
         testRunner.queueBackNavigation(howFarBack);
diff --git a/third_party/WebKit/LayoutTests/resources/gesture-util.js b/third_party/WebKit/LayoutTests/resources/gesture-util.js
index 26704b84..8bedc14 100644
--- a/third_party/WebKit/LayoutTests/resources/gesture-util.js
+++ b/third_party/WebKit/LayoutTests/resources/gesture-util.js
@@ -90,7 +90,8 @@
 // TODO(bokan): This isn't really instant but high enough that it works for
 // current purposes. This should be replaced with the Infinity value and
 // the synthetic gesture code modified to guarantee the single update behavior.
-const SPEED_INSTANT = 200000;
+// https://crbug.com/893608
+const SPEED_INSTANT = 400000;
 
 function smoothScroll(pixels_to_scroll, start_x, start_y, gesture_source_type, direction, speed_in_pixels_s, precise_scrolling_deltas, scroll_by_page, cursor_visible) {
   return new Promise((resolve, reject) => {
diff --git a/third_party/blink/perf_tests/bindings/resources/worker-structured-clone-perf-test.js b/third_party/blink/perf_tests/bindings/resources/worker-structured-clone-perf-test.js
index 91af53d..df82a501 100644
--- a/third_party/blink/perf_tests/bindings/resources/worker-structured-clone-perf-test.js
+++ b/third_party/blink/perf_tests/bindings/resources/worker-structured-clone-perf-test.js
@@ -1,24 +1,23 @@
 const WorkerStructuredClonePerfTestRunner = (function() {
   function pingPong(data) {
     return new Promise((resolve, reject) => {
-      let beginSerialize, endSerialize, beginDeserialize, endDeserialize;
+      let mainThreadBeginSerialize, mainThreadEndDeserialize, toWorkerTime, fromWorkerTime, totalTime;
       worker.addEventListener('message', function listener(e) {
         try {
           e.data;  // Force deserialization.
-          endDeserialize = PerfTestRunner.now();
+          mainThreadEndDeserialize = performance.now();
           worker.removeEventListener('message', listener);
-          // TODO(panicker): Deserialize is currently including worker hop and
-          // not accurate. Report this from the worker.
-          resolve([endSerialize - beginSerialize, endDeserialize - beginDeserialize,
-                  endDeserialize - beginSerialize]);
+          // toWorkerTime: Time from main thread beginning serialize to end of worker deserialize
+          toWorkerTime = (e.data.workerDeserialize + (e.data.workerTimeOrigin - performance.timeOrigin)) - mainThreadBeginSerialize;
+          // fromWorkerTime: Time from worker beginning serialize to end of main thread deserialize
+          fromWorkerTime = mainThreadEndDeserialize - (e.data.workerDeserialize + (e.data.workerTimeOrigin - performance.timeOrigin));
+          // totalTime: Time from main thread beginning serialzie to end of main thread deserialize
+          totalTime = mainThreadEndDeserialize - mainThreadBeginSerialize
+          resolve([toWorkerTime, fromWorkerTime, totalTime]);
         } catch (err) { reject(err); }
       });
-      beginSerialize = PerfTestRunner.now();
+      mainThreadBeginSerialize = performance.now();
       worker.postMessage(data);
-      beginDeserialize = endSerialize = PerfTestRunner.now();
-      // While Chrome does the deserialize lazily when e.data is read, this
-      // isn't portable, so it's more fair to measure from when the message is
-      // posted.
     });
   }
 
@@ -36,13 +35,13 @@
       });
 
       function pingPongUntilDone() {
-        pingPong(test.data).then(([serializeTime, deserializeTime, totalTime]) => {
-          console.log([serializeTime, deserializeTime, totalTime]);
-          if (test.measure === 'serialize')
-            PerfTestRunner.measureValueAsync(serializeTime);
-          else if (test.measure === 'deserialize')
-            PerfTestRunner.measureValueAsync(deserializeTime);
-          else if (test.measure === 'roundtrip')
+        pingPong(test.data).then(([toWorkerTime, fromWorkerTime, totalTime]) => {
+          console.log([toWorkerTime, fromWorkerTime, totalTime]);
+          if (test.measure == 'toWorker')
+            PerfTestRunner.measureValueAsync(toWorkerTime);
+          else if (test.measure === 'fromWorker')
+            PerfTestRunner.measureValueAsync(fromWorkerTime);
+          else if (test.measure == 'roundtrip')
             PerfTestRunner.measureValueAsync(totalTime);
           if (!isDone) pingPongUntilDone();
         });
diff --git a/third_party/blink/perf_tests/bindings/resources/worker-structured-clone.js b/third_party/blink/perf_tests/bindings/resources/worker-structured-clone.js
index 8b23883..fa381e7 100644
--- a/third_party/blink/perf_tests/bindings/resources/worker-structured-clone.js
+++ b/third_party/blink/perf_tests/bindings/resources/worker-structured-clone.js
@@ -1,3 +1,7 @@
 self.onmessage = function(e) {
-    self.postMessage(e.data);
+  var data = e.data;  // Force deserialization
+  var workerDeserialize = performance.now();
+  self.postMessage({'recieveddData' : data,
+                    'workerTimeOrigin' : performance.timeOrigin,
+                    'workerDeserialize' : workerDeserialize});
 };
diff --git a/third_party/blink/perf_tests/bindings/worker-structured-clone-json-serialize.html b/third_party/blink/perf_tests/bindings/worker-structured-clone-json-from-worker.html
similarity index 66%
copy from third_party/blink/perf_tests/bindings/worker-structured-clone-json-serialize.html
copy to third_party/blink/perf_tests/bindings/worker-structured-clone-json-from-worker.html
index 7597623..a310804 100644
--- a/third_party/blink/perf_tests/bindings/worker-structured-clone-json-serialize.html
+++ b/third_party/blink/perf_tests/bindings/worker-structured-clone-json-from-worker.html
@@ -4,9 +4,9 @@
 <script src="resources/worker-structured-clone-perf-test.js"></script>
 <script>
 WorkerStructuredClonePerfTestRunner.measureTimeAsync({
-  description: "Measures performance of serializing JSON-like data.",
+  description: "Measures performance of sending JSON-like data from a worker back to the main thread using deserialization.",
   data: JSON.parse(PerfTestRunner.loadFile("resources/blink-dev.json")),
-    measure: "serialize",
+  measure: "fromWorker",
 });
 </script>
 </body>
diff --git a/third_party/blink/perf_tests/bindings/worker-structured-clone-json-serialize.html b/third_party/blink/perf_tests/bindings/worker-structured-clone-json-to-worker.html
similarity index 70%
rename from third_party/blink/perf_tests/bindings/worker-structured-clone-json-serialize.html
rename to third_party/blink/perf_tests/bindings/worker-structured-clone-json-to-worker.html
index 7597623..0c93161 100644
--- a/third_party/blink/perf_tests/bindings/worker-structured-clone-json-serialize.html
+++ b/third_party/blink/perf_tests/bindings/worker-structured-clone-json-to-worker.html
@@ -4,9 +4,9 @@
 <script src="resources/worker-structured-clone-perf-test.js"></script>
 <script>
 WorkerStructuredClonePerfTestRunner.measureTimeAsync({
-  description: "Measures performance of serializing JSON-like data.",
+  description: "Measures performance of sending JSON-like data to a worker with deserialization.",
   data: JSON.parse(PerfTestRunner.loadFile("resources/blink-dev.json")),
-    measure: "serialize",
+  measure: "toWorker",
 });
 </script>
 </body>
diff --git a/third_party/blink/public/web/web_local_frame_client.h b/third_party/blink/public/web/web_local_frame_client.h
index 157eb43..9ef6306 100644
--- a/third_party/blink/public/web/web_local_frame_client.h
+++ b/third_party/blink/public/web/web_local_frame_client.h
@@ -446,6 +446,7 @@
 
   // The frame's document finished loading.
   // This method may not execute JavaScript code.
+  // TODO(dgozman): rename this to DidFireDOMContentLoadedEvent.
   virtual void DidFinishDocumentLoad() {}
 
   // Like |didFinishDocumentLoad|, except this method may run JavaScript
@@ -623,9 +624,6 @@
   virtual void DidRunInsecureContent(const WebSecurityOrigin&,
                                      const WebURL& insecure_url) {}
 
-  // A reflected XSS was encountered in the page and suppressed.
-  virtual void DidDetectXSS(const WebURL&, bool did_block_entire_page) {}
-
   // A PingLoader was created, and a request dispatched to a URL.
   virtual void DidDispatchPingLoader(const WebURL&) {}
 
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.cc b/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.cc
index c0d36b3..d0f3e98 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.cc
@@ -210,6 +210,54 @@
   stats_collector->IncreaseCollectedWrapperCount(count);
 }
 
+void ScheduleFollowupGCs(ThreadState* thread_state,
+                         v8::GCCallbackFlags flags,
+                         bool is_unified) {
+  DCHECK(!thread_state->IsGCForbidden());
+  // Schedules followup garbage collections. Such garbage collections may be
+  // needed when:
+  // 1. GC is not precise because it has to scan on-stack pointers.
+  // 2. GC needs to reclaim chains persistent handles.
+
+  // v8::kGCCallbackFlagForced is used for testing GCs that need to verify
+  // that objects indeed died.
+  if (flags & v8::kGCCallbackFlagForced) {
+    if (!is_unified) {
+      thread_state->CollectGarbage(
+          BlinkGC::kHeapPointersOnStack, BlinkGC::kAtomicMarking,
+          BlinkGC::kEagerSweeping, BlinkGC::GCReason::kForcedGC);
+    }
+
+    // Forces a precise GC at the end of the current event loop.
+    thread_state->ScheduleFullGC();
+  }
+
+  // In the unified world there is little need to schedule followup garbage
+  // collections as the current GC already computed the whole transitive
+  // closure. We ignore chains of persistent handles here. Cleanup of such
+  // handle chains requires GC loops at the caller side, e.g., see thread
+  // termination.
+  if (is_unified)
+    return;
+
+  if ((flags & v8::kGCCallbackFlagCollectAllAvailableGarbage) ||
+      (flags & v8::kGCCallbackFlagCollectAllExternalMemory)) {
+    // This single GC is not enough. See the above comment.
+    thread_state->CollectGarbage(
+        BlinkGC::kHeapPointersOnStack, BlinkGC::kAtomicMarking,
+        BlinkGC::kEagerSweeping, BlinkGC::GCReason::kForcedGC);
+
+    // The conservative GC might have left floating garbage. Schedule
+    // precise GC to ensure that we collect all available garbage.
+    thread_state->SchedulePreciseGC();
+  }
+
+  // Schedules a precise GC for the next idle time period.
+  if (flags & v8::kGCCallbackScheduleIdleGarbageCollection) {
+    thread_state->ScheduleIdleGC();
+  }
+}
+
 }  // namespace
 
 void V8GCController::GcEpilogue(v8::Isolate* isolate,
@@ -254,50 +302,9 @@
 
   ThreadState* current_thread_state = ThreadState::Current();
   if (current_thread_state && !current_thread_state->IsGCForbidden()) {
-    // v8::kGCCallbackFlagForced forces a Blink heap garbage collection
-    // when a garbage collection was forced from V8. This is either used
-    // for tests that force GCs from JavaScript to verify that objects die
-    // when expected.
-    if (flags & v8::kGCCallbackFlagForced) {
-      // This single GC is not enough for two reasons:
-      //   (1) The GC is not precise because the GC scans on-stack pointers
-      //       conservatively.
-      //   (2) One GC is not enough to break a chain of persistent handles. It's
-      //       possible that some heap allocated objects own objects that
-      //       contain persistent handles pointing to other heap allocated
-      //       objects. To break the chain, we need multiple GCs.
-      //
-      // Regarding (1), we force a precise GC at the end of the current event
-      // loop. So if you want to collect all garbage, you need to wait until the
-      // next event loop.  Regarding (2), it would be OK in practice to trigger
-      // only one GC per gcEpilogue, because GCController.collectAll() forces
-      // multiple V8's GC.
-      current_thread_state->CollectGarbage(
-          BlinkGC::kHeapPointersOnStack, BlinkGC::kAtomicMarking,
-          BlinkGC::kEagerSweeping, BlinkGC::GCReason::kForcedGC);
-
-      // Forces a precise GC at the end of the current event loop.
-      current_thread_state->ScheduleFullGC();
-    }
-
-    // v8::kGCCallbackFlagCollectAllAvailableGarbage is used when V8 handles
-    // low memory notifications.
-    if ((flags & v8::kGCCallbackFlagCollectAllAvailableGarbage) ||
-        (flags & v8::kGCCallbackFlagCollectAllExternalMemory)) {
-      // This single GC is not enough. See the above comment.
-      current_thread_state->CollectGarbage(
-          BlinkGC::kHeapPointersOnStack, BlinkGC::kAtomicMarking,
-          BlinkGC::kEagerSweeping, BlinkGC::GCReason::kForcedGC);
-
-      // The conservative GC might have left floating garbage. Schedule
-      // precise GC to ensure that we collect all available garbage.
-      current_thread_state->SchedulePreciseGC();
-    }
-
-    // Schedules a precise GC for the next idle time period.
-    if (flags & v8::kGCCallbackScheduleIdleGarbageCollection) {
-      current_thread_state->ScheduleIdleGC();
-    }
+    ScheduleFollowupGCs(
+        ThreadState::Current(), flags,
+        RuntimeEnabledFeatures::HeapUnifiedGarbageCollectionEnabled());
   }
 
   TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index 3bdb102..94dfbdc 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -1876,6 +1876,7 @@
     "frame/frame_test_helpers.h",
     "frame/history_test.cc",
     "frame/local_frame_test.cc",
+    "frame/local_frame_ukm_aggregator_test.cc",
     "frame/local_frame_view_test.cc",
     "frame/mhtml_archive_test.cc",
     "frame/mhtml_loading_test.cc",
diff --git a/third_party/blink/renderer/core/DEPS b/third_party/blink/renderer/core/DEPS
index 64bb7a2..33d83b3 100644
--- a/third_party/blink/renderer/core/DEPS
+++ b/third_party/blink/renderer/core/DEPS
@@ -85,4 +85,7 @@
     "find_in_page.cc" : [
         "+third_party/blink/renderer/core/frame/web_local_frame_impl.h",
     ],
+    "local_frame_ukm_aggregator_test.cc" : [
+        "+components/ukm/test_ukm_recorder.h"
+    ],
 }
diff --git a/third_party/blink/renderer/core/animation/compositor_animations.cc b/third_party/blink/renderer/core/animation/compositor_animations.cc
index 5d4d04e7..5b5669d 100644
--- a/third_party/blink/renderer/core/animation/compositor_animations.cc
+++ b/third_party/blink/renderer/core/animation/compositor_animations.cc
@@ -235,6 +235,16 @@
           property_namespace = CompositorElementIdNamespace::kEffectFilter;
           break;
         }
+        case CSSPropertyVariable: {
+          DCHECK(RuntimeEnabledFeatures::OffMainThreadCSSPaintEnabled());
+          if (!keyframe->GetAnimatableValue()->IsDouble()) {
+            // TODO(kevers): Extend support to other custom property types.
+            return FailureCode::Actionable(
+                "Accelerated animation cannot be applied to a custom property "
+                "that is not numeric-valued");
+          }
+          break;
+        }
         default:
           // any other types are not allowed to run on compositor.
           StringBuilder builder;
@@ -644,6 +654,18 @@
         curve = std::move(transform_curve);
         break;
       }
+      case CSSPropertyVariable: {
+        DCHECK(RuntimeEnabledFeatures::OffMainThreadCSSPaintEnabled());
+        target_property = CompositorTargetProperty::CSS_CUSTOM_PROPERTY;
+        // TODO(kevers): Extend support to non-float types.
+        std::unique_ptr<CompositorFloatAnimationCurve> float_curve =
+            CompositorFloatAnimationCurve::Create();
+        AddKeyframesToCurve(*float_curve, values);
+        float_curve->SetTimingFunction(*timing.timing_function);
+        float_curve->SetScaledDuration(scale);
+        curve = std::move(float_curve);
+        break;
+      }
       default:
         NOTREACHED();
         continue;
diff --git a/third_party/blink/renderer/core/animation/compositor_animations.h b/third_party/blink/renderer/core/animation/compositor_animations.h
index 4fc55de..393ace9 100644
--- a/third_party/blink/renderer/core/animation/compositor_animations.h
+++ b/third_party/blink/renderer/core/animation/compositor_animations.h
@@ -148,15 +148,15 @@
 
   friend class AnimationCompositorAnimationsTest;
   FRIEND_TEST_ALL_PREFIXES(AnimationCompositorAnimationsTest,
-                           canStartElementOnCompositorTransformSPv2);
+                           CanStartElementOnCompositorTransformSPv2);
   FRIEND_TEST_ALL_PREFIXES(AnimationCompositorAnimationsTest,
-                           canStartElementOnCompositorEffectSPv2);
+                           CanStartElementOnCompositorEffectSPv2);
   FRIEND_TEST_ALL_PREFIXES(AnimationCompositorAnimationsTest,
-                           canStartElementOnCompositorEffect);
+                           CanStartElementOnCompositorEffect);
   FRIEND_TEST_ALL_PREFIXES(AnimationCompositorAnimationsTest,
-                           cannotStartElementOnCompositorEffectSVG);
+                           CannotStartElementOnCompositorEffectSVG);
   FRIEND_TEST_ALL_PREFIXES(AnimationCompositorAnimationsTest,
-                           cancelIncompatibleCompositorAnimations);
+                           CancelIncompatibleCompositorAnimations);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/animation/compositor_animations_test.cc b/third_party/blink/renderer/core/animation/compositor_animations_test.cc
index 3179468..7e3db37 100644
--- a/third_party/blink/renderer/core/animation/compositor_animations_test.cc
+++ b/third_party/blink/renderer/core/animation/compositor_animations_test.cc
@@ -46,7 +46,11 @@
 #include "third_party/blink/renderer/core/animation/element_animations.h"
 #include "third_party/blink/renderer/core/animation/keyframe_effect.h"
 #include "third_party/blink/renderer/core/animation/pending_animations.h"
+#include "third_party/blink/renderer/core/css/property_descriptor.h"
+#include "third_party/blink/renderer/core/css/property_registration.h"
+#include "third_party/blink/renderer/core/css/property_registry.h"
 #include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
 #include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
 #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
 #include "third_party/blink/renderer/core/layout/layout_object.h"
@@ -138,7 +142,7 @@
     // snapshot the effect to make those available.
     base::Optional<CompositorElementIdSet> none;
     // TODO(crbug.com/725385): Remove once compositor uses InterpolationTypes.
-    auto style = ComputedStyle::Create();
+    auto style = GetDocument().EnsureStyleResolver().StyleForElement(element_);
     effect.SnapshotAllCompositorKeyframesIfNecessary(*element_.Get(), *style,
                                                      nullptr);
     return CheckCanStartEffectOnCompositor(timing, *element_.Get(), nullptr,
@@ -210,6 +214,20 @@
     return keyframe;
   }
 
+  StringKeyframe* CreateReplaceOpKeyframe(const String& property_name,
+                                          const String& value,
+                                          double offset = 0) {
+    StringKeyframe* keyframe = StringKeyframe::Create();
+    keyframe->SetCSSPropertyValue(AtomicString(property_name),
+                                  GetDocument().GetPropertyRegistry(), value,
+                                  GetDocument().GetSecureContextMode(),
+                                  GetDocument().ElementSheet().Contents());
+    keyframe->SetComposite(EffectModel::kCompositeReplace);
+    keyframe->SetOffset(offset);
+    keyframe->SetEasing(LinearTimingFunction::Shared());
+    return keyframe;
+  }
+
   StringKeyframe* CreateDefaultKeyframe(CSSPropertyID id,
                                         EffectModel::CompositeOperation op,
                                         double offset = 0) {
@@ -246,6 +264,29 @@
     return frames;
   }
 
+  void RegisterProperty(const String& name,
+                        const String& syntax,
+                        const String& initial_value,
+                        bool is_inherited) {
+    DummyExceptionStateForTesting exception_state;
+    PropertyDescriptor property_descriptor;
+    property_descriptor.setName(name);
+    property_descriptor.setSyntax(syntax);
+    property_descriptor.setInitialValue(initial_value);
+    property_descriptor.setInherits(is_inherited);
+    PropertyRegistration::registerProperty(&GetDocument(), property_descriptor,
+                                           exception_state);
+    EXPECT_FALSE(exception_state.HadException());
+  }
+
+  void SetCustomProperty(const String& name, const String& value) {
+    DummyExceptionStateForTesting exception_state;
+    element_->style()->setProperty(&GetDocument(), name, value, g_empty_string,
+                                   exception_state);
+    EXPECT_FALSE(exception_state.HadException());
+    EXPECT_TRUE(element_->style()->getPropertyValue(name));
+  }
+
   // This class exists to dodge the interlock between creating animatable
   // values iff we can animate them on the compositor, and hence can
   // start their animations on it. i.e. two far away switch statements
@@ -285,7 +326,7 @@
         return nullptr;
       }
       bool PopulateAnimatableValue(
-          const CSSProperty&,
+          const PropertyHandle&,
           Element&,
           const ComputedStyle& base_style,
           const ComputedStyle* parent_style) const final {
@@ -387,7 +428,7 @@
     // As the compositor code only understands AnimatableValues, we must
     // snapshot the effect to make those available.
     // TODO(crbug.com/725385): Remove once compositor uses InterpolationTypes.
-    auto style = ComputedStyle::Create();
+    auto style = GetDocument().EnsureStyleResolver().StyleForElement(element_);
     effect.SnapshotAllCompositorKeyframesIfNecessary(*element_.Get(), *style,
                                                      nullptr);
 
@@ -485,7 +526,7 @@
 }
 
 TEST_F(AnimationCompositorAnimationsTest,
-       isNotCandidateForCompositorAnimationTransformDependsOnBoxSize) {
+       IsNotCandidateForCompositorAnimationTransformDependsOnBoxSize) {
   // Absolute transforms can be animated on the compositor.
   String transform = "translateX(2px) translateY(2px)";
   StringKeyframe* good_keyframe =
@@ -537,6 +578,30 @@
 }
 
 TEST_F(AnimationCompositorAnimationsTest,
+       CanStartEffectOnCompositorCustomCssProperty) {
+  ScopedOffMainThreadCSSPaintForTest off_main_thread_css_paint(true);
+  RegisterProperty("--foo", "<number>", "0", false);
+  RegisterProperty("--bar", "<length>", "10px", false);
+  SetCustomProperty("--foo", "10");
+  SetCustomProperty("--bar", "10px");
+
+  auto style = GetDocument().EnsureStyleResolver().StyleForElement(element_);
+  EXPECT_TRUE(style->NonInheritedVariables());
+  EXPECT_TRUE(
+      style->NonInheritedVariables()->GetVariable(AtomicString("--foo")));
+  EXPECT_TRUE(
+      style->NonInheritedVariables()->GetVariable(AtomicString("--bar")));
+
+  StringKeyframe* keyframe = CreateReplaceOpKeyframe("--foo", "10");
+  EXPECT_TRUE(DuplicateSingleKeyframeAndTestIsCandidateOnResult(keyframe));
+
+  StringKeyframe* non_animatable_keyframe =
+      CreateReplaceOpKeyframe("--bar", "10px");
+  EXPECT_FALSE(DuplicateSingleKeyframeAndTestIsCandidateOnResult(
+      non_animatable_keyframe));
+}
+
+TEST_F(AnimationCompositorAnimationsTest,
        ConvertTimingForCompositorStartDelay) {
   timing_.iteration_duration = AnimationTimeDelta::FromSecondsD(20);
 
@@ -813,7 +878,7 @@
   EXPECT_TRUE(CheckCanStartEffectOnCompositor(timing, *element.Get(), animation,
                                               *animation_effect, none));
 
-  // Timings have to be convertible for compostor.
+  // Timings have to be convertible for compositor.
   compositor_ids.insert(CompositorElementIdFromUniqueObjectId(
       new_layout_object->UniqueId(), CompositorElementIdNamespace::kPrimary));
   EXPECT_TRUE(CheckCanStartEffectOnCompositor(
@@ -1194,7 +1259,7 @@
 // -----------------------------------------------------------------------
 // -----------------------------------------------------------------------
 
-TEST_F(AnimationCompositorAnimationsTest, createSimpleOpacityAnimation) {
+TEST_F(AnimationCompositorAnimationsTest, CreateSimpleOpacityAnimation) {
   // KeyframeEffect to convert
   StringKeyframeEffectModel* effect = CreateKeyframeEffectModel(
       CreateReplaceOpKeyframe(CSSPropertyOpacity, "0.2", 0),
@@ -1229,7 +1294,7 @@
 }
 
 TEST_F(AnimationCompositorAnimationsTest,
-       createSimpleOpacityAnimationDuration) {
+       CreateSimpleOpacityAnimationDuration) {
   // KeyframeEffect to convert
   StringKeyframeEffectModel* effect = CreateKeyframeEffectModel(
       CreateReplaceOpKeyframe(CSSPropertyOpacity, "0.2", 0),
@@ -1251,7 +1316,7 @@
 }
 
 TEST_F(AnimationCompositorAnimationsTest,
-       createMultipleKeyframeOpacityAnimationLinear) {
+       CreateMultipleKeyframeOpacityAnimationLinear) {
   // KeyframeEffect to convert
   StringKeyframeEffectModel* effect = CreateKeyframeEffectModel(
       CreateReplaceOpKeyframe(CSSPropertyOpacity, "0.2", 0),
@@ -1301,7 +1366,7 @@
 }
 
 TEST_F(AnimationCompositorAnimationsTest,
-       createSimpleOpacityAnimationStartDelay) {
+       CreateSimpleOpacityAnimationStartDelay) {
   // KeyframeEffect to convert
   StringKeyframeEffectModel* effect = CreateKeyframeEffectModel(
       CreateReplaceOpKeyframe(CSSPropertyOpacity, "0.2", 0),
@@ -1334,7 +1399,7 @@
 }
 
 TEST_F(AnimationCompositorAnimationsTest,
-       createMultipleKeyframeOpacityAnimationChained) {
+       CreateMultipleKeyframeOpacityAnimationChained) {
   // KeyframeEffect to convert
   StringKeyframeVector frames;
   frames.push_back(CreateReplaceOpKeyframe(CSSPropertyOpacity, "0.2", 0));
@@ -1392,7 +1457,7 @@
             keyframes[3]->GetTimingFunctionForTesting()->GetType());
 }
 
-TEST_F(AnimationCompositorAnimationsTest, createReversedOpacityAnimation) {
+TEST_F(AnimationCompositorAnimationsTest, CreateReversedOpacityAnimation) {
   scoped_refptr<TimingFunction> cubic_easy_flip_timing_function =
       CubicBezierTimingFunction::Create(0.0, 0.0, 0.0, 1.0);
 
@@ -1454,7 +1519,7 @@
 }
 
 TEST_F(AnimationCompositorAnimationsTest,
-       createReversedOpacityAnimationNegativeStartDelay) {
+       CreateReversedOpacityAnimationNegativeStartDelay) {
   // KeyframeEffect to convert
   StringKeyframeEffectModel* effect = CreateKeyframeEffectModel(
       CreateReplaceOpKeyframe(CSSPropertyOpacity, "0.2", 0),
@@ -1486,7 +1551,7 @@
 }
 
 TEST_F(AnimationCompositorAnimationsTest,
-       createSimpleOpacityAnimationFillModeNone) {
+       CreateSimpleOpacityAnimationFillModeNone) {
   // KeyframeEffect to convert
   StringKeyframeEffectModel* effect = CreateKeyframeEffectModel(
       CreateReplaceOpKeyframe(CSSPropertyOpacity, "0.2", 0),
@@ -1501,7 +1566,7 @@
 }
 
 TEST_F(AnimationCompositorAnimationsTest,
-       createSimpleOpacityAnimationFillModeAuto) {
+       CreateSimpleOpacityAnimationFillModeAuto) {
   // KeyframeEffect to convert
   StringKeyframeEffectModel* effect = CreateKeyframeEffectModel(
       CreateReplaceOpKeyframe(CSSPropertyOpacity, "0.2", 0),
@@ -1523,7 +1588,7 @@
 }
 
 TEST_F(AnimationCompositorAnimationsTest,
-       createSimpleOpacityAnimationWithTimingFunction) {
+       CreateSimpleOpacityAnimationWithTimingFunction) {
   // KeyframeEffect to convert
   StringKeyframeEffectModel* effect = CreateKeyframeEffectModel(
       CreateReplaceOpKeyframe(CSSPropertyOpacity, "0.2", 0),
@@ -1566,7 +1631,41 @@
 }
 
 TEST_F(AnimationCompositorAnimationsTest,
-       cancelIncompatibleCompositorAnimations) {
+       CreateSimpleCustomFloatPropertyAnimation) {
+  ScopedOffMainThreadCSSPaintForTest off_main_thread_css_paint(true);
+
+  RegisterProperty("--foo", "<number>", "0", false);
+  SetCustomProperty("--foo", "10");
+
+  StringKeyframeEffectModel* effect =
+      CreateKeyframeEffectModel(CreateReplaceOpKeyframe("--foo", "10", 0),
+                                CreateReplaceOpKeyframe("--foo", "20", 1.0));
+
+  std::unique_ptr<CompositorKeyframeModel> keyframe_model =
+      ConvertToCompositorAnimation(*effect);
+  EXPECT_EQ(CompositorTargetProperty::CSS_CUSTOM_PROPERTY,
+            keyframe_model->TargetProperty());
+
+  std::unique_ptr<CompositorFloatAnimationCurve> keyframed_float_curve =
+      keyframe_model->FloatCurveForTesting();
+
+  CompositorFloatAnimationCurve::Keyframes keyframes =
+      keyframed_float_curve->KeyframesForTesting();
+  ASSERT_EQ(2UL, keyframes.size());
+
+  EXPECT_EQ(0, keyframes[0]->Time());
+  EXPECT_EQ(10, keyframes[0]->Value());
+  EXPECT_EQ(TimingFunction::Type::LINEAR,
+            keyframes[0]->GetTimingFunctionForTesting()->GetType());
+
+  EXPECT_EQ(1.0, keyframes[1]->Time());
+  EXPECT_EQ(20, keyframes[1]->Value());
+  EXPECT_EQ(TimingFunction::Type::LINEAR,
+            keyframes[1]->GetTimingFunctionForTesting()->GetType());
+}
+
+TEST_F(AnimationCompositorAnimationsTest,
+       CancelIncompatibleCompositorAnimations) {
   Persistent<Element> element = GetDocument().CreateElementForBinding("shared");
   base::Optional<CompositorElementIdSet> none;
 
@@ -1653,7 +1752,7 @@
 }  // namespace
 
 TEST_F(AnimationCompositorAnimationsTest,
-       canStartElementOnCompositorTransformSPv2) {
+       CanStartElementOnCompositorTransformSPv2) {
   Persistent<Element> element = GetDocument().CreateElementForBinding("shared");
   LayoutObjectProxy* layout_object = LayoutObjectProxy::Create(element.Get());
   layout_object->EnsureIdForTestingProxy();
@@ -1686,7 +1785,7 @@
 }
 
 TEST_F(AnimationCompositorAnimationsTest,
-       canStartElementOnCompositorEffectSPv2) {
+       CanStartElementOnCompositorEffectSPv2) {
   Persistent<Element> element = GetDocument().CreateElementForBinding("shared");
   LayoutObjectProxy* layout_object = LayoutObjectProxy::Create(element.Get());
   layout_object->EnsureIdForTestingProxy();
@@ -1718,7 +1817,7 @@
   LayoutObjectProxy::Dispose(layout_object);
 }
 
-TEST_F(AnimationCompositorAnimationsTest, trackRafAnimation) {
+TEST_F(AnimationCompositorAnimationsTest, TrackRafAnimation) {
   LoadTestData("raf-countdown.html");
 
   CompositorAnimationHost* host =
@@ -1747,7 +1846,7 @@
   EXPECT_FALSE(host->NextFrameHasPendingRAFForTesting());
 }
 
-TEST_F(AnimationCompositorAnimationsTest, trackRafAnimationTimeout) {
+TEST_F(AnimationCompositorAnimationsTest, TrackRafAnimationTimeout) {
   LoadTestData("raf-timeout.html");
 
   CompositorAnimationHost* host =
@@ -1761,7 +1860,7 @@
   EXPECT_FALSE(host->NextFrameHasPendingRAFForTesting());
 }
 
-TEST_F(AnimationCompositorAnimationsTest, trackRafAnimationNoneRegistered) {
+TEST_F(AnimationCompositorAnimationsTest, TrackRafAnimationNoneRegistered) {
   SetBodyInnerHTML("<div id='box'></div>");
 
   // Run a full frame after loading the test data so that scripted animations
@@ -1782,7 +1881,7 @@
   EXPECT_FALSE(host->NextFrameHasPendingRAFForTesting());
 }
 
-TEST_F(AnimationCompositorAnimationsTest, canStartElementOnCompositorEffect) {
+TEST_F(AnimationCompositorAnimationsTest, CanStartElementOnCompositorEffect) {
   LoadTestData("transform-animation.html");
   Document* document = GetFrame()->GetDocument();
   Element* target = document->getElementById("target");
@@ -1804,7 +1903,7 @@
 // animation on a SVG element, the effect can be started on compositor but the
 // element itself cannot.
 TEST_F(AnimationCompositorAnimationsTest,
-       cannotStartElementOnCompositorEffectSVG) {
+       CannotStartElementOnCompositorEffectSVG) {
   LoadTestData("transform-animation-on-svg.html");
   Document* document = GetFrame()->GetDocument();
   Element* target = document->getElementById("dots");
diff --git a/third_party/blink/renderer/core/animation/css/css_animatable_value_factory.cc b/third_party/blink/renderer/core/animation/css/css_animatable_value_factory.cc
index c8dee3e..40778cb 100644
--- a/third_party/blink/renderer/core/animation/css/css_animatable_value_factory.cc
+++ b/third_party/blink/renderer/core/animation/css/css_animatable_value_factory.cc
@@ -34,8 +34,10 @@
 #include "third_party/blink/renderer/core/animation/animatable/animatable_filter_operations.h"
 #include "third_party/blink/renderer/core/animation/animatable/animatable_transform.h"
 #include "third_party/blink/renderer/core/animation/compositor_animations.h"
+#include "third_party/blink/renderer/core/animation/property_handle.h"
 #include "third_party/blink/renderer/core/css/properties/css_property.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 
 namespace blink {
 
@@ -52,11 +54,18 @@
   return AnimatableTransform::Create(operation, has_transform ? zoom : 1);
 }
 
-AnimatableValue* CSSAnimatableValueFactory::Create(const CSSProperty& property,
-                                                   const ComputedStyle& style) {
-  DCHECK(property.IsInterpolable());
-  DCHECK(property.IsCompositableProperty());
-  switch (property.PropertyID()) {
+AnimatableValue* CSSAnimatableValueFactory::Create(
+    const PropertyHandle& property,
+    const ComputedStyle& style) {
+  const CSSProperty& css_property = property.GetCSSProperty();
+#if DCHECK_IS_ON()
+  // Variables are conditionally interpolable and compositable.
+  if (css_property.PropertyID() != CSSPropertyVariable) {
+    DCHECK(css_property.IsInterpolable());
+    DCHECK(css_property.IsCompositableProperty());
+  }
+#endif
+  switch (css_property.PropertyID()) {
     case CSSPropertyOpacity:
       return AnimatableDouble::Create(style.Opacity());
     case CSSPropertyFilter:
@@ -78,6 +87,19 @@
       return CreateFromTransformProperties(style.Scale(), style.EffectiveZoom(),
                                            nullptr);
     }
+    case CSSPropertyVariable: {
+      if (!RuntimeEnabledFeatures::OffMainThreadCSSPaintEnabled()) {
+        return nullptr;
+      }
+      const AtomicString& property_name = property.CustomPropertyName();
+      const CSSValue* value = style.GetRegisteredVariable(property_name);
+      if (!value || !value->IsPrimitiveValue() ||
+          !ToCSSPrimitiveValue(*value).IsNumber()) {
+        return nullptr;
+      }
+      return AnimatableDouble::Create(
+          ToCSSPrimitiveValue(*value).GetFloatValue());
+    }
     default:
       NOTREACHED();
       return nullptr;
diff --git a/third_party/blink/renderer/core/animation/css/css_animatable_value_factory.h b/third_party/blink/renderer/core/animation/css/css_animatable_value_factory.h
index 1ef40807..30243107 100644
--- a/third_party/blink/renderer/core/animation/css/css_animatable_value_factory.h
+++ b/third_party/blink/renderer/core/animation/css/css_animatable_value_factory.h
@@ -32,19 +32,19 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_CSS_CSS_ANIMATABLE_VALUE_FACTORY_H_
 
 #include "third_party/blink/renderer/core/animation/animatable/animatable_value.h"
-#include "third_party/blink/renderer/core/css/properties/css_property.h"
 #include "third_party/blink/renderer/core/css_property_names.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 
 namespace blink {
 
 class ComputedStyle;
+class PropertyHandle;
 
 class CSSAnimatableValueFactory {
   STATIC_ONLY(CSSAnimatableValueFactory);
 
  public:
-  static AnimatableValue* Create(const CSSProperty&, const ComputedStyle&);
+  static AnimatableValue* Create(const PropertyHandle&, const ComputedStyle&);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/animation/css/css_animations.cc b/third_party/blink/renderer/core/animation/css/css_animations.cc
index d5faf28..220aafd 100644
--- a/third_party/blink/renderer/core/animation/css/css_animations.cc
+++ b/third_party/blink/renderer/core/animation/css/css_animations.cc
@@ -819,10 +819,10 @@
   keyframes.push_back(end_keyframe);
 
   if (property.GetCSSProperty().IsCompositableProperty()) {
-    AnimatableValue* from = CSSAnimatableValueFactory::Create(
-        property.GetCSSProperty(), state.old_style);
-    AnimatableValue* to = CSSAnimatableValueFactory::Create(
-        property.GetCSSProperty(), state.style);
+    AnimatableValue* from =
+        CSSAnimatableValueFactory::Create(property, state.old_style);
+    AnimatableValue* to =
+        CSSAnimatableValueFactory::Create(property, state.style);
     delay_keyframe->SetCompositorValue(from);
     start_keyframe->SetCompositorValue(from);
     end_keyframe->SetCompositorValue(to);
diff --git a/third_party/blink/renderer/core/animation/keyframe.h b/third_party/blink/renderer/core/animation/keyframe.h
index 1baf81c..909a4b6 100644
--- a/third_party/blink/renderer/core/animation/keyframe.h
+++ b/third_party/blink/renderer/core/animation/keyframe.h
@@ -133,12 +133,13 @@
     // FIXME: Remove this once CompositorAnimations no longer depends on
     // AnimatableValues
     virtual bool PopulateAnimatableValue(
-        const CSSProperty&,
+        const PropertyHandle&,
         Element&,
         const ComputedStyle& base_style,
         const ComputedStyle* parent_style) const {
       return false;
     }
+
     virtual const AnimatableValue* GetAnimatableValue() const = 0;
 
     virtual bool IsAnimatableValuePropertySpecificKeyframe() const {
diff --git a/third_party/blink/renderer/core/animation/keyframe_effect_model.cc b/third_party/blink/renderer/core/animation/keyframe_effect_model.cc
index b6e1c91..f590afa 100644
--- a/third_party/blink/renderer/core/animation/keyframe_effect_model.cc
+++ b/third_party/blink/renderer/core/animation/keyframe_effect_model.cc
@@ -37,9 +37,11 @@
 #include "third_party/blink/renderer/core/animation/compositor_animations.h"
 #include "third_party/blink/renderer/core/animation/css/css_animatable_value_factory.h"
 #include "third_party/blink/renderer/core/css/css_property_equality.h"
+#include "third_party/blink/renderer/core/css/property_registry.h"
 #include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/frame/use_counter.h"
+#include "third_party/blink/renderer/core/style/computed_style.h"
 #include "third_party/blink/renderer/platform/animation/animation_utilities.h"
 #include "third_party/blink/renderer/platform/geometry/float_box.h"
 #include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
@@ -112,25 +114,19 @@
     const ComputedStyle& old_style,
     const ComputedStyle& new_style,
     const ComputedStyle* parent_style) const {
-  bool updated = false;
-  EnsureKeyframeGroups();
-  static const CSSProperty** compositable_properties = CompositableProperties();
-  for (size_t i = 0; i < num_compositable_properties; i++) {
-    const CSSProperty& property = *compositable_properties[i];
-    if (CSSPropertyEquality::PropertiesEqual(PropertyHandle(property),
-                                             old_style, new_style))
-      continue;
-    PropertySpecificKeyframeGroup* keyframe_group =
-        keyframe_groups_->at(PropertyHandle(property));
-    if (!keyframe_group)
-      continue;
-    for (auto& keyframe : keyframe_group->keyframes_) {
-      if (keyframe->IsNeutral())
-        updated |= keyframe->PopulateAnimatableValue(property, element,
-                                                     new_style, parent_style);
-    }
-  }
-  return updated;
+  ShouldSnapshotPropertyCallback should_snapshot_property_callback =
+      [&old_style, &new_style](const PropertyHandle& property) {
+        return !CSSPropertyEquality::PropertiesEqual(property, old_style,
+                                                     new_style);
+      };
+  ShouldSnapshotKeyframeCallback should_snapshot_keyframe_callback =
+      [](const PropertySpecificKeyframe& keyframe) {
+        return keyframe.IsNeutral();
+      };
+
+  return SnapshotCompositableProperties(element, new_style, parent_style,
+                                        should_snapshot_property_callback,
+                                        should_snapshot_keyframe_callback);
 }
 
 bool KeyframeEffectModelBase::SnapshotAllCompositorKeyframesIfNecessary(
@@ -140,22 +136,21 @@
   if (!needs_compositor_keyframes_snapshot_)
     return false;
   needs_compositor_keyframes_snapshot_ = false;
-  bool updated = false;
+
   bool has_neutral_compositable_keyframe = false;
-  EnsureKeyframeGroups();
-  static const CSSProperty** compositable_properties = CompositableProperties();
-  for (size_t i = 0; i < num_compositable_properties; i++) {
-    const CSSProperty& property = *compositable_properties[i];
-    PropertySpecificKeyframeGroup* keyframe_group =
-        keyframe_groups_->at(PropertyHandle(property));
-    if (!keyframe_group)
-      continue;
-    for (auto& keyframe : keyframe_group->keyframes_) {
-      updated |= keyframe->PopulateAnimatableValue(property, element,
-                                                   base_style, parent_style);
-      has_neutral_compositable_keyframe |= keyframe->IsNeutral();
-    }
-  }
+  ShouldSnapshotPropertyCallback should_snapshot_property_callback =
+      [](const PropertyHandle& property) { return true; };
+  ShouldSnapshotKeyframeCallback should_snapshot_keyframe_callback =
+      [&has_neutral_compositable_keyframe](
+          const PropertySpecificKeyframe& keyframe) mutable {
+        has_neutral_compositable_keyframe |= keyframe.IsNeutral();
+        return true;
+      };
+
+  bool updated = SnapshotCompositableProperties(
+      element, base_style, parent_style, should_snapshot_property_callback,
+      should_snapshot_keyframe_callback);
+
   if (updated && has_neutral_compositable_keyframe) {
     UseCounter::Count(element.GetDocument(),
                       WebFeature::kSyntheticKeyframesInCompositedCSSAnimation);
@@ -163,6 +158,67 @@
   return updated;
 }
 
+bool KeyframeEffectModelBase::SnapshotCompositableProperties(
+    Element& element,
+    const ComputedStyle& computed_style,
+    const ComputedStyle* parent_style,
+    ShouldSnapshotPropertyCallback should_snapshot_property_callback,
+    ShouldSnapshotKeyframeCallback should_snapshot_keyframe_callback) const {
+  EnsureKeyframeGroups();
+  bool updated = false;
+  static const CSSProperty** compositable_properties = CompositableProperties();
+  for (size_t i = 0; i < num_compositable_properties; i++) {
+    updated |= SnapshotCompositorKeyFrames(
+        PropertyHandle(*compositable_properties[i]), element, computed_style,
+        parent_style, should_snapshot_property_callback,
+        should_snapshot_keyframe_callback);
+  }
+  // Custom properties need to be handled separately, since not all values
+  // can be animated.  Need to resolve the value of each custom property to
+  // ensure that it can be animated.
+  if (auto* inherited_variables = computed_style.InheritedVariables()) {
+    for (const auto& name : inherited_variables->GetCustomPropertyNames()) {
+      updated |= SnapshotCompositorKeyFrames(
+          PropertyHandle(name), element, computed_style, parent_style,
+          should_snapshot_property_callback, should_snapshot_keyframe_callback);
+    }
+  }
+  if (auto* non_inherited_variables = computed_style.NonInheritedVariables()) {
+    for (const auto& name : non_inherited_variables->GetCustomPropertyNames()) {
+      updated |= SnapshotCompositorKeyFrames(
+          PropertyHandle(name), element, computed_style, parent_style,
+          should_snapshot_property_callback, should_snapshot_keyframe_callback);
+    }
+  }
+  return updated;
+}
+
+bool KeyframeEffectModelBase::SnapshotCompositorKeyFrames(
+    const PropertyHandle& property,
+    Element& element,
+    const ComputedStyle& computed_style,
+    const ComputedStyle* parent_style,
+    ShouldSnapshotPropertyCallback should_snapshot_property_callback,
+    ShouldSnapshotKeyframeCallback should_snapshot_keyframe_callback) const {
+  if (!should_snapshot_property_callback(property))
+    return false;
+
+  PropertySpecificKeyframeGroup* keyframe_group =
+      keyframe_groups_->at(property);
+  if (!keyframe_group)
+    return false;
+
+  bool updated = false;
+  for (auto& keyframe : keyframe_group->keyframes_) {
+    if (!should_snapshot_keyframe_callback(*keyframe))
+      continue;
+
+    updated |= keyframe->PopulateAnimatableValue(property, element,
+                                                 computed_style, parent_style);
+  }
+  return updated;
+}
+
 template <class K>
 Vector<double> KeyframeEffectModelBase::GetComputedOffsets(
     const HeapVector<K>& keyframes) {
diff --git a/third_party/blink/renderer/core/animation/keyframe_effect_model.h b/third_party/blink/renderer/core/animation/keyframe_effect_model.h
index aa96602..7b52cc8 100644
--- a/third_party/blink/renderer/core/animation/keyframe_effect_model.h
+++ b/third_party/blink/renderer/core/animation/keyframe_effect_model.h
@@ -48,6 +48,7 @@
 
 namespace blink {
 
+class ComputedStyle;
 class Element;
 class KeyframeEffectModelTest;
 
@@ -165,6 +166,26 @@
   void EnsureKeyframeGroups() const;
   void EnsureInterpolationEffectPopulated() const;
 
+  using ShouldSnapshotPropertyCallback =
+      std::function<bool(const PropertyHandle&)>;
+  using ShouldSnapshotKeyframeCallback =
+      std::function<bool(const PropertySpecificKeyframe&)>;
+
+  bool SnapshotCompositableProperties(
+      Element& element,
+      const ComputedStyle& computed_style,
+      const ComputedStyle* parent_style,
+      ShouldSnapshotPropertyCallback should_process_property_callback,
+      ShouldSnapshotKeyframeCallback should_process_keyframe_callback) const;
+
+  bool SnapshotCompositorKeyFrames(
+      const PropertyHandle& property,
+      Element& element,
+      const ComputedStyle& computed_style,
+      const ComputedStyle* parent_style,
+      ShouldSnapshotPropertyCallback should_process_property_callback,
+      ShouldSnapshotKeyframeCallback should_process_keyframe_callback) const;
+
   KeyframeVector keyframes_;
   // The spec describes filtering the normalized keyframes at sampling time
   // to get the 'property-specific keyframes'. For efficiency, we cache the
diff --git a/third_party/blink/renderer/core/animation/keyframe_effect_model_test.cc b/third_party/blink/renderer/core/animation/keyframe_effect_model_test.cc
index c055b3b..5feb953 100644
--- a/third_party/blink/renderer/core/animation/keyframe_effect_model_test.cc
+++ b/third_party/blink/renderer/core/animation/keyframe_effect_model_test.cc
@@ -37,10 +37,14 @@
 #include "third_party/blink/renderer/core/animation/invalidatable_interpolation.h"
 #include "third_party/blink/renderer/core/animation/string_keyframe.h"
 #include "third_party/blink/renderer/core/css/css_primitive_value.h"
+#include "third_party/blink/renderer/core/css/property_descriptor.h"
+#include "third_party/blink/renderer/core/css/property_registration.h"
+#include "third_party/blink/renderer/core/css/property_registry.h"
 #include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
 #include "third_party/blink/renderer/core/dom/element.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
 #include "third_party/blink/renderer/core/testing/page_test_base.h"
+#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
 
 namespace blink {
 
@@ -106,6 +110,25 @@
   return keyframes;
 }
 
+StringKeyframeVector KeyframesAtZeroAndOne(
+    AtomicString property_name,
+    const PropertyRegistry* property_registry,
+    const String& zero_value,
+    const String& one_value) {
+  StringKeyframeVector keyframes(2);
+  keyframes[0] = StringKeyframe::Create();
+  keyframes[0]->SetOffset(0.0);
+  keyframes[0]->SetCSSPropertyValue(
+      property_name, property_registry, zero_value,
+      SecureContextMode::kInsecureContext, nullptr);
+  keyframes[1] = StringKeyframe::Create();
+  keyframes[1]->SetOffset(1.0);
+  keyframes[1]->SetCSSPropertyValue(property_name, property_registry, one_value,
+                                    SecureContextMode::kInsecureContext,
+                                    nullptr);
+  return keyframes;
+}
+
 void ExpectProperty(CSSPropertyID property,
                     Interpolation* interpolation_value) {
   InvalidatableInterpolation* interpolation =
@@ -652,6 +675,45 @@
   EXPECT_TRUE(value->IsFilterOperations());
 }
 
+TEST_F(AnimationKeyframeEffectModel, CompositorSnapshotUpdateCustomProperty) {
+  ScopedOffMainThreadCSSPaintForTest off_main_thread_css_paint(true);
+  DummyExceptionStateForTesting exception_state;
+  PropertyDescriptor property_descriptor;
+  property_descriptor.setName("--foo");
+  property_descriptor.setSyntax("<number>");
+  property_descriptor.setInitialValue("0");
+  property_descriptor.setInherits(false);
+  PropertyRegistration::registerProperty(&GetDocument(), property_descriptor,
+                                         exception_state);
+  EXPECT_FALSE(exception_state.HadException());
+
+  StringKeyframeVector keyframes = KeyframesAtZeroAndOne(
+      AtomicString("--foo"), GetDocument().GetPropertyRegistry(), "0", "100");
+
+  element->style()->setProperty(&GetDocument(), "--foo", "0", g_empty_string,
+                                exception_state);
+  EXPECT_FALSE(exception_state.HadException());
+
+  StringKeyframeEffectModel* effect =
+      StringKeyframeEffectModel::Create(keyframes);
+
+  auto style = GetDocument().EnsureStyleResolver().StyleForElement(element);
+
+  const AnimatableValue* value;
+
+  // Snapshot should update first time after construction
+  EXPECT_TRUE(effect->SnapshotAllCompositorKeyframesIfNecessary(
+      *element, *style, nullptr));
+
+  // Animatable value should be available after snapshot
+  value = effect
+              ->GetPropertySpecificKeyframes(
+                  PropertyHandle(AtomicString("--foo")))[0]
+              ->GetAnimatableValue();
+  EXPECT_TRUE(value);
+  EXPECT_TRUE(value->IsDouble());
+}
+
 }  // namespace blink
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/animation/string_keyframe.cc b/third_party/blink/renderer/core/animation/string_keyframe.cc
index 8fcfbe3..ff3c9c1 100644
--- a/third_party/blink/renderer/core/animation/string_keyframe.cc
+++ b/third_party/blink/renderer/core/animation/string_keyframe.cc
@@ -169,7 +169,7 @@
 }
 
 bool StringKeyframe::CSSPropertySpecificKeyframe::PopulateAnimatableValue(
-    const CSSProperty& property,
+    const PropertyHandle& property,
     Element& element,
     const ComputedStyle& base_style,
     const ComputedStyle* parent_style) const {
diff --git a/third_party/blink/renderer/core/animation/string_keyframe.h b/third_party/blink/renderer/core/animation/string_keyframe.h
index c503feaf..d2b824f 100644
--- a/third_party/blink/renderer/core/animation/string_keyframe.h
+++ b/third_party/blink/renderer/core/animation/string_keyframe.h
@@ -94,7 +94,7 @@
 
     const CSSValue* Value() const { return value_.Get(); }
 
-    bool PopulateAnimatableValue(const CSSProperty&,
+    bool PopulateAnimatableValue(const PropertyHandle&,
                                  Element&,
                                  const ComputedStyle& base_style,
                                  const ComputedStyle* parent_style) const final;
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver.cc b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
index 0d3b4ac..a8ed17a4f 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
@@ -819,7 +819,7 @@
     Element& element,
     const ComputedStyle& base_style,
     const ComputedStyle* parent_style,
-    const CSSProperty& property,
+    const PropertyHandle& property,
     const CSSValue* value) {
   // TODO(alancutter): Avoid creating a StyleResolverState just to apply a
   // single value on a ComputedStyle.
@@ -827,10 +827,11 @@
                            parent_style);
   state.SetStyle(ComputedStyle::Clone(base_style));
   if (value) {
-    StyleBuilder::ApplyProperty(property, state, *value);
+    StyleBuilder::ApplyProperty(property.GetCSSProperty(), state, *value);
     state.GetFontBuilder().CreateFont(
         state.GetDocument().GetStyleEngine().GetFontSelector(),
         state.StyleRef());
+    CSSVariableResolver(state).ResolveVariableDefinitions();
   }
   return CSSAnimatableValueFactory::Create(property, *state.Style());
 }
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver.h b/third_party/blink/renderer/core/css/resolver/style_resolver.h
index f300fa31..a84ffa57 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver.h
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver.h
@@ -52,6 +52,7 @@
 class RuleSet;
 class CSSPropertyValueSet;
 class StyleRuleUsageTracker;
+class PropertyHandle;
 
 enum RuleMatchingBehavior { kMatchAllRules, kMatchAllRulesExcludingSMIL };
 
@@ -78,7 +79,7 @@
       Element&,
       const ComputedStyle& base_style,
       const ComputedStyle* parent_style,
-      const CSSProperty&,
+      const PropertyHandle&,
       const CSSValue*);
 
   scoped_refptr<ComputedStyle> PseudoStyleForElement(
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index 5ff62e1..5bc37f9 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -3573,6 +3573,7 @@
 
 bool Document::DispatchBeforeUnloadEvent(ChromeClient& chrome_client,
                                          bool is_reload,
+                                         bool auto_cancel,
                                          bool& did_allow_navigation) {
   if (!dom_window_)
     return true;
@@ -3603,6 +3604,7 @@
     kNoDialogNoUserGesture,
     kNoDialogMultipleConfirmationForNavigation,
     kShowDialog,
+    kNoDialogAutoCancelTrue,
     kDialogEnumMax
   };
   DEFINE_STATIC_LOCAL(EnumerationHistogram, beforeunload_dialog_histogram,
@@ -3632,6 +3634,15 @@
     Intervention::GenerateReport(frame_, "BeforeUnloadMultiple", message);
     return true;
   }
+
+  // If |auto_cancel| is set then do not ask the |chrome_client| to display a
+  // modal dialog. Simply indicate that the navigation should not proceed.
+  if (auto_cancel) {
+    beforeunload_dialog_histogram.Count(kNoDialogAutoCancelTrue);
+    did_allow_navigation = false;
+    return false;
+  }
+
   String text = before_unload_event.returnValue();
   beforeunload_dialog_histogram.Count(
       BeforeUnloadDialogHistogramEnum::kShowDialog);
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index 93ea57d..bc4131e 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -633,8 +633,30 @@
 
   void CheckCompleted();
 
-  bool DispatchBeforeUnloadEvent(ChromeClient&,
+  // Dispatches beforeunload into this document. Returns true if the
+  // beforeunload handler indicates that it is safe to proceed with an unload,
+  // false otherwise.
+  //
+  // |chrome_client| is used to synchronously get user consent (via a modal
+  // javascript dialog) to allow the unload to proceed if the beforeunload
+  // handler returns a non-null value, indicating unsaved state.
+  //
+  // |is_reload| indicates if the beforeunload is being triggered because of a
+  // reload operation, otherwise it is assumed to be a page close or navigation.
+  //
+  // If |auto_cancel| is true and the beforeunload returns a non-null value then
+  // the |chrome_client| will not be invoked, and this function will
+  // automatically return false, indicating that the unload should not proceed.
+  // This is set to true by the freezing logic, which uses this to determine if
+  // a non-empty beforeunload handler is present before allowing discarding to
+  // proceed.
+  //
+  // |did_allow_navigation| is set to reflect the choice made by the user via
+  // the modal dialog. The value is meaningless if |auto_cancel|
+  // is true, in which case it will always be set to false.
+  bool DispatchBeforeUnloadEvent(ChromeClient& chrome_client,
                                  bool is_reload,
+                                 bool auto_cancel,
                                  bool& did_allow_navigation);
   void DispatchUnloadEvents();
 
diff --git a/third_party/blink/renderer/core/exported/local_frame_client_impl.cc b/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
index 09032f01..d7e2cf8d 100644
--- a/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
+++ b/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
@@ -692,12 +692,6 @@
   }
 }
 
-void LocalFrameClientImpl::DidDetectXSS(const KURL& insecure_url,
-                                        bool did_block_entire_page) {
-  if (web_frame_->Client())
-    web_frame_->Client()->DidDetectXSS(insecure_url, did_block_entire_page);
-}
-
 void LocalFrameClientImpl::DidDispatchPingLoader(const KURL& url) {
   if (web_frame_->Client())
     web_frame_->Client()->DidDispatchPingLoader(url);
diff --git a/third_party/blink/renderer/core/exported/local_frame_client_impl.h b/third_party/blink/renderer/core/exported/local_frame_client_impl.h
index dd6caba6..8ec8399b 100644
--- a/third_party/blink/renderer/core/exported/local_frame_client_impl.h
+++ b/third_party/blink/renderer/core/exported/local_frame_client_impl.h
@@ -139,7 +139,6 @@
   void DidContainInsecureFormAction() override;
   void DidRunInsecureContent(const SecurityOrigin*,
                              const KURL& insecure_url) override;
-  void DidDetectXSS(const KURL&, bool did_block_entire_page) override;
   void DidDispatchPingLoader(const KURL&) override;
   void DidDisplayContentWithCertificateErrors() override;
   void DidRunContentWithCertificateErrors() override;
diff --git a/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.cc b/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.cc
index e97cf4c1..4d38ebd 100644
--- a/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.cc
+++ b/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.cc
@@ -185,15 +185,23 @@
       if (!data_pipe_consumer_) {
         network::mojom::blink::DataPipeGetterPtr* data_pipe_getter =
             iter_->data_pipe_getter_->GetPtr();
-        mojo::DataPipe data_pipe;
+
+        mojo::ScopedDataPipeProducerHandle pipe_producer_handle;
+        mojo::ScopedDataPipeConsumerHandle pipe_consumer_handle;
+        MojoResult rv = mojo::CreateDataPipe(nullptr, &pipe_producer_handle,
+                                             &pipe_consumer_handle);
+        if (rv != MOJO_RESULT_OK) {
+          return Result::kError;
+        }
+
         (*data_pipe_getter)
             ->Read(
-                std::move(data_pipe.producer_handle),
+                std::move(pipe_producer_handle),
                 WTF::Bind(&DataPipeAndDataBytesConsumer::DataPipeGetterCallback,
                           WrapWeakPersistent(this)));
         std::unique_ptr<WebDataConsumerHandle> consumer_handle =
             Platform::Current()->CreateDataConsumerHandle(
-                std::move(data_pipe.consumer_handle));
+                std::move(pipe_consumer_handle));
         data_pipe_consumer_ = new BytesConsumerForDataConsumerHandle(
             execution_context_, std::move(consumer_handle));
         if (client_)
diff --git a/third_party/blink/renderer/core/fileapi/file_reader_loader.cc b/third_party/blink/renderer/core/fileapi/file_reader_loader.cc
index 16f81436..173a43d 100644
--- a/third_party/blink/renderer/core/fileapi/file_reader_loader.cc
+++ b/third_party/blink/renderer/core/fileapi/file_reader_loader.cc
@@ -90,16 +90,23 @@
   started_loading_ = true;
 #endif  // DCHECK_IS_ON()
 
-  mojo::DataPipe pipe(blink::BlobUtils::GetDataPipeCapacity(blob_data->size()));
-  if (!pipe.producer_handle.is_valid()) {
+  MojoCreateDataPipeOptions options;
+  options.struct_size = sizeof(MojoCreateDataPipeOptions);
+  options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE;
+  options.element_num_bytes = 1;
+  options.capacity_num_bytes =
+      blink::BlobUtils::GetDataPipeCapacity(blob_data->size());
+
+  mojo::ScopedDataPipeProducerHandle producer_handle;
+  MojoResult rv = CreateDataPipe(&options, &producer_handle, &consumer_handle_);
+  if (rv != MOJO_RESULT_OK) {
     Failed(FileError::kNotReadableErr, FailureType::kMojoPipeCreation);
     return;
   }
-  consumer_handle_ = std::move(pipe.consumer_handle);
 
   mojom::blink::BlobReaderClientPtr client_ptr;
   binding_.Bind(MakeRequest(&client_ptr));
-  blob_data->ReadAll(std::move(pipe.producer_handle), std::move(client_ptr));
+  blob_data->ReadAll(std::move(producer_handle), std::move(client_ptr));
 
   if (IsSyncLoad()) {
     // Wait for OnCalculatedSize, which will also synchronously drain the data
diff --git a/third_party/blink/renderer/core/frame/deprecation.cc b/third_party/blink/renderer/core/frame/deprecation.cc
index 2fa8c84c..ad7015a 100644
--- a/third_party/blink/renderer/core/frame/deprecation.cc
+++ b/third_party/blink/renderer/core/frame/deprecation.cc
@@ -592,8 +592,8 @@
     case WebFeature::kTextToSpeech_SpeakDisallowedByAutoplay:
       return {
           "TextToSpeech_DisallowedByAutoplay", kM71,
-          String::Format("speechSynthesis.speak() without user activation is"
-                         "no longer allowed since %s. See"
+          String::Format("speechSynthesis.speak() without user activation is "
+                         "no longer allowed since %s. See "
                          "https://www.chromestatus.com/feature/"
                          "5687444770914304 for more details",
                          MilestoneString(kM71))};
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index bd2cb91..2bd4094 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -504,10 +504,23 @@
 void LocalFrame::DidFreeze() {
   DCHECK(RuntimeEnabledFeatures::PageLifecycleEnabled());
   if (GetDocument()) {
+    auto* frame_resource_coordinator = GetFrameResourceCoordinator();
+    if (frame_resource_coordinator) {
+      // Determine if there is a beforeunload handler by dispatching a
+      // beforeunload that will *not* launch a user dialog. If
+      // |proceed| is false then there is a non-empty beforeunload
+      // handler indicating potentially unsaved user state.
+      bool unused_did_allow_navigation = false;
+      bool proceed = GetDocument()->DispatchBeforeUnloadEvent(
+          *View()->GetChromeClient(), false /* is_reload */,
+          true /* auto_cancel */, unused_did_allow_navigation);
+      frame_resource_coordinator->SetHasNonEmptyBeforeUnload(!proceed);
+    }
+
     GetDocument()->DispatchFreezeEvent();
     // TODO(fmeawad): Move the following logic to the page once we have a
     // PageResourceCoordinator in Blink. http://crbug.com/838415
-    if (auto* frame_resource_coordinator = GetFrameResourceCoordinator()) {
+    if (frame_resource_coordinator) {
       frame_resource_coordinator->SetLifecycleState(
           resource_coordinator::mojom::LifecycleState::kFrozen);
     }
diff --git a/third_party/blink/renderer/core/frame/local_frame_client.h b/third_party/blink/renderer/core/frame/local_frame_client.h
index 48eb2c9..c9e8f87 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client.h
+++ b/third_party/blink/renderer/core/frame/local_frame_client.h
@@ -192,7 +192,6 @@
   // from an insecure source.  Note that the insecure content can spread to
   // other frames in the same origin.
   virtual void DidRunInsecureContent(const SecurityOrigin*, const KURL&) = 0;
-  virtual void DidDetectXSS(const KURL&, bool did_block_entire_page) = 0;
   virtual void DidDispatchPingLoader(const KURL&) = 0;
 
   // The frame displayed content with certificate errors with given URL.
diff --git a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc
index 8b3f761..388b5db 100644
--- a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc
@@ -58,21 +58,21 @@
 
   // Set up sub-strings for the bucketed UMA metrics
   Vector<String> threshold_substrings;
-  if (!bucket_thresholds_.size()) {
+  if (!bucket_thresholds().size()) {
     threshold_substrings.push_back(".All");
   } else {
     threshold_substrings.push_back(
         String::Format(".LessThan%lums",
-                       (unsigned long)bucket_thresholds_[0].InMilliseconds()));
-    for (wtf_size_t i = 1; i < bucket_thresholds_.size(); ++i) {
+                       (unsigned long)bucket_thresholds()[0].InMilliseconds()));
+    for (wtf_size_t i = 1; i < bucket_thresholds().size(); ++i) {
       threshold_substrings.push_back(String::Format(
           ".%lumsTo%lums",
-          (unsigned long)bucket_thresholds_[i - 1].InMilliseconds(),
-          (unsigned long)bucket_thresholds_[i].InMilliseconds()));
+          (unsigned long)bucket_thresholds()[i - 1].InMilliseconds(),
+          (unsigned long)bucket_thresholds()[i].InMilliseconds()));
     }
     threshold_substrings.push_back(String::Format(
         ".MoreThan%lums",
-        (unsigned long)bucket_thresholds_[bucket_thresholds_.size() - 1]
+        (unsigned long)bucket_thresholds()[bucket_thresholds().size() - 1]
             .InMilliseconds()));
   }
 
@@ -80,7 +80,7 @@
   absolute_metric_records_.ReserveInitialCapacity(kCount);
   ratio_metric_records_.ReserveInitialCapacity(kCount);
   for (unsigned i = 0; i < (unsigned)kCount; ++i) {
-    const auto& metric_name = metric_strings_[i];
+    const auto& metric_name = metric_strings()[i];
 
     // Absolute records report the absolute time for each metric, both
     // average and worst case. They have an associated UMA too that we
@@ -222,9 +222,9 @@
     // Send ratio UMA data only when flushed to reduce overhead from metrics.
     // Find which bucket we're in for UMA data. We need to do this separately
     // for each metric because not every metric records on every frame.
-    size_t bucket_index = bucket_thresholds_.size();
+    size_t bucket_index = bucket_thresholds().size();
     for (size_t i = 0; i < bucket_index; ++i) {
-      if (average_frame_duration < bucket_thresholds_[i].InMicroseconds()) {
+      if (average_frame_duration < bucket_thresholds()[i].InMicroseconds()) {
         bucket_index = i;
       }
     }
diff --git a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h
index 7b424690..9f532bcc 100644
--- a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h
+++ b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h
@@ -5,7 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_LOCAL_FRAME_UKM_AGGREGATOR_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_LOCAL_FRAME_UKM_AGGREGATOR_H_
 
-#include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "third_party/blink/renderer/platform/wtf/time.h"
 
@@ -103,7 +103,7 @@
 //
 // If the source_id/recorder changes then a new
 // UkmHierarchicalTimeAggregator has to be created.
-class LocalFrameUkmAggregator {
+class CORE_EXPORT LocalFrameUkmAggregator {
  public:
   // Changing these values requires changing the names of metrics specified
   // below. For every metric name added here, add an entry in the
@@ -120,22 +120,32 @@
   };
 
  private:
+  friend class LocalFrameUkmAggregatorTest;
+
   // Add an entry in this arrray every time a new metric is added.
-  const String metric_strings_[kCount] = {
-      "Compositing", "CompositingCommit", "IntersectionObservation", "Paint",
-      "PrePaint",    "StyleAndLayout",    "ForcedStyleAndLayout"};
+  static const Vector<String>& metric_strings() {
+    // Leaky construction to avoid exit-time destruction.
+    static const Vector<String>* strings = new Vector<String>{
+        "Compositing", "CompositingCommit", "IntersectionObservation", "Paint",
+        "PrePaint",    "StyleAndLayout",    "ForcedStyleAndLayout"};
+    return *strings;
+  }
 
   // Modify this array if the UMA ratio metrics should be bucketed in a
   // different way.
-  const Vector<TimeDelta> bucket_thresholds_ = {TimeDelta::FromMilliseconds(1),
-                                                TimeDelta::FromMilliseconds(5)};
+  static const Vector<TimeDelta>& bucket_thresholds() {
+    // Leaky construction to avoid exit-time destruction.
+    static const Vector<TimeDelta>* thresholds = new Vector<TimeDelta>{
+        TimeDelta::FromMilliseconds(1), TimeDelta::FromMilliseconds(5)};
+    return *thresholds;
+  }
 
  public:
   // This class will start a timer upon creation, which will end when the
   // object is destroyed. Upon destruction it will record a sample into the
   // aggregator that created the scoped timer. It will also record an event
   // into the histogram counter.
-  class ScopedUkmHierarchicalTimer {
+  class CORE_EXPORT ScopedUkmHierarchicalTimer {
    public:
     ScopedUkmHierarchicalTimer(ScopedUkmHierarchicalTimer&&);
     ~ScopedUkmHierarchicalTimer();
diff --git a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator_test.cc b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator_test.cc
new file mode 100644
index 0000000..69db1fd
--- /dev/null
+++ b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator_test.cc
@@ -0,0 +1,194 @@
+// Copyright 2018 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 "third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h"
+
+#include "components/ukm/test_ukm_recorder.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/testing/wtf/scoped_mock_clock.h"
+
+namespace blink {
+
+class LocalFrameUkmAggregatorTest : public testing::Test {
+ public:
+  LocalFrameUkmAggregatorTest() = default;
+  ~LocalFrameUkmAggregatorTest() override = default;
+
+  void SetUp() override {
+    clock_.emplace();
+    aggregator_.reset(new LocalFrameUkmAggregator(
+        ukm::UkmRecorder::GetNewSourceID(), &recorder_));
+  }
+
+  void TearDown() override {
+    aggregator_.reset();
+    clock_.reset();
+  }
+
+  LocalFrameUkmAggregator& aggregator() {
+    CHECK(aggregator_);
+    return *aggregator_;
+  }
+
+  ukm::TestUkmRecorder& recorder() { return recorder_; }
+
+  void ResetAggregator() { aggregator_.reset(); }
+
+  WTF::ScopedMockClock& clock() { return *clock_; }
+
+  std::string GetAverageMetricName(int index) {
+    return std::string(
+               LocalFrameUkmAggregator::metric_strings()[index].Utf8().data()) +
+           ".Average";
+  }
+
+  std::string GetWorstCaseMetricName(int index) {
+    return std::string(
+               LocalFrameUkmAggregator::metric_strings()[index].Utf8().data()) +
+           ".WorstCase";
+  }
+
+  base::TimeTicks Now() {
+    return base::TimeTicks() + base::TimeDelta::FromSecondsD(clock_->Now());
+  }
+
+ private:
+  base::Optional<WTF::ScopedMockClock> clock_;
+  std::unique_ptr<LocalFrameUkmAggregator> aggregator_;
+  ukm::TestUkmRecorder recorder_;
+};
+
+TEST_F(LocalFrameUkmAggregatorTest, EmptyEventsNotRecorded) {
+  // Although the tests use a mock clock, the UKM aggregator checks if the
+  // system has a high resolution clock before recording results. As a result,
+  // the tests will fail if the system does not have a high resolution clock.
+  if (!base::TimeTicks::IsHighResolution())
+    return;
+
+  clock().Advance(TimeDelta::FromSeconds(10));
+  ResetAggregator();
+
+  EXPECT_EQ(recorder().sources_count(), 0u);
+  EXPECT_EQ(recorder().entries_count(), 0u);
+}
+
+TEST_F(LocalFrameUkmAggregatorTest, EventsRecordedPerSecond) {
+  // Although the tests use a mock clock, the UKM aggregator checks if the
+  // system has a high resolution clock before recording results. As a result,
+  // the tests will fail if the system does not have a high resolution clock.
+  if (!base::TimeTicks::IsHighResolution())
+    return;
+
+  // Have 100 events 999ms each; The records should be recorded once every 30
+  // seconds. The total run time is 99.9 seconds, so we should expect 3 events:
+  // 0-30 sec, 30-60 sec, 60-90 sec.
+  for (int i = 0; i < 100; ++i) {
+    {
+      auto timer = aggregator().GetScopedTimer(i % 2);
+      clock().Advance(TimeDelta::FromMilliseconds(999));
+    }
+    aggregator().RecordPrimarySample(base::TimeTicks(), Now());
+  }
+
+  EXPECT_EQ(recorder().entries_count(), 3u);
+
+  // Once we reset, we record any remaining samples into one more entry, for a
+  // total of 4.
+  ResetAggregator();
+
+  EXPECT_EQ(recorder().entries_count(), 4u);
+  auto entries = recorder().GetEntriesByName("Blink.UpdateTime");
+  EXPECT_EQ(entries.size(), 4u);
+
+  for (auto* entry : entries) {
+    EXPECT_TRUE(
+        ukm::TestUkmRecorder::EntryHasMetric(entry, GetAverageMetricName(0)));
+    const int64_t* metric1_average =
+        ukm::TestUkmRecorder::GetEntryMetric(entry, GetAverageMetricName(0));
+    EXPECT_NEAR(*metric1_average / 1e6, 0.999, 0.0001);
+
+    EXPECT_TRUE(
+        ukm::TestUkmRecorder::EntryHasMetric(entry, GetWorstCaseMetricName(0)));
+    const int64_t* metric1_worst =
+        ukm::TestUkmRecorder::GetEntryMetric(entry, GetWorstCaseMetricName(0));
+    EXPECT_NEAR(*metric1_worst / 1e6, 0.999, 0.0001);
+
+    EXPECT_TRUE(
+        ukm::TestUkmRecorder::EntryHasMetric(entry, GetAverageMetricName(1)));
+    const int64_t* metric2_average =
+        ukm::TestUkmRecorder::GetEntryMetric(entry, GetAverageMetricName(1));
+    EXPECT_NEAR(*metric2_average / 1e6, 0.999, 0.0001);
+
+    EXPECT_TRUE(
+        ukm::TestUkmRecorder::EntryHasMetric(entry, GetWorstCaseMetricName(1)));
+    const int64_t* metric2_worst =
+        ukm::TestUkmRecorder::GetEntryMetric(entry, GetWorstCaseMetricName(1));
+    EXPECT_NEAR(*metric2_worst / 1e6, 0.999, 0.0001);
+  }
+}
+
+TEST_F(LocalFrameUkmAggregatorTest, EventsAveragedCorrectly) {
+  // Although the tests use a mock clock, the UKM aggregator checks if the
+  // system has a high resolution clock before recording results. As a result,
+  // the tests will fail if the system does not have a high resolution clock.
+  if (!base::TimeTicks::IsHighResolution())
+    return;
+
+  // 1, 2, and 3 seconds.
+  for (int i = 1; i <= 3; ++i) {
+    {
+      auto timer = aggregator().GetScopedTimer(0);
+      clock().Advance(TimeDelta::FromSeconds(i));
+    }
+  }
+
+  // 3, 3, 3, and then 1 outside of the loop.
+  for (int i = 0; i < 3; ++i) {
+    auto timer = aggregator().GetScopedTimer(1);
+    clock().Advance(TimeDelta::FromSeconds(3));
+  }
+  {
+    auto timer = aggregator().GetScopedTimer(1);
+    clock().Advance(TimeDelta::FromSeconds(1));
+  }
+
+  aggregator().RecordPrimarySample(
+      base::TimeTicks(),
+      base::TimeTicks() + base::TimeDelta::FromSecondsD(120));
+
+  ResetAggregator();
+  auto entries = recorder().GetEntriesByName("Blink.UpdateTime");
+  EXPECT_EQ(entries.size(), 1u);
+  auto* entry = entries[0];
+
+  EXPECT_TRUE(
+      ukm::TestUkmRecorder::EntryHasMetric(entry, GetAverageMetricName(0)));
+  const int64_t* metric1_average =
+      ukm::TestUkmRecorder::GetEntryMetric(entry, GetAverageMetricName(0));
+  // metric1 (1, 2, 3) average is 2
+  EXPECT_NEAR(*metric1_average / 1e6, 2.0, 0.0001);
+
+  EXPECT_TRUE(
+      ukm::TestUkmRecorder::EntryHasMetric(entry, GetWorstCaseMetricName(0)));
+  const int64_t* metric1_worst =
+      ukm::TestUkmRecorder::GetEntryMetric(entry, GetWorstCaseMetricName(0));
+  // metric1 (1, 2, 3) worst case is 3
+  EXPECT_NEAR(*metric1_worst / 1e6, 3.0, 0.0001);
+
+  EXPECT_TRUE(
+      ukm::TestUkmRecorder::EntryHasMetric(entry, GetAverageMetricName(1)));
+  const int64_t* metric2_average =
+      ukm::TestUkmRecorder::GetEntryMetric(entry, GetAverageMetricName(1));
+  // metric1 (3, 3, 3, 1) average is 2.5
+  EXPECT_NEAR(*metric2_average / 1e6, 2.5, 0.0001);
+
+  EXPECT_TRUE(
+      ukm::TestUkmRecorder::EntryHasMetric(entry, GetWorstCaseMetricName(1)));
+  const int64_t* metric2_worst =
+      ukm::TestUkmRecorder::GetEntryMetric(entry, GetWorstCaseMetricName(1));
+  // metric1 (3, 3, 3, 1) worst case is 3
+  EXPECT_NEAR(*metric2_worst / 1e6, 3.0, 0.0001);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc
index 74654ed..d7520c1 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc
+++ b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc
@@ -15,6 +15,7 @@
 #include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h"
 #include "third_party/blink/renderer/platform/cross_thread_functional.h"
 #include "third_party/blink/renderer/platform/graphics/image_data_buffer.h"
+#include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
 #include "third_party/blink/renderer/platform/histogram.h"
 #include "third_party/blink/renderer/platform/image-encoders/image_encoder_utils.h"
 #include "third_party/blink/renderer/platform/scheduler/public/background_scheduler.h"
@@ -192,17 +193,11 @@
   sk_sp<SkImage> skia_image = image_->PaintImageForCurrentFrame().GetSkImage();
   DCHECK(skia_image);
 
-  // If image is lazy decoded, we can either draw it on a canvas or
-  // call readPixels() to trigger decoding. We expect drawing on a very small
-  // canvas to be faster than readPixels().
+  // If image is lazy decoded, call readPixels() to trigger decoding.
   if (skia_image->isLazyGenerated()) {
-    SkImageInfo info = SkImageInfo::MakeN32(1, 1, skia_image->alphaType());
-    sk_sp<SkSurface> surface = SkSurface::MakeRaster(info);
-    if (surface) {
-      SkPaint paint;
-      paint.setBlendMode(SkBlendMode::kSrc);
-      surface->getCanvas()->drawImage(skia_image.get(), 0, 0, &paint);
-    }
+    SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
+    uint8_t pixel[info.bytesPerPixel()];
+    skia_image->readPixels(info, pixel, info.minRowBytes(), 0, 0);
   }
 
   // For kHTMLCanvasToBlobCallback and kOffscreenCanvasConvertToBlobPromise
@@ -224,46 +219,39 @@
   } else {
     sk_sp<SkColorSpace> blob_color_space =
         BlobColorSpaceToSkColorSpace(encode_options_.colorSpace());
-
-    if (!SkColorSpace::Equals(skia_image->colorSpace(),
-                              blob_color_space.get())) {
-      if (!skia_image->colorSpace()) {
-        skia_image->peekPixels(&src_data_);
-        src_data_.setColorSpace(SkColorSpace::MakeSRGB());
-        skia_image = SkImage::MakeFromRaster(src_data_, nullptr, nullptr);
-      }
+    bool needs_color_space_conversion = !ApproximatelyEqualSkColorSpaces(
+        skia_image->refColorSpace(), blob_color_space);
+    if (needs_color_space_conversion && !skia_image->colorSpace()) {
+      skia_image->peekPixels(&src_data_);
+      src_data_.setColorSpace(SkColorSpace::MakeSRGB());
+      skia_image = SkImage::MakeFromRaster(src_data_, nullptr, nullptr);
       DCHECK(skia_image->colorSpace());
+    }
+
+    SkColorType target_color_type = kN32_SkColorType;
+    if (encode_options_.pixelFormat() == kRGBA16ImagePixelFormatName)
+      target_color_type = kRGBA_F16_SkColorType;
+    // We can do color space and color type conversion together.
+    if (needs_color_space_conversion) {
       image_ = StaticBitmapImage::Create(skia_image);
-      image_ = image_->ConvertToColorSpace(blob_color_space,
-                                           skia_image->colorType());
+      image_ = image_->ConvertToColorSpace(blob_color_space, target_color_type);
       skia_image = image_->PaintImageForCurrentFrame().GetSkImage();
+    } else if (skia_image->colorType() != target_color_type) {
+      size_t data_length = skia_image->width() * skia_image->height() *
+                           SkColorTypeBytesPerPixel(target_color_type);
+      png_data_helper_ = SkData::MakeUninitialized(data_length);
+      SkImageInfo info = SkImageInfo::Make(
+          skia_image->width(), skia_image->height(), target_color_type,
+          skia_image->alphaType(), skia_image->refColorSpace());
+      SkPixmap src_data_f16(info, png_data_helper_->writable_data(),
+                            info.minRowBytes());
+      skia_image->readPixels(src_data_f16, 0, 0);
+      skia_image = SkImage::MakeFromRaster(src_data_f16, nullptr, nullptr);
+      image_ = StaticBitmapImage::Create(skia_image);
     }
 
-    if (skia_image->peekPixels(&src_data_)) {
+    if (skia_image->peekPixels(&src_data_))
       static_bitmap_image_loaded_ = true;
-
-      // If the source image is 8 bit per channel but the blob is requested in
-      // 16 bpc PNG, we need to ensure the color type of the pixmap is
-      // kRGBA_F16_SkColorType to kick in 16 bit encoding in SkPngEncoder. Since
-      // SkPixmap only holds a pointer to data, we need a helper data member
-      // here.
-      if (mime_type_ == kMimeTypePng &&
-          encode_options_.pixelFormat() == kRGBA16ImagePixelFormatName &&
-          src_data_.colorType() == kN32_SkColorType) {
-        size_t data_length = src_data_.width() * src_data_.height() *
-                             SkColorTypeBytesPerPixel(kRGBA_F16_SkColorType);
-        png_16bit_data_helper_ = SkData::MakeUninitialized(data_length);
-        SkImageInfo info = SkImageInfo::Make(
-            src_data_.width(), src_data_.height(), kRGBA_F16_SkColorType,
-            src_data_.alphaType(), src_data_.info().refColorSpace());
-        SkPixmap src_data_f16(info, png_16bit_data_helper_->data(),
-                              info.minRowBytes());
-        src_data_.readPixels(src_data_f16);
-        src_data_ = src_data_f16;
-        skia_image = SkImage::MakeFromRaster(src_data_, nullptr, nullptr);
-        image_ = StaticBitmapImage::Create(skia_image);
-      }
-    }
   }
 
   if (static_bitmap_image_loaded_) {
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.h b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.h
index d6fccdbe..d191b36 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.h
+++ b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.h
@@ -128,7 +128,7 @@
   ImageEncodingMimeType mime_type_;
   const ImageEncodeOptions encode_options_;
   ToBlobFunctionType function_type_;
-  sk_sp<SkData> png_16bit_data_helper_;
+  sk_sp<SkData> png_data_helper_;
 
   // Chrome metrics use
   TimeTicks start_time_;
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator_test.cc b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator_test.cc
index bc915b3..e539e23 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator_test.cc
+++ b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator_test.cc
@@ -10,7 +10,7 @@
 #include "third_party/blink/renderer/core/html/canvas/image_data.h"
 #include "third_party/blink/renderer/core/testing/page_test_base.h"
 #include "third_party/blink/renderer/platform/graphics/color_correction_test_utils.h"
-#include "third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h"
+#include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 #include "third_party/skia/include/core/SkSurface.h"
@@ -255,15 +255,12 @@
   std::list<String> blob_color_spaces = {kSRGBImageColorSpaceName,
                                          kDisplayP3ImageColorSpaceName,
                                          kRec2020ImageColorSpaceName};
-  // SkPngEncoder still does not support 16bit PNG encoding. Add
-  // kRGBA16ImagePixelFormatName to blob_pixel_formats when this is fixed.
-  // crbug.com/840372
-  // bugs.chromium.org/p/skia/issues/detail?id=7926
-  // https://fiddle.skia.org/c/b795f0141f4e1a5773bf9494b5bc87b5
-  std::list<String> blob_pixel_formats = {kRGBA8ImagePixelFormatName};
+  std::list<String> blob_pixel_formats = {
+      kRGBA8ImagePixelFormatName, kRGBA16ImagePixelFormatName,
+  };
 
-  // The maximum difference locally observed is 3.
-  const unsigned uint8_color_tolerance = 5;
+  // The maximum difference locally observed is 2.
+  const unsigned uint8_color_tolerance = 2;
   const float f16_color_tolerance = 0.01;
 
   for (auto color_space_param : color_space_params) {
@@ -272,8 +269,8 @@
         for (auto blob_pixel_format : blob_pixel_formats) {
           // Create the StaticBitmapImage in canvas_color_space
           sk_sp<SkImage> source_image = DrawAndReturnImage(color_space_param);
-          scoped_refptr<UnacceleratedStaticBitmapImage> source_bitmap_image =
-              UnacceleratedStaticBitmapImage::Create(source_image);
+          scoped_refptr<StaticBitmapImage> source_bitmap_image =
+              StaticBitmapImage::Create(source_image);
 
           // Prepare encoding options
           ImageEncodeOptions options;
@@ -296,9 +293,18 @@
               async_blob_creator->GetEncodedImageForConvertToBlobTest().size());
           sk_sp<SkImage> decoded_img = SkImage::MakeFromEncoded(sk_data);
 
-          sk_sp<SkImage> ref_image = source_image->makeColorSpace(
+          sk_sp<SkColorSpace> expected_color_space =
               CanvasAsyncBlobCreator::BlobColorSpaceToSkColorSpace(
-                  blob_color_space));
+                  blob_color_space);
+          SkColorType expected_color_type =
+              (blob_pixel_format == kRGBA8ImagePixelFormatName)
+                  ? kN32_SkColorType
+                  : kRGBA_F16_SkColorType;
+          scoped_refptr<StaticBitmapImage> ref_bitmap =
+              source_bitmap_image->ConvertToColorSpace(expected_color_space,
+                                                       expected_color_type);
+          sk_sp<SkImage> ref_image =
+              ref_bitmap->PaintImageForCurrentFrame().GetSkImage();
 
           // Jpeg does not support transparent images.
           bool compare_alpha = (blob_mime_type != "image/jpeg");
diff --git a/third_party/blink/renderer/core/html/parser/xss_auditor_delegate.cc b/third_party/blink/renderer/core/html/parser/xss_auditor_delegate.cc
index 81968c8..609c93215 100644
--- a/third_party/blink/renderer/core/html/parser/xss_auditor_delegate.cc
+++ b/third_party/blink/renderer/core/html/parser/xss_auditor_delegate.cc
@@ -116,9 +116,6 @@
   if (!did_send_notifications_ && local_frame->Client()) {
     did_send_notifications_ = true;
 
-    local_frame->Client()->DidDetectXSS(document_->Url(),
-                                        xss_info.did_block_entire_page_);
-
     if (!report_url_.IsEmpty())
       PingLoader::SendViolationReport(local_frame, report_url_,
                                       GenerateViolationReport(xss_info),
diff --git a/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc b/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
index da61f2c..817d529 100644
--- a/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
@@ -411,6 +411,10 @@
   return IsHorizontalFlow(*style_);
 }
 
+bool FlexLayoutAlgorithm::IsColumnFlow() const {
+  return StyleRef().IsColumnFlexDirection();
+}
+
 bool FlexLayoutAlgorithm::IsHorizontalFlow(const ComputedStyle& style) {
   if (style.IsHorizontalWritingMode())
     return !style.IsColumnFlexDirection();
@@ -437,6 +441,19 @@
   return kNormalBehavior;
 }
 
+bool FlexLayoutAlgorithm::ShouldApplyMinSizeAutoForChild(
+    const LayoutBox& child) const {
+  // TODO(cbiesinger): For now, we do not handle min-height: auto for nested
+  // column flexboxes. See crbug.com/596743
+  // css-flexbox section 4.5
+
+  Length min = IsHorizontalFlow() ? child.StyleRef().MinWidth()
+                                  : child.StyleRef().MinHeight();
+  return min.IsAuto() && !child.ShouldApplySizeContainment() &&
+         MainAxisOverflowForChild(child) == EOverflow::kVisible &&
+         !(IsColumnFlow() && child.IsFlexibleBox());
+}
+
 TransformedWritingMode FlexLayoutAlgorithm::GetTransformedWritingMode() const {
   return GetTransformedWritingMode(*style_);
 }
@@ -563,4 +580,11 @@
   return LayoutUnit();
 }
 
+EOverflow FlexLayoutAlgorithm::MainAxisOverflowForChild(
+    const LayoutBox& child) const {
+  if (IsHorizontalFlow())
+    return child.StyleRef().OverflowX();
+  return child.StyleRef().OverflowY();
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/flexible_box_algorithm.h b/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
index bae8b0f..e3390e9 100644
--- a/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
+++ b/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
@@ -283,10 +283,13 @@
   FlexLine* ComputeNextFlexLine(LayoutUnit container_logical_width);
 
   bool IsHorizontalFlow() const;
+  bool IsColumnFlow() const;
   static bool IsHorizontalFlow(const ComputedStyle&);
   bool IsLeftToRightFlow() const;
   TransformedWritingMode GetTransformedWritingMode() const;
 
+  bool ShouldApplyMinSizeAutoForChild(const LayoutBox& child) const;
+
   static TransformedWritingMode GetTransformedWritingMode(const ComputedStyle&);
 
   static const StyleContentAlignmentData& ContentAlignmentNormalBehavior();
@@ -305,6 +308,7 @@
       unsigned number_of_items);
 
  private:
+  EOverflow MainAxisOverflowForChild(const LayoutBox& child) const;
   bool IsMultiline() const { return style_->FlexWrap() != EFlexWrap::kNowrap; }
 
   const ComputedStyle* style_;
diff --git a/third_party/blink/renderer/core/layout/layout_flexible_box.cc b/third_party/blink/renderer/core/layout/layout_flexible_box.cc
index c24084b..0922fc49 100644
--- a/third_party/blink/renderer/core/layout/layout_flexible_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_flexible_box.cc
@@ -829,7 +829,7 @@
       continue;
     }
 
-    flex_algorithm.emplace_back(ConstructFlexItem(*child, layout_type));
+    ConstructAndAppendFlexItem(&flex_algorithm, *child, layout_type);
   }
 
   LayoutUnit cross_axis_offset = FlowAwareContentInsetBefore();
@@ -977,6 +977,7 @@
 
 DISABLE_CFI_PERF
 MinMaxSize LayoutFlexibleBox::ComputeMinAndMaxSizesForChild(
+    const FlexLayoutAlgorithm& algorithm,
     const LayoutBox& child) const {
   MinMaxSize sizes{LayoutUnit(), LayoutUnit::Max()};
 
@@ -996,14 +997,7 @@
     // computeMainAxisExtentForChild can return -1 when the child has a
     // percentage min size, but we have an indefinite size in that axis.
     sizes.min_size = std::max(LayoutUnit(), sizes.min_size);
-  } else if (min.IsAuto() && !child.ShouldApplySizeContainment() &&
-             MainAxisOverflowForChild(child) == EOverflow::kVisible &&
-             !(IsColumnFlow() && child.IsFlexibleBox())) {
-    // TODO(cbiesinger): For now, we do not handle min-height: auto for nested
-    // column flexboxes. We need to implement
-    // https://drafts.csswg.org/css-flexbox/#intrinsic-sizes before that
-    // produces reasonable results. Tracking bug: https://crbug.com/581553
-    // css-flexbox section 4.5
+  } else if (algorithm.ShouldApplyMinSizeAutoForChild(child)) {
     LayoutUnit content_size =
         ComputeMainAxisExtentForChild(child, kMinSize, Length(kMinContent));
     DCHECK_GE(content_size, LayoutUnit());
@@ -1121,8 +1115,10 @@
 }
 
 DISABLE_CFI_PERF
-FlexItem LayoutFlexibleBox::ConstructFlexItem(LayoutBox& child,
-                                              ChildLayoutType layout_type) {
+void LayoutFlexibleBox::ConstructAndAppendFlexItem(
+    FlexLayoutAlgorithm* algorithm,
+    LayoutBox& child,
+    ChildLayoutType layout_type) {
   if (layout_type != kNeverLayout && ChildHasIntrinsicMainAxisSize(child)) {
     // If this condition is true, then ComputeMainAxisExtentForChild will call
     // child.IntrinsicContentLogicalHeight() and
@@ -1142,7 +1138,7 @@
     }
   }
 
-  MinMaxSize sizes = ComputeMinAndMaxSizesForChild(child);
+  MinMaxSize sizes = ComputeMinAndMaxSizesForChild(*algorithm, child);
 
   LayoutUnit border_and_padding = IsHorizontalFlow()
                                       ? child.BorderAndPaddingWidth()
@@ -1151,8 +1147,8 @@
       ComputeInnerFlexBaseSizeForChild(child, border_and_padding, layout_type);
   LayoutUnit margin =
       IsHorizontalFlow() ? child.MarginWidth() : child.MarginHeight();
-  return FlexItem(&child, child_inner_flex_base_size, sizes, border_and_padding,
-                  margin);
+  algorithm->emplace_back(&child, child_inner_flex_base_size, sizes,
+                          border_and_padding, margin);
 }
 
 static LayoutUnit AlignmentOffset(LayoutUnit available_free_space,
@@ -1345,13 +1341,6 @@
   return result;
 }
 
-EOverflow LayoutFlexibleBox::MainAxisOverflowForChild(
-    const LayoutBox& child) const {
-  if (IsHorizontalFlow())
-    return child.StyleRef().OverflowX();
-  return child.StyleRef().OverflowY();
-}
-
 EOverflow LayoutFlexibleBox::CrossAxisOverflowForChild(
     const LayoutBox& child) const {
   if (IsHorizontalFlow())
diff --git a/third_party/blink/renderer/core/layout/layout_flexible_box.h b/third_party/blink/renderer/core/layout/layout_flexible_box.h
index a2eb5329..4870be7 100644
--- a/third_party/blink/renderer/core/layout/layout_flexible_box.h
+++ b/third_party/blink/renderer/core/layout/layout_flexible_box.h
@@ -39,6 +39,7 @@
 
 class FlexItem;
 class FlexItemVectorView;
+class FlexLayoutAlgorithm;
 class FlexLine;
 struct MinMaxSize;
 
@@ -166,11 +167,14 @@
 
   LayoutUnit ComputeChildMarginValue(Length margin);
   void PrepareOrderIteratorAndMargins();
-  MinMaxSize ComputeMinAndMaxSizesForChild(const LayoutBox& child) const;
+  MinMaxSize ComputeMinAndMaxSizesForChild(const FlexLayoutAlgorithm& algorithm,
+                                           const LayoutBox& child) const;
   LayoutUnit AdjustChildSizeForAspectRatioCrossAxisMinAndMax(
       const LayoutBox& child,
       LayoutUnit child_size) const;
-  FlexItem ConstructFlexItem(LayoutBox& child, ChildLayoutType);
+  void ConstructAndAppendFlexItem(FlexLayoutAlgorithm* algorithm,
+                                  LayoutBox& child,
+                                  ChildLayoutType);
 
   bool ResolveFlexibleLengths(FlexLine*,
                               LayoutUnit initial_free_space,
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc
index cffcb1a..387ad8d 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc
@@ -98,7 +98,9 @@
 }
 
 void LayoutNGBlockFlow::UpdateOutOfFlowBlockLayout() {
-  LayoutBlock* container = ContainingBlock();
+  LayoutBoxModelObject* css_container = ToLayoutBoxModelObject(Container());
+  LayoutBox* container =
+      css_container->IsBox() ? ToLayoutBox(css_container) : ContainingBlock();
   const ComputedStyle* container_style = container->Style();
   const ComputedStyle* parent_style = Parent()->Style();
   NGConstraintSpace constraint_space =
@@ -148,7 +150,6 @@
 
   // Calculate the actual size of the containing block for this out-of-flow
   // descendant. This is what's used to size and position us.
-  LayoutBoxModelObject* css_container = ToLayoutBoxModelObject(Container());
   LayoutUnit containing_block_logical_width =
       ContainingBlockLogicalWidthForPositioned(css_container);
   LayoutUnit containing_block_logical_height =
diff --git a/third_party/blink/renderer/core/loader/empty_clients.h b/third_party/blink/renderer/core/loader/empty_clients.h
index cec382ce..63e1b57 100644
--- a/third_party/blink/renderer/core/loader/empty_clients.h
+++ b/third_party/blink/renderer/core/loader/empty_clients.h
@@ -314,7 +314,6 @@
   void DidDisplayInsecureContent() override {}
   void DidContainInsecureFormAction() override {}
   void DidRunInsecureContent(const SecurityOrigin*, const KURL&) override {}
-  void DidDetectXSS(const KURL&, bool) override {}
   void DidDispatchPingLoader(const KURL&) override {}
   void DidDisplayContentWithCertificateErrors() override {}
   void DidRunContentWithCertificateErrors() override {}
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.cc b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
index a0992e4..dacc48b 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
@@ -436,6 +436,14 @@
   }
 
   if (GetLocalFrameClient()->GetPreviewsStateForFrame() &
+      WebURLRequest::kResourceLoadingHintsOn) {
+    request.AddHTTPHeaderField(
+        "Intervention",
+        "<https://www.chromestatus.com/features/4510564810227712>; "
+        "level=\"warning\"");
+  }
+
+  if (GetLocalFrameClient()->GetPreviewsStateForFrame() &
       WebURLRequest::kClientLoFiOn) {
     request.AddHTTPHeaderField(
         "Intervention",
diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc
index 880ce05..5f7728b 100644
--- a/third_party/blink/renderer/core/loader/frame_loader.cc
+++ b/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -1502,7 +1502,8 @@
     IgnoreOpensDuringUnloadCountIncrementer ignore_opens_during_unload(
         frame_->GetDocument());
     if (!frame_->GetDocument()->DispatchBeforeUnloadEvent(
-            page->GetChromeClient(), is_reload, did_allow_navigation))
+            page->GetChromeClient(), is_reload, false /* auto_cancel */,
+            did_allow_navigation))
       return false;
 
     // Then deal with descendent frames.
@@ -1523,7 +1524,8 @@
           ignore_opens_during_unload_descendant(
               descendant_frame->GetDocument());
       if (!descendant_frame->GetDocument()->DispatchBeforeUnloadEvent(
-              page->GetChromeClient(), is_reload, did_allow_navigation))
+              page->GetChromeClient(), is_reload, false /* auto_cancel */,
+              did_allow_navigation))
         return false;
     }
   }
diff --git a/third_party/blink/renderer/devtools/front_end/elements/StylesSidebarPane.js b/third_party/blink/renderer/devtools/front_end/elements/StylesSidebarPane.js
index 36b0565..c0eeb86 100644
--- a/third_party/blink/renderer/devtools/front_end/elements/StylesSidebarPane.js
+++ b/third_party/blink/renderer/devtools/front_end/elements/StylesSidebarPane.js
@@ -1639,6 +1639,8 @@
       event.consume(true);
       return;
     }
+    if (this.element.hasSelection())
+      return;
     this._startEditingAtFirstPosition();
     event.consume(true);
   }
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.h b/third_party/blink/renderer/modules/accessibility/ax_node_object.h
index 71b6b907..400c2b9 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_node_object.h
+++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.h
@@ -61,8 +61,6 @@
   const AXObject* InheritsPresentationalRoleFrom() const override;
   ax::mojom::Role DetermineAccessibilityRole() override;
   virtual ax::mojom::Role NativeRoleIgnoringAria() const;
-  String AccessibilityDescriptionForElements(
-      HeapVector<Member<Element>>& elements) const;
   void AlterSliderOrSpinButtonValue(bool increase);
   AXObject* ActiveDescendant() override;
   String AriaAccessibilityDescription() const;
diff --git a/third_party/blink/renderer/modules/payments/payment_request.cc b/third_party/blink/renderer/modules/payments/payment_request.cc
index da63e69b..4c50b44 100644
--- a/third_party/blink/renderer/modules/payments/payment_request.cc
+++ b/third_party/blink/renderer/modules/payments/payment_request.cc
@@ -56,6 +56,7 @@
 #include "third_party/blink/renderer/platform/mojo/mojo_helper.h"
 #include "third_party/blink/renderer/platform/uuid.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
 #include "third_party/blink/renderer/platform/wtf/hash_set.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 
@@ -539,6 +540,10 @@
 bool IsValidMethodFormat(const String& identifier) {
   KURL url(NullURL(), identifier);
   if (url.IsValid()) {
+    // Allow localhost payment method for test.
+    if (SecurityOrigin::Create(url)->IsLocalhost())
+      return true;
+
     // URL PMI validation rules:
     // https://www.w3.org/TR/payment-method-id/#dfn-validate-a-url-based-payment-method-identifier
     return url.Protocol() == "https" && url.User().IsEmpty() &&
diff --git a/third_party/blink/renderer/modules/speech/speech_recognition.cc b/third_party/blink/renderer/modules/speech/speech_recognition.cc
index 0b3927ad..5047cac2 100644
--- a/third_party/blink/renderer/modules/speech/speech_recognition.cc
+++ b/third_party/blink/renderer/modules/speech/speech_recognition.cc
@@ -93,7 +93,7 @@
   auto* it = std::stable_partition(
       results.begin(), results.end(),
       [](const auto& result) { return !result->is_provisional; });
-  size_t provisional_count = results.end() - it;
+  wtf_size_t provisional_count = static_cast<wtf_size_t>(results.end() - it);
 
   // Add the new results to the previous final results.
   HeapVector<Member<SpeechRecognitionResult>> aggregated_results =
diff --git a/third_party/blink/renderer/modules/speech/speech_recognition.h b/third_party/blink/renderer/modules/speech/speech_recognition.h
index b4e08c6..ed6259e 100644
--- a/third_party/blink/renderer/modules/speech/speech_recognition.h
+++ b/third_party/blink/renderer/modules/speech/speech_recognition.h
@@ -129,7 +129,7 @@
   String lang_;
   bool continuous_;
   bool interim_results_;
-  unsigned long max_alternatives_;
+  uint32_t max_alternatives_;
 
   Member<SpeechRecognitionController> controller_;
   bool started_;
diff --git a/third_party/blink/renderer/modules/speech/speech_recognition_controller.cc b/third_party/blink/renderer/modules/speech/speech_recognition_controller.cc
index 6bd603d..c16ed49 100644
--- a/third_party/blink/renderer/modules/speech/speech_recognition_controller.cc
+++ b/third_party/blink/renderer/modules/speech/speech_recognition_controller.cc
@@ -56,7 +56,7 @@
     const String& lang,
     bool continuous,
     bool interim_results,
-    unsigned long max_alternatives) {
+    uint32_t max_alternatives) {
   mojom::blink::StartSpeechRecognitionRequestParamsPtr msg_params =
       mojom::blink::StartSpeechRecognitionRequestParams::New();
   for (unsigned i = 0; i < grammars.length(); i++) {
diff --git a/third_party/blink/renderer/modules/speech/speech_recognition_controller.h b/third_party/blink/renderer/modules/speech/speech_recognition_controller.h
index 1f98f35..06c4c2a9 100644
--- a/third_party/blink/renderer/modules/speech/speech_recognition_controller.h
+++ b/third_party/blink/renderer/modules/speech/speech_recognition_controller.h
@@ -52,7 +52,7 @@
              const String& lang,
              bool continuous,
              bool interim_results,
-             unsigned long max_alternatives);
+             uint32_t max_alternatives);
 
   static SpeechRecognitionController* Create(LocalFrame& frame);
   static SpeechRecognitionController* From(LocalFrame* frame) {
diff --git a/third_party/blink/renderer/modules/speech/speech_recognition_event.cc b/third_party/blink/renderer/modules/speech/speech_recognition_event.cc
index 8c77fcd..5236cc5e 100644
--- a/third_party/blink/renderer/modules/speech/speech_recognition_event.cc
+++ b/third_party/blink/renderer/modules/speech/speech_recognition_event.cc
@@ -36,7 +36,7 @@
 }
 
 SpeechRecognitionEvent* SpeechRecognitionEvent::CreateResult(
-    unsigned long result_index,
+    uint32_t result_index,
     const HeapVector<Member<SpeechRecognitionResult>>& results) {
   return new SpeechRecognitionEvent(
       EventTypeNames::result, result_index,
@@ -72,7 +72,7 @@
 
 SpeechRecognitionEvent::SpeechRecognitionEvent(
     const AtomicString& event_name,
-    unsigned long result_index,
+    uint32_t result_index,
     SpeechRecognitionResultList* results)
     : Event(event_name, Bubbles::kNo, Cancelable::kNo),
       result_index_(result_index),
diff --git a/third_party/blink/renderer/modules/speech/speech_recognition_event.h b/third_party/blink/renderer/modules/speech/speech_recognition_event.h
index 7348f04..5bf5b563 100644
--- a/third_party/blink/renderer/modules/speech/speech_recognition_event.h
+++ b/third_party/blink/renderer/modules/speech/speech_recognition_event.h
@@ -45,11 +45,11 @@
   ~SpeechRecognitionEvent() override;
 
   static SpeechRecognitionEvent* CreateResult(
-      unsigned long result_index,
+      uint32_t result_index,
       const HeapVector<Member<SpeechRecognitionResult>>& results);
   static SpeechRecognitionEvent* CreateNoMatch(SpeechRecognitionResult*);
 
-  unsigned long resultIndex() const { return result_index_; }
+  uint32_t resultIndex() const { return result_index_; }
   SpeechRecognitionResultList* results() const { return results_; }
 
   // These two methods are here to satisfy the specification which requires
@@ -66,10 +66,10 @@
   SpeechRecognitionEvent(const AtomicString&,
                          const SpeechRecognitionEventInit&);
   SpeechRecognitionEvent(const AtomicString& event_name,
-                         unsigned long result_index,
+                         uint32_t result_index,
                          SpeechRecognitionResultList* results);
 
-  unsigned long result_index_;
+  uint32_t result_index_;
   Member<SpeechRecognitionResultList> results_;
 };
 
diff --git a/third_party/blink/renderer/modules/speech/speech_synthesis.cc b/third_party/blink/renderer/modules/speech/speech_synthesis.cc
index b0c6670..c86e56d 100644
--- a/third_party/blink/renderer/modules/speech/speech_synthesis.cc
+++ b/third_party/blink/renderer/modules/speech/speech_synthesis.cc
@@ -70,9 +70,8 @@
   // platform again.
   const Vector<scoped_refptr<PlatformSpeechSynthesisVoice>>& platform_voices =
       platform_speech_synthesizer_->GetVoiceList();
-  size_t voice_count = platform_voices.size();
-  for (size_t k = 0; k < voice_count; k++)
-    voice_list_.push_back(SpeechSynthesisVoice::Create(platform_voices[k]));
+  for (auto voice : platform_voices)
+    voice_list_.push_back(SpeechSynthesisVoice::Create(voice));
 
   return voice_list_;
 }
@@ -153,7 +152,7 @@
 
 void SpeechSynthesis::FireEvent(const AtomicString& type,
                                 SpeechSynthesisUtterance* utterance,
-                                unsigned long char_index,
+                                uint32_t char_index,
                                 const String& name) {
   double millis;
   if (!GetElapsedTimeMillis(&millis))
diff --git a/third_party/blink/renderer/modules/speech/speech_synthesis.h b/third_party/blink/renderer/modules/speech/speech_synthesis.h
index ff767def..850407da 100644
--- a/third_party/blink/renderer/modules/speech/speech_synthesis.h
+++ b/third_party/blink/renderer/modules/speech/speech_synthesis.h
@@ -89,7 +89,7 @@
   void HandleSpeakingCompleted(SpeechSynthesisUtterance*, bool error_occurred);
   void FireEvent(const AtomicString& type,
                  SpeechSynthesisUtterance*,
-                 unsigned long char_index,
+                 uint32_t char_index,
                  const String& name);
 
   void FireErrorEvent(SpeechSynthesisUtterance*,
diff --git a/third_party/blink/renderer/modules/vr/vr_display.h b/third_party/blink/renderer/modules/vr/vr_display.h
index de85257e..429ac4e 100644
--- a/third_party/blink/renderer/modules/vr/vr_display.h
+++ b/third_party/blink/renderer/modules/vr/vr_display.h
@@ -265,21 +265,28 @@
 
 using VRDisplayVector = HeapVector<Member<VRDisplay>>;
 
+// When adding values, insert them before Max and add them to
+// VRPresentationResult in enums.xml. Do not reuse values.
+// Also, remove kPlaceholderForPreviousHighValue.
+// When values become obsolete, comment them out here and mark them deprecated
+// in enums.xml.
 enum class PresentationResult {
   kRequested = 0,
   kSuccess = 1,
   kSuccessAlreadyPresenting = 2,
   kVRDisplayCannotPresent = 3,
   kPresentationNotSupportedByDisplay = 4,
-  kVRDisplayNotFound = 5,
+  // kVRDisplayNotFound = 5,
   kNotInitiatedByUserGesture = 6,
   kInvalidNumberOfLayers = 7,
   kInvalidLayerSource = 8,
   kLayerSourceMissingWebGLContext = 9,
   kInvalidLayerBounds = 10,
-  kServiceInactive = 11,
-  kRequestDenied = 12,
-  kFullscreenNotEnabled = 13,
+  // kServiceInactive = 11,
+  // kRequestDenied = 12,
+  // kFullscreenNotEnabled = 13,
+  // TODO(ddorwin): Remove this placeholder when adding a new value.
+  kPlaceholderForPreviousHighValue = 13,
   kPresentationResultMax,  // Must be last member of enum.
 };
 
diff --git a/third_party/blink/renderer/modules/websockets/dom_websocket.cc b/third_party/blink/renderer/modules/websockets/dom_websocket.cc
index 76458a4..489e7379 100644
--- a/third_party/blink/renderer/modules/websockets/dom_websocket.cc
+++ b/third_party/blink/renderer/modules/websockets/dom_websocket.cc
@@ -30,7 +30,9 @@
 
 #include "third_party/blink/renderer/modules/websockets/dom_websocket.h"
 
+#include "base/feature_list.h"
 #include "base/location.h"
+#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/task_type.h"
 #include "third_party/blink/public/platform/web_insecure_request_policy.h"
@@ -47,6 +49,7 @@
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/use_counter.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
+#include "third_party/blink/renderer/core/loader/mixed_content_checker.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h"
 #include "third_party/blink/renderer/modules/websockets/close_event.h"
@@ -292,8 +295,11 @@
   NETWORK_DVLOG(1) << "WebSocket " << this << " connect() url=" << url;
   url_ = KURL(NullURL(), url);
 
-  if (GetExecutionContext()->GetSecurityContext().GetInsecureRequestPolicy() &
-          kUpgradeInsecureRequests &&
+  if ((GetExecutionContext()->GetSecurityContext().GetInsecureRequestPolicy() &
+           kUpgradeInsecureRequests ||
+       (base::FeatureList::IsEnabled(
+            blink::features::kMixedContentAutoupgrade) &&
+        GetExecutionContext()->Url().ProtocolIs("https"))) &&
       url_.Protocol() == "ws" &&
       !SecurityOrigin::Create(url_)->IsPotentiallyTrustworthy()) {
     UseCounter::Count(GetExecutionContext(),
diff --git a/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc b/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc
index f46924e..784928d 100644
--- a/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc
+++ b/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc
@@ -6,8 +6,10 @@
 
 #include <memory>
 
+#include "base/test/scoped_feature_list.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/platform/web_insecure_request_policy.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
@@ -267,6 +269,27 @@
   EXPECT_EQ(KURL("ws://example.com/endpoint"), websocket_scope.Socket().url());
 }
 
+TEST(DOMWebSocketTest, mixedContentAutoUpgrade) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(features::kMixedContentAutoupgrade);
+  V8TestingScope scope;
+  DOMWebSocketTestScope websocket_scope(scope.GetExecutionContext());
+  {
+    InSequence s;
+    EXPECT_CALL(websocket_scope.Channel(),
+                Connect(KURL("wss://example.com/endpoint"), String()))
+        .WillOnce(Return(true));
+  }
+  scope.GetDocument().SetURL(KURL("https://example.com"));
+  scope.GetDocument().SetInsecureRequestPolicy(kLeaveInsecureRequestsAlone);
+  websocket_scope.Socket().Connect("ws://example.com/endpoint",
+                                   Vector<String>(), scope.GetExceptionState());
+
+  EXPECT_FALSE(scope.GetExceptionState().HadException());
+  EXPECT_EQ(DOMWebSocket::kConnecting, websocket_scope.Socket().readyState());
+  EXPECT_EQ(KURL("wss://example.com/endpoint"), websocket_scope.Socket().url());
+}
+
 TEST(DOMWebSocketTest, channelConnectSuccess) {
   V8TestingScope scope;
   DOMWebSocketTestScope websocket_scope(scope.GetExecutionContext());
diff --git a/third_party/blink/renderer/platform/fonts/font_custom_platform_data.cc b/third_party/blink/renderer/platform/fonts/font_custom_platform_data.cc
index 4fafbed..e2eebf0 100644
--- a/third_party/blink/renderer/platform/fonts/font_custom_platform_data.cc
+++ b/third_party/blink/renderer/platform/fonts/font_custom_platform_data.cc
@@ -107,10 +107,9 @@
 
     if (variation_settings && variation_settings->size() < UINT16_MAX) {
       axes.ReserveCapacity(variation_settings->size() + axes.size());
-      for (size_t i = 0; i < variation_settings->size(); ++i) {
-        SkFontArguments::Axis axis = {
-            AtomicStringToFourByteTag(variation_settings->at(i).Tag()),
-            SkFloatToScalar(variation_settings->at(i).Value())};
+      for (const auto& setting : *variation_settings) {
+        SkFontArguments::Axis axis = {AtomicStringToFourByteTag(setting.Tag()),
+                                      SkFloatToScalar(setting.Value())};
         axes.push_back(axis);
       }
     }
diff --git a/third_party/blink/renderer/platform/fonts/font_fallback_iterator.cc b/third_party/blink/renderer/platform/fonts/font_fallback_iterator.cc
index cff57804..d854365af1 100644
--- a/third_party/blink/renderer/platform/fonts/font_fallback_iterator.cc
+++ b/third_party/blink/renderer/platform/fonts/font_fallback_iterator.cc
@@ -224,7 +224,7 @@
   if (hint_list.size() <= 1)
     return 0;
 
-  for (size_t i = 1; i < hint_list.size(); ++i) {
+  for (wtf_size_t i = 1; i < hint_list.size(); ++i) {
     if (Character::HasDefiniteScript(hint_list[i]))
       return i;
   }
diff --git a/third_party/blink/renderer/platform/fonts/font_metrics.h b/third_party/blink/renderer/platform/fonts/font_metrics.h
index 8938175..fbacc8cf 100644
--- a/third_party/blink/renderer/platform/fonts/font_metrics.h
+++ b/third_party/blink/renderer/platform/fonts/font_metrics.h
@@ -62,7 +62,7 @@
 
   void SetAscent(float ascent) {
     ascent_ = ascent;
-    ascent_int_ = lroundf(ascent);
+    ascent_int_ = static_cast<int>(lroundf(ascent));
   }
 
   float FloatDescent(FontBaseline baseline_type = kAlphabeticBaseline) const {
@@ -73,7 +73,7 @@
 
   void SetDescent(float descent) {
     descent_ = descent;
-    descent_int_ = lroundf(descent);
+    descent_int_ = static_cast<int>(lroundf(descent));
   }
 
   float FloatHeight(FontBaseline baseline_type = kAlphabeticBaseline) const {
@@ -112,8 +112,8 @@
     return Ascent() + Descent();
   }
 
-  int LineGap() const { return lroundf(line_gap_); }
-  int LineSpacing() const { return lroundf(line_spacing_); }
+  int LineGap() const { return static_cast<int>(lroundf(line_gap_)); }
+  int LineSpacing() const { return static_cast<int>(lroundf(line_spacing_)); }
 
   // LayoutUnit variants of certain metrics.
   // LayoutNG should use LayoutUnit for the block progression metrics.
diff --git a/third_party/blink/renderer/platform/fonts/opentype/font_settings.h b/third_party/blink/renderer/platform/fonts/opentype/font_settings.h
index fdb01c6..835e92e3 100644
--- a/third_party/blink/renderer/platform/fonts/opentype/font_settings.h
+++ b/third_party/blink/renderer/platform/fonts/opentype/font_settings.h
@@ -41,16 +41,16 @@
 class FontSettings {
  public:
   void Append(const T& feature) { list_.push_back(feature); }
-  size_t size() const { return list_.size(); }
-  const T& operator[](int index) const { return list_[index]; }
-  const T& at(size_t index) const { return list_.at(index); }
+  wtf_size_t size() const { return list_.size(); }
+  const T& operator[](wtf_size_t index) const { return list_[index]; }
+  const T& at(wtf_size_t index) const { return list_.at(index); }
   bool operator==(const FontSettings& other) const {
     return list_ == other.list_;
   };
   String ToString() const {
     StringBuilder builder;
-    size_t num_features = size();
-    for (size_t i = 0; i < num_features; ++i) {
+    wtf_size_t num_features = size();
+    for (wtf_size_t i = 0; i < num_features; ++i) {
       if (i > 0)
         builder.Append(",");
       const AtomicString& tag = at(i).Tag();
@@ -60,6 +60,10 @@
     }
     return builder.ToString();
   }
+  const T* begin() const { return list_.begin(); }
+  const T* end() const { return list_.end(); }
+  T* begin() { return list_.begin(); }
+  T* end() { return list_.end(); }
 
  protected:
   FontSettings() = default;
diff --git a/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.cc b/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.cc
index 6acc43a..3236274 100644
--- a/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.cc
+++ b/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.cc
@@ -30,6 +30,7 @@
 #include "third_party/blink/renderer/platform/fonts/simple_font_data.h"
 #include "third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.h"
 #include "third_party/blink/renderer/platform/geometry/float_rect.h"
+#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
 
 namespace blink {
 namespace OpenType {
@@ -135,7 +136,7 @@
                               SkFontTableTag tag,
                               Vector<char>& destination) {
   const size_t table_size = typeface->getTableSize(tag);
-  destination.resize(table_size);
+  destination.resize(SafeCast<wtf_size_t>(table_size));
   if (table_size) {
     typeface->getTableData(tag, 0, table_size, destination.data());
   }
@@ -217,16 +218,16 @@
   if (HasVORG())
     return;
 
-  size_t size_extra =
+  wtf_size_t size_extra =
       buffer.size() - sizeof(OpenType::VmtxTable::Entry) * count_vmtx_entries;
   if (size_extra % sizeof(OpenType::Int16)) {
     DLOG(ERROR) << "vmtx has incorrect tsb count";
     return;
   }
-  size_t count_top_side_bearings =
+  wtf_size_t count_top_side_bearings =
       count_vmtx_entries + size_extra / sizeof(OpenType::Int16);
   top_side_bearings_.resize(count_top_side_bearings);
-  size_t i;
+  wtf_size_t i;
   for (i = 0; i < count_vmtx_entries; ++i)
     top_side_bearings_[i] = vmtx->entries[i].top_side_bearing;
   if (i < count_top_side_bearings) {
@@ -247,7 +248,7 @@
 }
 
 float OpenTypeVerticalData::AdvanceHeight(Glyph glyph) const {
-  size_t count_heights = advance_heights_.size();
+  wtf_size_t count_heights = advance_heights_.size();
   if (count_heights) {
     uint16_t advance_f_unit =
         advance_heights_[glyph < count_heights ? glyph : count_heights - 1];
@@ -264,10 +265,10 @@
     const Glyph* glyphs,
     size_t count,
     float* out_xy_array) const {
-  size_t count_widths = advance_widths_.size();
+  wtf_size_t count_widths = advance_widths_.size();
   DCHECK_GT(count_widths, 0u);
   bool use_vorg = HasVORG();
-  size_t count_top_side_bearings = top_side_bearings_.size();
+  wtf_size_t count_top_side_bearings = top_side_bearings_.size();
   float default_vert_origin_y = std::numeric_limits<float>::quiet_NaN();
   for (float *end = &(out_xy_array[count * 2]); out_xy_array != end;
        ++glyphs, out_xy_array += 2) {
diff --git a/third_party/blink/renderer/platform/fonts/script_run_iterator.cc b/third_party/blink/renderer/platform/fonts/script_run_iterator.cc
index ca054ad..86da0df 100644
--- a/third_party/blink/renderer/platform/fonts/script_run_iterator.cc
+++ b/third_party/blink/renderer/platform/fonts/script_run_iterator.cc
@@ -76,7 +76,7 @@
     // Ignore common. Find the preferred script of the multiple scripts that
     // remain, and ensure it is at the head. Just keep swapping them in,
     // there aren't likely to be many.
-    for (size_t i = 1; i < dst.size(); ++i) {
+    for (wtf_size_t i = 1; i < dst.size(); ++i) {
       if (dst.at(0) == USCRIPT_LATIN || dst.at(i) < dst.at(0)) {
         std::swap(dst.at(0), dst.at(i));
       }
@@ -92,7 +92,7 @@
   // just sorted in alphabetic order.
   dst.push_back(dst.at(0));
   dst.at(0) = primary_script;
-  for (size_t i = 2; i < dst.size(); ++i) {
+  for (wtf_size_t i = 2; i < dst.size(); ++i) {
     if (dst.at(1) == USCRIPT_LATIN || dst.at(i) < dst.at(1)) {
       std::swap(dst.at(1), dst.at(i));
     }
@@ -115,7 +115,7 @@
 }
 
 ScriptRunIterator::ScriptRunIterator(const UChar* text,
-                                     size_t length,
+                                     wtf_size_t length,
                                      const ScriptData* data)
     : text_(text),
       length_(length),
@@ -141,7 +141,7 @@
   }
 }
 
-ScriptRunIterator::ScriptRunIterator(const UChar* text, size_t length)
+ScriptRunIterator::ScriptRunIterator(const UChar* text, wtf_size_t length)
     : ScriptRunIterator(text, length, ICUScriptData::Instance()) {}
 
 bool ScriptRunIterator::Consume(unsigned& limit, UScriptCode& script) {
@@ -149,7 +149,7 @@
     return false;
   }
 
-  size_t pos;
+  wtf_size_t pos;
   UChar32 ch;
   while (Fetch(&pos, &ch)) {
     PairedBracketType paired_type = script_data_->GetPairedBracketType(ch);
@@ -200,12 +200,13 @@
         next_set_->push_back(script);
 
         // And pop stack to this point.
-        int num_popped = std::distance(brackets_.rbegin(), it);
+        int num_popped =
+            static_cast<int>(std::distance(brackets_.rbegin(), it));
         // TODO: No resize operation in WTF::Deque?
         for (int i = 0; i < num_popped; ++i)
           brackets_.pop_back();
-        brackets_fixup_depth_ = std::max(static_cast<size_t>(0),
-                                         brackets_fixup_depth_ - num_popped);
+        brackets_fixup_depth_ = static_cast<wtf_size_t>(
+            std::max(0, static_cast<int>(brackets_fixup_depth_) - num_popped));
         return;
       }
     }
@@ -291,7 +292,8 @@
   }
 
   // Only change current if the run continues.
-  int written = std::distance(current_set_.begin(), current_write_it);
+  int written =
+      static_cast<int>(std::distance(current_set_.begin(), current_write_it));
   if (written > 0) {
     current_set_.resize(written);
     return true;
@@ -314,7 +316,7 @@
       brackets_fixup_depth_ = brackets_.size();
     }
     auto it = brackets_.rbegin();
-    for (size_t i = 0; i < brackets_fixup_depth_; ++i) {
+    for (wtf_size_t i = 0; i < brackets_fixup_depth_; ++i) {
       it->script = resolved_script;
       ++it;
     }
@@ -322,7 +324,7 @@
   }
 }
 
-bool ScriptRunIterator::Fetch(size_t* pos, UChar32* ch) {
+bool ScriptRunIterator::Fetch(wtf_size_t* pos, UChar32* ch) {
   if (ahead_pos_ > length_) {
     return false;
   }
diff --git a/third_party/blink/renderer/platform/fonts/script_run_iterator.h b/third_party/blink/renderer/platform/fonts/script_run_iterator.h
index 4bb1d48c..6f3f16ae 100644
--- a/third_party/blink/renderer/platform/fonts/script_run_iterator.h
+++ b/third_party/blink/renderer/platform/fonts/script_run_iterator.h
@@ -24,12 +24,12 @@
   WTF_MAKE_NONCOPYABLE(ScriptRunIterator);
 
  public:
-  ScriptRunIterator(const UChar* text, size_t length);
+  ScriptRunIterator(const UChar* text, wtf_size_t length);
 
   // This maintains a reference to data. It must exist for the lifetime of
   // this object. Typically data is a singleton that exists for the life of
   // the process.
-  ScriptRunIterator(const UChar* text, size_t length, const ScriptData*);
+  ScriptRunIterator(const UChar* text, wtf_size_t length, const ScriptData*);
 
   bool Consume(unsigned& limit, UScriptCode&);
 
@@ -46,15 +46,15 @@
   void CloseBracket(UChar32);
   bool MergeSets();
   void FixupStack(UScriptCode resolved_script);
-  bool Fetch(size_t* pos, UChar32*);
+  bool Fetch(wtf_size_t* pos, UChar32*);
 
   UScriptCode ResolveCurrentScript() const;
 
   const UChar* text_;
-  const size_t length_;
+  const wtf_size_t length_;
 
   Deque<BracketRec> brackets_;
-  size_t brackets_fixup_depth_;
+  wtf_size_t brackets_fixup_depth_;
   // Limit max brackets so that the bracket tracking buffer does not grow
   // excessively large when processing long runs of text.
   static const int kMaxBrackets = 32;
@@ -67,7 +67,7 @@
   std::unique_ptr<UScriptCodeList> ahead_set_;
 
   UChar32 ahead_character_;
-  size_t ahead_pos_;
+  wtf_size_t ahead_pos_;
 
   UScriptCode common_preferred_;
 
diff --git a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.cc b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.cc
index 2ce1274d4..b8bdb2a 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.cc
@@ -45,6 +45,7 @@
 #include "third_party/blink/renderer/platform/resolution_units.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
+#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
 
 #include <hb-ot.h>
 #include <hb.h>
@@ -338,7 +339,8 @@
                                        void* user_data) {
   SkTypeface* typeface = reinterpret_cast<SkTypeface*>(user_data);
 
-  const size_t table_size = typeface->getTableSize(tag);
+  const wtf_size_t table_size =
+      SafeCast<wtf_size_t>(typeface->getTableSize(tag));
   if (!table_size) {
     return nullptr;
   }
@@ -387,8 +389,8 @@
     std::unique_ptr<hb_blob_t, void (*)(hb_blob_t*)> face_blob(
         hb_blob_create(
             reinterpret_cast<const char*>(typeface_stream->getMemoryBase()),
-            typeface_stream->getLength(), HB_MEMORY_MODE_READONLY,
-            typeface_stream, DeleteTypefaceStream),
+            SafeCast<unsigned int>(typeface_stream->getLength()),
+            HB_MEMORY_MODE_READONLY, typeface_stream, DeleteTypefaceStream),
         hb_blob_destroy);
     face = hb_face_create(face_blob.get(), ttc_index);
   }
diff --git a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc
index 8cc42af..1b1cb1e 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc
@@ -774,7 +774,7 @@
   void OverlayCapsFeatures(FontDescription::FontVariantCaps);
   void PrependCounting(const hb_feature_t&);
   FeaturesVector* features_;
-  size_t count_features_;
+  wtf_size_t count_features_;
 };
 
 CapsFeatureSettingsScopedOverlay::CapsFeatureSettingsScopedOverlay(
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
index 19b7b58..1c84a168 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
@@ -823,7 +823,7 @@
       continue;
     unsigned run_start_index = run->start_index_ + text_start_offset;
     float total_space_for_run = 0;
-    for (size_t i = 0; i < run->glyph_data_.size(); i++) {
+    for (wtf_size_t i = 0; i < run->glyph_data_.size(); i++) {
       HarfBuzzRunGlyphData& glyph_data = run->glyph_data_[i];
 
       // Skip if it's not a grapheme cluster boundary.
@@ -1196,14 +1196,14 @@
   // start index. For RTL, we place the run before the next run with a lower
   // character index. Otherwise, for both directions, at the end.
   if (HB_DIRECTION_IS_FORWARD(run->direction_)) {
-    for (size_t pos = 0; pos < runs_.size(); ++pos) {
+    for (wtf_size_t pos = 0; pos < runs_.size(); ++pos) {
       if (runs_.at(pos)->start_index_ > run->start_index_) {
         runs_.insert(pos, std::move(run));
         break;
       }
     }
   } else {
-    for (size_t pos = 0; pos < runs_.size(); ++pos) {
+    for (wtf_size_t pos = 0; pos < runs_.size(); ++pos) {
       if (runs_.at(pos)->start_index_ < run->start_index_) {
         runs_.insert(pos, std::move(run));
         break;
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result.h b/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
index b4cad4c0..214f256 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
@@ -248,7 +248,7 @@
   // Computes the list of fonts along with the number of glyphs for each font.
   struct RunFontData {
     SimpleFontData* font_data_;
-    size_t glyph_count_;
+    wtf_size_t glyph_count_;
   };
   void GetRunFontData(Vector<RunFontData>* font_data) const;
 
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h b/third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h
index 59cac7c..4ad56a5 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h
@@ -118,7 +118,7 @@
                             float offset_x,
                             float offset_y);
 
-  size_t GlyphToCharacterIndex(size_t i) const {
+  unsigned GlyphToCharacterIndex(unsigned i) const {
     return start_index_ + glyph_data_[i].character_index;
   }
 
@@ -175,7 +175,8 @@
     DCHECK(end > start);
     unsigned number_of_characters = std::min(end - start, num_characters_);
     auto glyphs = FindGlyphDataRange(start, end);
-    unsigned number_of_glyphs = std::distance(glyphs.begin, glyphs.end);
+    unsigned number_of_glyphs =
+        static_cast<unsigned>(std::distance(glyphs.begin, glyphs.end));
 
     auto run = std::make_unique<RunInfo>(
         font_data_.get(), direction_, canvas_rotation_, script_,
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_test_info.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result_test_info.cc
index 29dfd440..49baaaf 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_test_info.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_test_info.cc
@@ -43,12 +43,12 @@
 }
 
 uint16_t ShapeResultTestInfo::GlyphForTesting(unsigned run_index,
-                                              size_t glyph_index) const {
+                                              unsigned glyph_index) const {
   return runs_[run_index]->glyph_data_[glyph_index].glyph;
 }
 
 float ShapeResultTestInfo::AdvanceForTesting(unsigned run_index,
-                                             size_t glyph_index) const {
+                                             unsigned glyph_index) const {
   return runs_[run_index]->glyph_data_[glyph_index].advance;
 }
 
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_test_info.h b/third_party/blink/renderer/platform/fonts/shaping/shape_result_test_info.h
index f659681..27cc6a4 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_test_info.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_test_info.h
@@ -25,8 +25,8 @@
                          unsigned& num_characters,
                          unsigned& num_glyphs,
                          hb_script_t&) const;
-  uint16_t GlyphForTesting(unsigned run_index, size_t glyph_index) const;
-  float AdvanceForTesting(unsigned run_index, size_t glyph_index) const;
+  uint16_t GlyphForTesting(unsigned run_index, unsigned glyph_index) const;
+  float AdvanceForTesting(unsigned run_index, unsigned glyph_index) const;
   SimpleFontData* FontDataForTesting(unsigned run_index) const;
   Vector<unsigned> CharacterIndexesForTesting() const;
 };
diff --git a/third_party/blink/renderer/platform/fonts/skia/font_cache_skia.cc b/third_party/blink/renderer/platform/fonts/skia/font_cache_skia.cc
index 7468c06..0c49c09 100644
--- a/third_party/blink/renderer/platform/fonts/skia/font_cache_skia.cc
+++ b/third_party/blink/renderer/platform/fonts/skia/font_cache_skia.cc
@@ -98,9 +98,9 @@
     FontFallbackPriority fallback_priority) {
   DCHECK(fm);
 
-  const size_t kMaxLocales = 4;
+  const int kMaxLocales = 4;
   const char* bcp47_locales[kMaxLocales];
-  size_t locale_count = 0;
+  int locale_count = 0;
 
   // Fill in the list of locales in the reverse priority order.
   // Skia expects the highest array index to be the first priority.
diff --git a/third_party/blink/renderer/platform/fonts/unicode_range_set.cc b/third_party/blink/renderer/platform/fonts/unicode_range_set.cc
index 1721b04..5122b6a 100644
--- a/third_party/blink/renderer/platform/fonts/unicode_range_set.cc
+++ b/third_party/blink/renderer/platform/fonts/unicode_range_set.cc
@@ -39,8 +39,8 @@
   // Unify overlapping ranges.
   UChar32 from = ranges_[0].From();
   UChar32 to = ranges_[0].To();
-  size_t target_index = 0;
-  for (size_t i = 1; i < ranges_.size(); i++) {
+  wtf_size_t target_index = 0;
+  for (wtf_size_t i = 1; i < ranges_.size(); i++) {
     if (to + 1 >= ranges_[i].From()) {
       to = std::max(to, ranges_[i].To());
     } else {
@@ -86,7 +86,7 @@
     return false;
   }
   bool equal = true;
-  for (size_t i = 0; i < ranges_.size(); ++i) {
+  for (wtf_size_t i = 0; i < ranges_.size(); ++i) {
     equal = equal && ranges_[i] == other.ranges_[i];
   }
   return equal;
diff --git a/third_party/blink/renderer/platform/fonts/unicode_range_set.h b/third_party/blink/renderer/platform/fonts/unicode_range_set.h
index f766c4c..9fd9f7dc 100644
--- a/third_party/blink/renderer/platform/fonts/unicode_range_set.h
+++ b/third_party/blink/renderer/platform/fonts/unicode_range_set.h
@@ -64,8 +64,8 @@
   bool Contains(UChar32) const;
   bool IntersectsWith(const String&) const;
   bool IsEntireRange() const { return ranges_.IsEmpty(); }
-  size_t size() const { return ranges_.size(); }
-  const UnicodeRange& RangeAt(size_t i) const { return ranges_[i]; }
+  wtf_size_t size() const { return ranges_.size(); }
+  const UnicodeRange& RangeAt(wtf_size_t i) const { return ranges_[i]; }
   bool operator==(const UnicodeRangeSet& other) const;
 
  private:
diff --git a/third_party/blink/renderer/platform/geometry/blend.h b/third_party/blink/renderer/platform/geometry/blend.h
index 10005926..6db4f3c 100644
--- a/third_party/blink/renderer/platform/geometry/blend.h
+++ b/third_party/blink/renderer/platform/geometry/blend.h
@@ -16,7 +16,7 @@
 namespace blink {
 
 inline int Blend(int from, int to, double progress) {
-  return lround(from + (to - from) * progress);
+  return static_cast<int>(lround(from + (to - from) * progress));
 }
 
 // For unsigned types.
diff --git a/third_party/blink/renderer/platform/geometry/float_rect.cc b/third_party/blink/renderer/platform/geometry/float_rect.cc
index 95fe5b7c..d9af7d7 100644
--- a/third_party/blink/renderer/platform/geometry/float_rect.cc
+++ b/third_party/blink/renderer/platform/geometry/float_rect.cc
@@ -261,9 +261,8 @@
 FloatRect UnionRect(const Vector<FloatRect>& rects) {
   FloatRect result;
 
-  size_t count = rects.size();
-  for (size_t i = 0; i < count; ++i)
-    result.Unite(rects[i]);
+  for (const auto& rect : rects)
+    result.Unite(rect);
 
   return result;
 }
diff --git a/third_party/blink/renderer/platform/geometry/int_point.h b/third_party/blink/renderer/platform/geometry/int_point.h
index 5da33140..b8d637c 100644
--- a/third_party/blink/renderer/platform/geometry/int_point.h
+++ b/third_party/blink/renderer/platform/geometry/int_point.h
@@ -79,8 +79,8 @@
   }
 
   void Scale(float sx, float sy) {
-    x_ = lroundf(static_cast<float>(x_ * sx));
-    y_ = lroundf(static_cast<float>(y_ * sy));
+    x_ = static_cast<int>(lroundf(static_cast<float>(x_ * sx)));
+    y_ = static_cast<int>(lroundf(static_cast<float>(y_ * sy)));
   }
 
   IntPoint ExpandedTo(const IntPoint& other) const {
diff --git a/third_party/blink/renderer/platform/geometry/int_rect.cc b/third_party/blink/renderer/platform/geometry/int_rect.cc
index 55406ad..74de7f4 100644
--- a/third_party/blink/renderer/platform/geometry/int_rect.cc
+++ b/third_party/blink/renderer/platform/geometry/int_rect.cc
@@ -170,20 +170,19 @@
 IntRect UnionRect(const Vector<IntRect>& rects) {
   IntRect result;
 
-  size_t count = rects.size();
-  for (size_t i = 0; i < count; ++i)
-    result.Unite(rects[i]);
+  for (const IntRect& rect : rects)
+    result.Unite(rect);
 
   return result;
 }
 
 IntRect UnionRectEvenIfEmpty(const Vector<IntRect>& rects) {
-  size_t count = rects.size();
+  wtf_size_t count = rects.size();
   if (!count)
     return IntRect();
 
   IntRect result = rects[0];
-  for (size_t i = 1; i < count; ++i)
+  for (wtf_size_t i = 1; i < count; ++i)
     result.UniteEvenIfEmpty(rects[i]);
 
   return result;
diff --git a/third_party/blink/renderer/platform/geometry/layout_rect.cc b/third_party/blink/renderer/platform/geometry/layout_rect.cc
index 5f95394..aaf8de55 100644
--- a/third_party/blink/renderer/platform/geometry/layout_rect.cc
+++ b/third_party/blink/renderer/platform/geometry/layout_rect.cc
@@ -141,20 +141,19 @@
 LayoutRect UnionRect(const Vector<LayoutRect>& rects) {
   LayoutRect result;
 
-  size_t count = rects.size();
-  for (size_t i = 0; i < count; ++i)
-    result.Unite(rects[i]);
+  for (const LayoutRect& rect : rects)
+    result.Unite(rect);
 
   return result;
 }
 
 LayoutRect UnionRectEvenIfEmpty(const Vector<LayoutRect>& rects) {
-  size_t count = rects.size();
+  wtf_size_t count = rects.size();
   if (!count)
     return LayoutRect();
 
   LayoutRect result = rects[0];
-  for (size_t i = 1; i < count; ++i)
+  for (wtf_size_t i = 1; i < count; ++i)
     result.UniteEvenIfEmpty(rects[i]);
 
   return result;
diff --git a/third_party/blink/renderer/platform/geometry/region.cc b/third_party/blink/renderer/platform/geometry/region.cc
index 153f0df..217ce61 100644
--- a/third_party/blink/renderer/platform/geometry/region.cc
+++ b/third_party/blink/renderer/platform/geometry/region.cc
@@ -241,7 +241,7 @@
   AppendSpan(rect.MaxY());
 }
 
-Region::Shape::Shape(size_t segments_capacity, size_t spans_capacity) {
+Region::Shape::Shape(wtf_size_t segments_capacity, wtf_size_t spans_capacity) {
   segments_.ReserveCapacity(segments_capacity);
   spans_.ReserveCapacity(spans_capacity);
 }
@@ -321,7 +321,7 @@
     return nullptr;
 
   DCHECK_LT(it + 1, spans_.data() + spans_.size());
-  size_t segment_index = (it + 1)->segment_index;
+  wtf_size_t segment_index = (it + 1)->segment_index;
 
   SECURITY_DCHECK(segment_index <= segments_.size());
   return segments_.data() + segment_index;
@@ -381,9 +381,9 @@
 }
 
 void Region::Shape::Translate(const IntSize& offset) {
-  for (size_t i = 0; i < segments_.size(); ++i)
+  for (wtf_size_t i = 0; i < segments_.size(); ++i)
     segments_[i] += offset.Width();
-  for (size_t i = 0; i < spans_.size(); ++i)
+  for (wtf_size_t i = 0; i < spans_.size(); ++i)
     spans_[i].y += offset.Height();
 }
 
@@ -407,8 +407,8 @@
                   Operation::kShouldAddRemainingSpansFromShape2),
                 "invalid span combination");
 
-  size_t segments_capacity = shape1.SegmentsSize() + shape2.SegmentsSize();
-  size_t spans_capacity = shape1.SpansSize() + shape2.SpansSize();
+  wtf_size_t segments_capacity = shape1.SegmentsSize() + shape2.SegmentsSize();
+  wtf_size_t spans_capacity = shape1.SpansSize() + shape2.SpansSize();
   Shape result(segments_capacity, spans_capacity);
   if (Operation::TrySimpleOperation(shape1, shape2, result))
     return result;
diff --git a/third_party/blink/renderer/platform/geometry/region.h b/third_party/blink/renderer/platform/geometry/region.h
index 440ef38..12e29acb 100644
--- a/third_party/blink/renderer/platform/geometry/region.h
+++ b/third_party/blink/renderer/platform/geometry/region.h
@@ -80,10 +80,11 @@
  private:
   struct Span {
     DISALLOW_NEW();
-    Span(int y, size_t segment_index) : y(y), segment_index(segment_index) {}
+    Span(int y, wtf_size_t segment_index)
+        : y(y), segment_index(segment_index) {}
 
     int y;
-    size_t segment_index;
+    wtf_size_t segment_index;
   };
 
   // Shape composed of non-overlapping rectangles implied by segments [x, max_x)
@@ -99,7 +100,7 @@
    public:
     Shape();
     Shape(const IntRect&);
-    Shape(size_t segments_capacity, size_t spans_capacity);
+    Shape(wtf_size_t segments_capacity, wtf_size_t spans_capacity);
 
     IntRect Bounds() const;
     bool IsEmpty() const { return spans_.IsEmpty(); }
@@ -108,12 +109,12 @@
     typedef const Span* SpanIterator;
     SpanIterator SpansBegin() const;
     SpanIterator SpansEnd() const;
-    size_t SpansSize() const { return spans_.size(); }
+    wtf_size_t SpansSize() const { return spans_.size(); }
 
     typedef const int* SegmentIterator;
     SegmentIterator SegmentsBegin(SpanIterator) const;
     SegmentIterator SegmentsEnd(SpanIterator) const;
-    size_t SegmentsSize() const { return segments_.size(); }
+    wtf_size_t SegmentsSize() const { return segments_.size(); }
 
     static Shape UnionShapes(const Shape& shape1, const Shape& shape2);
     static Shape IntersectShapes(const Shape& shape1, const Shape& shape2);
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
index d83ef72..fc8416b 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
@@ -71,7 +71,6 @@
 }
 
 void PaintArtifactCompositor::WillBeRemovedFromFrame() {
-  UnregisterAllElementIds();
   root_layer_->RemoveAllChildren();
   if (extra_data_for_testing_enabled_) {
     extra_data_for_testing_->content_layers.clear();
@@ -80,22 +79,6 @@
   }
 }
 
-void PaintArtifactCompositor::UnregisterAllElementIds() {
-  // Unregister element ids for all layers. For now we rely on the
-  // element id being set on the layer, but we'll be removing that for
-  // SPv2 soon. We may also shift to having multiple element ids per
-  // layer. When we do either of these, we'll need to keep around the
-  // element ids for unregistering in some other manner.
-  cc::LayerTreeHost* host = root_layer_->layer_tree_host();
-  if (!host)
-    return;
-  for (auto child : root_layer_->children()) {
-    auto element_id = child->element_id();
-    if (element_id)
-      host->UnregisterElement(element_id, cc::ElementListType::ACTIVE);
-  }
-}
-
 std::unique_ptr<JSONObject> PaintArtifactCompositor::LayersAsJSON(
     LayerTreeFlags flags) const {
   ContentLayerClientImpl::LayerAsJSONContext context(flags);
@@ -718,7 +701,6 @@
   DCHECK(!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
          host->GetSettings().use_layer_lists);
 
-  UnregisterAllElementIds();
   if (extra_data_for_testing_enabled_)
     extra_data_for_testing_.reset(new ExtraDataForTesting);
 
@@ -767,6 +749,20 @@
     scoped_refptr<cc::Layer> layer = CompositedLayerForPendingLayer(
         paint_artifact, pending_layer, layer_offset, new_content_layer_clients,
         new_scroll_hit_test_layers);
+    // Get the compositor element id for the layer. Scrollable layers are only
+    // associated with scroll element ids which are set in
+    // ScrollHitTestLayerForPendingLayer.
+    CompositorElementId element_id =
+        layer->scrollable()
+            ? layer->element_id()
+            : property_state.GetCompositorElementId(composited_element_ids);
+    // TODO(wkorman): Cease setting element id on layer once
+    // animation subsystem no longer requires element id to layer
+    // map. http://crbug.com/709137
+    // TODO(pdr): Element ids will still need to be set on scroll layers.
+    layer->SetElementId(element_id);
+    if (element_id)
+      composited_element_ids.insert(element_id);
     layer->SetLayerTreeHost(root_layer_->layer_tree_host());
 
     int transform_id =
@@ -783,33 +779,8 @@
 
     layer->SetOffsetToTransformParent(layer_offset);
 
-    // Get the compositor element id for the layer. Scrollable layers are only
-    // associated with scroll element ids which are set in
-    // ScrollHitTestLayerForPendingLayer.
-    CompositorElementId element_id =
-        layer->scrollable()
-            ? layer->element_id()
-            : property_state.GetCompositorElementId(composited_element_ids);
-    if (element_id) {
-      // TODO(wkorman): Cease setting element id on layer once
-      // animation subsystem no longer requires element id to layer
-      // map. http://crbug.com/709137
-      // TODO(pdr): Element ids will still need to be set on scroll layers.
-      layer->SetElementId(element_id);
-      composited_element_ids.insert(element_id);
-    }
-
     layer_list_builder.Add(layer);
 
-    // TODO(wkorman): Once we've removed all uses of
-    // LayerTreeHost::{LayerByElementId,element_layers_map} we can
-    // revise element register/unregister to cease passing layer and
-    // only register/unregister element id with the mutator host.
-    if (element_id) {
-      host->RegisterElement(element_id, cc::ElementListType::ACTIVE,
-                            layer.get());
-    }
-
     layer->set_property_tree_sequence_number(
         root_layer_->property_tree_sequence_number());
     layer->SetTransformTreeIndex(transform_id);
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h
index 03502a9..030294c 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h
@@ -137,8 +137,6 @@
       base::RepeatingCallback<void(const gfx::ScrollOffset&,
                                    const cc::ElementId&)> scroll_callback);
 
-  void UnregisterAllElementIds();
-
   // Collects the PaintChunks into groups which will end up in the same
   // cc layer. This is the entry point of the layerization algorithm.
   void CollectPendingLayers(const PaintArtifact&,
diff --git a/third_party/blink/renderer/platform/graphics/skia/skia_utils.cc b/third_party/blink/renderer/platform/graphics/skia/skia_utils.cc
index 3dff61d..38cd420 100644
--- a/third_party/blink/renderer/platform/graphics/skia/skia_utils.cc
+++ b/third_party/blink/renderer/platform/graphics/skia/skia_utils.cc
@@ -34,6 +34,7 @@
 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_flags.h"
 #include "third_party/skia/include/effects/SkCornerPathEffect.h"
+#include "third_party/skia/third_party/skcms/skcms.h"
 #include "ui/gfx/icc_profile.h"
 
 #include <algorithm>
@@ -341,6 +342,19 @@
   return gfx::ColorSpace::CreateSRGB();
 }
 
+bool ApproximatelyEqualSkColorSpaces(sk_sp<SkColorSpace> src_color_space,
+                                     sk_sp<SkColorSpace> dst_color_space) {
+  if ((!src_color_space && dst_color_space) ||
+      (src_color_space && !dst_color_space))
+    return false;
+  if (!src_color_space && !dst_color_space)
+    return true;
+  skcms_ICCProfile src_profile, dst_profile;
+  src_color_space->toProfile(&src_profile);
+  dst_color_space->toProfile(&dst_profile);
+  return skcms_ApproximatelyEqualProfiles(&src_profile, &dst_profile);
+}
+
 template <typename PrimitiveType>
 void DrawFocusRingPrimitive(const PrimitiveType&,
                             cc::PaintCanvas*,
diff --git a/third_party/blink/renderer/platform/graphics/skia/skia_utils.h b/third_party/blink/renderer/platform/graphics/skia/skia_utils.h
index 4d7816c..9633ea90 100644
--- a/third_party/blink/renderer/platform/graphics/skia/skia_utils.h
+++ b/third_party/blink/renderer/platform/graphics/skia/skia_utils.h
@@ -77,6 +77,10 @@
 gfx::ColorSpace PLATFORM_EXPORT
 SkColorSpaceToGfxColorSpace(const sk_sp<SkColorSpace>);
 
+bool PLATFORM_EXPORT
+ApproximatelyEqualSkColorSpaces(sk_sp<SkColorSpace> src_color_space,
+                                sk_sp<SkColorSpace> dst_color_space);
+
 // Skia has problems when passed infinite, etc floats, filter them to 0.
 inline SkScalar WebCoreFloatToSkScalar(float f) {
   return SkFloatToScalar(std::isfinite(f) ? f : 0);
diff --git a/third_party/blink/renderer/platform/instrumentation/resource_coordinator/frame_resource_coordinator.cc b/third_party/blink/renderer/platform/instrumentation/resource_coordinator/frame_resource_coordinator.cc
index b0a1d90..aa33be3a 100644
--- a/third_party/blink/renderer/platform/instrumentation/resource_coordinator/frame_resource_coordinator.cc
+++ b/third_party/blink/renderer/platform/instrumentation/resource_coordinator/frame_resource_coordinator.cc
@@ -32,6 +32,11 @@
   service_->SetLifecycleState(state);
 }
 
+void FrameResourceCoordinator::SetHasNonEmptyBeforeUnload(
+    bool has_nonempty_beforeunload) {
+  service_->SetHasNonEmptyBeforeUnload(has_nonempty_beforeunload);
+}
+
 void FrameResourceCoordinator::OnNonPersistentNotificationCreated() {
   service_->OnNonPersistentNotificationCreated();
 }
diff --git a/third_party/blink/renderer/platform/instrumentation/resource_coordinator/frame_resource_coordinator.h b/third_party/blink/renderer/platform/instrumentation/resource_coordinator/frame_resource_coordinator.h
index 9fbc01d..483cf4f 100644
--- a/third_party/blink/renderer/platform/instrumentation/resource_coordinator/frame_resource_coordinator.h
+++ b/third_party/blink/renderer/platform/instrumentation/resource_coordinator/frame_resource_coordinator.h
@@ -25,6 +25,7 @@
 
   void SetNetworkAlmostIdle(bool);
   void SetLifecycleState(resource_coordinator::mojom::LifecycleState);
+  void SetHasNonEmptyBeforeUnload(bool has_nonempty_beforeunload);
   void OnNonPersistentNotificationCreated();
 
  private:
diff --git a/third_party/blink/renderer/platform/network/mime/mime_type_registry.cc b/third_party/blink/renderer/platform/network/mime/mime_type_registry.cc
index e024e360..354528a 100644
--- a/third_party/blink/renderer/platform/network/mime/mime_type_registry.cc
+++ b/third_party/blink/renderer/platform/network/mime/mime_type_registry.cc
@@ -161,7 +161,7 @@
     const String& codecs) {
   const std::string ascii_mime_type = ToLowerASCIIOrEmpty(mime_type);
   std::vector<std::string> codec_vector;
-  media::SplitCodecsToVector(ToASCIIOrEmpty(codecs), &codec_vector, false);
+  media::SplitCodecs(ToASCIIOrEmpty(codecs), &codec_vector);
   return static_cast<SupportsType>(
       media::IsSupportedMediaFormat(ascii_mime_type, codec_vector));
 }
@@ -172,7 +172,7 @@
   if (ascii_mime_type.empty())
     return false;
   std::vector<std::string> parsed_codec_ids;
-  media::SplitCodecsToVector(ToASCIIOrEmpty(codecs), &parsed_codec_ids, false);
+  media::SplitCodecs(ToASCIIOrEmpty(codecs), &parsed_codec_ids);
   return static_cast<MIMETypeRegistry::SupportsType>(
       media::StreamParserFactory::IsTypeSupported(ascii_mime_type,
                                                   parsed_codec_ids));
diff --git a/third_party/blink/renderer/platform/ukm_time_aggregator.cc b/third_party/blink/renderer/platform/ukm_time_aggregator.cc
deleted file mode 100644
index 3dab37c..0000000
--- a/third_party/blink/renderer/platform/ukm_time_aggregator.cc
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright 2018 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 "third_party/blink/renderer/platform/ukm_time_aggregator.h"
-
-#include "services/metrics/public/cpp/ukm_entry_builder.h"
-#include "services/metrics/public/cpp/ukm_recorder.h"
-#include "third_party/blink/renderer/platform/histogram.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-#include "third_party/blink/renderer/platform/wtf/time.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-
-namespace blink {
-
-UkmTimeAggregator::ScopedUkmTimer::ScopedUkmTimer(
-    UkmTimeAggregator* aggregator,
-    size_t metric_index,
-    CustomCountHistogram* histogram_counter)
-    : aggregator_(aggregator),
-      metric_index_(metric_index),
-      histogram_counter_(histogram_counter),
-      start_time_(CurrentTimeTicks()) {}
-
-UkmTimeAggregator::ScopedUkmTimer::ScopedUkmTimer(ScopedUkmTimer&& other)
-    : aggregator_(other.aggregator_),
-      metric_index_(other.metric_index_),
-      histogram_counter_(other.histogram_counter_),
-      start_time_(other.start_time_) {
-  other.aggregator_ = nullptr;
-}
-
-UkmTimeAggregator::ScopedUkmTimer::~ScopedUkmTimer() {
-  if (aggregator_ && base::TimeTicks::IsHighResolution()) {
-    aggregator_->RecordSample(metric_index_, start_time_, CurrentTimeTicks(),
-                              histogram_counter_);
-  }
-}
-
-UkmTimeAggregator::UkmTimeAggregator(String event_name,
-                                     int64_t source_id,
-                                     ukm::UkmRecorder* recorder,
-                                     const Vector<String>& metric_names,
-                                     TimeDelta event_frequency)
-    : event_name_(std::move(event_name)),
-      source_id_(source_id),
-      recorder_(recorder),
-      event_frequency_(event_frequency),
-      last_flushed_time_(CurrentTimeTicks()) {
-  metric_records_.ReserveCapacity(metric_names.size());
-  for (const auto& metric_name : metric_names) {
-    auto& record = metric_records_.emplace_back();
-    record.worst_case_metric_name = metric_name;
-    record.worst_case_metric_name.append(".WorstCase");
-    record.average_metric_name = metric_name;
-    record.average_metric_name.append(".Average");
-  }
-}
-
-UkmTimeAggregator::~UkmTimeAggregator() {
-  Flush(TimeTicks());
-}
-
-UkmTimeAggregator::ScopedUkmTimer UkmTimeAggregator::GetScopedTimer(
-    size_t metric_index,
-    CustomCountHistogram* histogram_counter) {
-  return ScopedUkmTimer(this, metric_index, histogram_counter);
-}
-
-void UkmTimeAggregator::RecordSample(size_t metric_index,
-                                     TimeTicks start,
-                                     TimeTicks end,
-                                     CustomCountHistogram* histogram_counter) {
-  FlushIfNeeded(end);
-
-  // Record the UMA if we have a counter.
-  TimeDelta duration = end - start;
-  if (histogram_counter)
-    histogram_counter->CountMicroseconds(duration);
-
-  // Append the duration to the appropriate metrics record.
-  DCHECK_LT(metric_index, metric_records_.size());
-  auto& record = metric_records_[metric_index];
-  if (duration > record.worst_case_duration)
-    record.worst_case_duration = duration;
-  record.total_duration += duration;
-  ++record.sample_count;
-  has_data_ = true;
-}
-
-void UkmTimeAggregator::FlushIfNeeded(TimeTicks current_time) {
-  if (current_time >= last_flushed_time_ + event_frequency_)
-    Flush(current_time);
-}
-
-void UkmTimeAggregator::Flush(TimeTicks current_time) {
-  last_flushed_time_ = current_time;
-  if (!has_data_)
-    return;
-
-  ukm::UkmEntryBuilder builder(source_id_, event_name_.Utf8().data());
-  for (auto& record : metric_records_) {
-    if (record.sample_count == 0)
-      continue;
-    builder.SetMetric(record.worst_case_metric_name.Utf8().data(),
-                      record.worst_case_duration.InMicroseconds());
-    builder.SetMetric(record.average_metric_name.Utf8().data(),
-                      record.total_duration.InMicroseconds() /
-                          static_cast<int64_t>(record.sample_count));
-    record.reset();
-  }
-  builder.Record(recorder_);
-  has_data_ = false;
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/platform/ukm_time_aggregator.h b/third_party/blink/renderer/platform/ukm_time_aggregator.h
deleted file mode 100644
index 55d67c71..0000000
--- a/third_party/blink/renderer/platform/ukm_time_aggregator.h
+++ /dev/null
@@ -1,167 +0,0 @@
-// Copyright 2018 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_UKM_TIME_AGGREGATOR_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_UKM_TIME_AGGREGATOR_H_
-
-#include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-#include "third_party/blink/renderer/platform/wtf/time.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-
-namespace ukm {
-class UkmRecorder;
-}
-
-namespace blink {
-class CustomCountHistogram;
-
-// This class is a helper class for aggregating and recording time based UKM
-// metrics. The simplest way to use it is via the SCOPED_UMA_AND_UKM_TIMER macro
-// in LocalFrameView.
-//
-// It takes the following constructor parameters:
-// - event_name: The name of the event(s) that will be generated by this
-//               aggregator.
-// - source_id: UKM Source ID associated with the events.
-// - recorder: UkmRecorder which will handle the events
-// - metric_names: A Vector of strings that represent the base names for the
-//                 metrics associated with the event. Note that the order of
-//                 this array is important, since the scoped timer is created
-//                 with an index into this array.
-// - event_frequency: The interval over which metrics are aggregated. Within
-//                    one interval there will be one event generated.
-//
-// After the aggregator is created, one can create ScopedUkmTimer object which
-// will measure the time, in microseconds, from creation until the object
-// destruction. When destroyed, it will record a sample into the aggregator.
-// This does not necessarily generate a UKM event. Instead, the sample is
-// aggregated with other samples in the interval specified by event frequency.
-// An event is actually generated in one of two situations:
-//
-//  - If a sample is added that lies in the next event frequency interval (this
-//    will generate an event for the previous interval)
-//  - If the aggregator is destroyed (this will generate an event for any
-//    remaining samples in the aggregator)
-//
-// Note that no event is generated if there were no samples in an interval.
-//
-// Note that one can also give an optional CustomCountHistogram pointer when
-// creating the scoped timer. This is provided as a convenience. Upon
-// destruction the timer will record a sample into the histogram counter.
-//
-// Sample usage (see also SCOPED_UMA_AND_UKM_TIMER):
-//   // Note that values of this enum correspond to the indices of the metric
-//   // names array given to UkmTimeAggregator at construction.
-//   enum class MetricNames { kMetric1, kMetric2, kMetric3 };
-//   std::unique_ptr<UkmTimeAggregator> aggregator(
-//      new UkmTimeAggregator("my_event",
-//                            GetSourceId(),
-//                            GetUkmRecorder(),
-//                            {"metric1", "metric2", "metric3"},
-//                            TimeDelta::FromSeconds(1)));
-//
-//   ...
-//   {
-//     auto timer =
-//       aggregator->GetScopedTimer(static_cast<size_t>(MetricNames::kMetric2));
-//     ...
-//   }
-//   // At this point an sample for "metric2" is recorded, which may generate
-//   // an event for "my_event" if there were previous samples.
-//   ...
-//   // Destroying an aggregator will generate an event as well if there were
-//   // samples.
-//   aggregator.reset();
-//
-// In the example above, the event name is "my_event". It will measure six
-// metrics:
-//   "metric1.Average", "metric1.WorstCase",
-//   "metric2.Average", "metric2.WorstCase",
-//   "metric3.Average", "metric3.WorstCase"
-//
-// Note that these have to be specified in the appropriate ukm.xml file to be
-// captured.
-//
-// If the source_id/event_name/recorder change then a new UkmTimeAggregator has
-// to be created.
-class PLATFORM_EXPORT UkmTimeAggregator {
- public:
-  // This class will start a timer upon creation, which will end when the
-  // object is destroyed. Upon destruction it will record a sample into the
-  // aggregator that created the scoped timer. It will also record an event
-  // into an optional histogram counter.
-  class PLATFORM_EXPORT ScopedUkmTimer {
-   public:
-    ScopedUkmTimer(ScopedUkmTimer&&);
-    ~ScopedUkmTimer();
-
-   private:
-    friend class UkmTimeAggregator;
-
-    ScopedUkmTimer(UkmTimeAggregator*,
-                   size_t metric_index,
-                   CustomCountHistogram* histogram_counter);
-
-    UkmTimeAggregator* aggregator_;
-    const size_t metric_index_;
-    CustomCountHistogram* const histogram_counter_;
-    const TimeTicks start_time_;
-
-    DISALLOW_COPY_AND_ASSIGN(ScopedUkmTimer);
-  };
-
-  UkmTimeAggregator(String event_name,
-                    int64_t source_id,
-                    ukm::UkmRecorder*,
-                    const Vector<String>& metric_names,
-                    TimeDelta event_frequency);
-  ~UkmTimeAggregator();
-
-  // Create a scoped timer with the index of the metric and an optional
-  // histogram counter. Note the index has to correspond to the right index in
-  // metric_names. For example, if metric_names is {"a", "b", "c"} then index
-  // 1 refers to metric "a", which will end up generating "a.Average" and
-  // "a.WorstCase" metrics.
-  ScopedUkmTimer GetScopedTimer(
-      size_t metric_index,
-      CustomCountHistogram* histogram_counter = nullptr);
-
-  void RecordSample(size_t metric_index,
-                    TimeTicks start,
-                    TimeTicks end,
-                    CustomCountHistogram* histogram_counter);
-
- private:
-  struct MetricRecord {
-    String worst_case_metric_name;
-    String average_metric_name;
-    TimeDelta total_duration;
-    TimeDelta worst_case_duration;
-    size_t sample_count = 0u;
-
-    void reset() {
-      total_duration = TimeDelta();
-      worst_case_duration = TimeDelta();
-      sample_count = 0u;
-    }
-  };
-
-  void FlushIfNeeded(TimeTicks current_time);
-  void Flush(TimeTicks current_time);
-
-  const String event_name_;
-  const int64_t source_id_;
-  ukm::UkmRecorder* const recorder_;
-  const TimeDelta event_frequency_;
-  TimeTicks last_flushed_time_;
-  Vector<MetricRecord> metric_records_;
-  bool has_data_ = false;
-
-  DISALLOW_COPY_AND_ASSIGN(UkmTimeAggregator);
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_UKM_TIME_AGGREGATOR_H_
diff --git a/third_party/blink/renderer/platform/ukm_time_aggregator_test.cc b/third_party/blink/renderer/platform/ukm_time_aggregator_test.cc
deleted file mode 100644
index 99ad4f02..0000000
--- a/third_party/blink/renderer/platform/ukm_time_aggregator_test.cc
+++ /dev/null
@@ -1,157 +0,0 @@
-// Copyright 2018 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 "third_party/blink/renderer/platform/ukm_time_aggregator.h"
-
-#include "components/ukm/test_ukm_recorder.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/testing/wtf/scoped_mock_clock.h"
-
-namespace blink {
-namespace {
-
-// These tests must use metrics defined in ukm.xml
-const char* kEvent = "Blink.UpdateTime";
-const char* kMetric1 = "Compositing";
-const char* kMetric1Average = "Compositing.Average";
-const char* kMetric1WorstCase = "Compositing.WorstCase";
-const char* kMetric2 = "Paint";
-const char* kMetric2Average = "Paint.Average";
-const char* kMetric2WorstCase = "Paint.WorstCase";
-
-TEST(UkmTimeAggregatorTest, EmptyEventsNotRecorded) {
-  // Although the tests use a mock clock, the UKM aggregator checks if the
-  // system has a high resolution clock before recording results. As a result,
-  // the tests will fail if the system does not have a high resolution clock.
-  if (!base::TimeTicks::IsHighResolution())
-    return;
-
-  WTF::ScopedMockClock clock;
-  ukm::TestUkmRecorder recorder;
-  int64_t source_id = ukm::UkmRecorder::GetNewSourceID();
-  std::unique_ptr<UkmTimeAggregator> aggregator(
-      new UkmTimeAggregator(kEvent, source_id, &recorder, {kMetric1, kMetric2},
-                            TimeDelta::FromSeconds(1)));
-  clock.Advance(TimeDelta::FromSeconds(10));
-  aggregator.reset();
-
-  EXPECT_EQ(recorder.sources_count(), 0u);
-  EXPECT_EQ(recorder.entries_count(), 0u);
-}
-
-TEST(UkmTimeAggregatorTest, EventsRecordedPerSecond) {
-  // Although the tests use a mock clock, the UKM aggregator checks if the
-  // system has a high resolution clock before recording results. As a result,
-  // the tests will fail if the system does not have a high resolution clock.
-  if (!base::TimeTicks::IsHighResolution())
-    return;
-
-  WTF::ScopedMockClock clock;
-  ukm::TestUkmRecorder recorder;
-  int64_t source_id = ukm::UkmRecorder::GetNewSourceID();
-  std::unique_ptr<UkmTimeAggregator> aggregator(
-      new UkmTimeAggregator(kEvent, source_id, &recorder, {kMetric1, kMetric2},
-                            TimeDelta::FromSeconds(1)));
-  // Have 100 events 99ms each; if the records are recorded once per second, we
-  // should expect 9 records to be recorded while the timer ticks. 0-1, 1-2,
-  // ..., 8-9 seconds.
-  for (int i = 0; i < 100; ++i) {
-    auto timer = aggregator->GetScopedTimer(i % 2);
-    clock.Advance(TimeDelta::FromMilliseconds(99));
-  }
-
-  EXPECT_EQ(recorder.entries_count(), 9u);
-
-  // Once we reset, we record any remaining samples into one more entry, for a
-  // total of 10.
-  aggregator.reset();
-
-  EXPECT_EQ(recorder.entries_count(), 10u);
-  auto entries = recorder.GetEntriesByName(kEvent);
-  EXPECT_EQ(entries.size(), 10u);
-
-  for (auto* entry : entries) {
-    EXPECT_TRUE(ukm::TestUkmRecorder::EntryHasMetric(entry, kMetric1Average));
-    const int64_t* metric1_average =
-        ukm::TestUkmRecorder::GetEntryMetric(entry, kMetric1Average);
-    EXPECT_NEAR(*metric1_average / 1e6, 0.099, 0.0001);
-
-    EXPECT_TRUE(ukm::TestUkmRecorder::EntryHasMetric(entry, kMetric1WorstCase));
-    const int64_t* metric1_worst =
-        ukm::TestUkmRecorder::GetEntryMetric(entry, kMetric1WorstCase);
-    EXPECT_NEAR(*metric1_worst / 1e6, 0.099, 0.0001);
-
-    EXPECT_TRUE(ukm::TestUkmRecorder::EntryHasMetric(entry, kMetric2Average));
-    const int64_t* metric2_average =
-        ukm::TestUkmRecorder::GetEntryMetric(entry, kMetric2Average);
-    EXPECT_NEAR(*metric2_average / 1e6, 0.099, 0.0001);
-
-    EXPECT_TRUE(ukm::TestUkmRecorder::EntryHasMetric(entry, kMetric2WorstCase));
-    const int64_t* metric2_worst =
-        ukm::TestUkmRecorder::GetEntryMetric(entry, kMetric2WorstCase);
-    EXPECT_NEAR(*metric2_worst / 1e6, 0.099, 0.0001);
-  }
-}
-
-TEST(UkmTimeAggregatorTest, EventsAveragedCorrectly) {
-  // Although the tests use a mock clock, the UKM aggregator checks if the
-  // system has a high resolution clock before recording results. As a result,
-  // the tests will fail if the system does not have a high resolution clock.
-  if (!base::TimeTicks::IsHighResolution())
-    return;
-
-  WTF::ScopedMockClock clock;
-  ukm::TestUkmRecorder recorder;
-  int64_t source_id = ukm::UkmRecorder::GetNewSourceID();
-  std::unique_ptr<UkmTimeAggregator> aggregator(
-      new UkmTimeAggregator(kEvent, source_id, &recorder, {kMetric1, kMetric2},
-                            TimeDelta::FromSeconds(10000)));
-  // 1, 2, and 3 seconds.
-  for (int i = 1; i <= 3; ++i) {
-    auto timer = aggregator->GetScopedTimer(0);
-    clock.Advance(TimeDelta::FromSeconds(i));
-  }
-
-  // 3, 3, 3, and then 1 outside of the loop.
-  for (int i = 0; i < 3; ++i) {
-    auto timer = aggregator->GetScopedTimer(1);
-    clock.Advance(TimeDelta::FromSeconds(3));
-  }
-  {
-    auto timer = aggregator->GetScopedTimer(1);
-    clock.Advance(TimeDelta::FromSeconds(1));
-  }
-
-  aggregator.reset();
-  auto entries = recorder.GetEntriesByName(kEvent);
-  EXPECT_EQ(entries.size(), 1u);
-  auto* entry = entries[0];
-
-  EXPECT_TRUE(ukm::TestUkmRecorder::EntryHasMetric(entry, kMetric1Average));
-  const int64_t* metric1_average =
-      ukm::TestUkmRecorder::GetEntryMetric(entry, kMetric1Average);
-  // metric1 (1, 2, 3) average is 2
-  EXPECT_NEAR(*metric1_average / 1e6, 2.0, 0.0001);
-
-  EXPECT_TRUE(ukm::TestUkmRecorder::EntryHasMetric(entry, kMetric1WorstCase));
-  const int64_t* metric1_worst =
-      ukm::TestUkmRecorder::GetEntryMetric(entry, kMetric1WorstCase);
-  // metric1 (1, 2, 3) worst case is 3
-  EXPECT_NEAR(*metric1_worst / 1e6, 3.0, 0.0001);
-
-  EXPECT_TRUE(ukm::TestUkmRecorder::EntryHasMetric(entry, kMetric2Average));
-  const int64_t* metric2_average =
-      ukm::TestUkmRecorder::GetEntryMetric(entry, kMetric2Average);
-  // metric1 (3, 3, 3, 1) average is 2.5
-  EXPECT_NEAR(*metric2_average / 1e6, 2.5, 0.0001);
-
-  EXPECT_TRUE(ukm::TestUkmRecorder::EntryHasMetric(entry, kMetric2WorstCase));
-  const int64_t* metric2_worst =
-      ukm::TestUkmRecorder::GetEntryMetric(entry, kMetric2WorstCase);
-  // metric1 (3, 3, 3, 1) worst case is 3
-  EXPECT_NEAR(*metric2_worst / 1e6, 3.0, 0.0001);
-}
-
-}  // namespace
-}  // namespace blink
diff --git a/third_party/libaom/README.chromium b/third_party/libaom/README.chromium
index f48e3b3..13018444 100644
--- a/third_party/libaom/README.chromium
+++ b/third_party/libaom/README.chromium
@@ -3,7 +3,7 @@
 URL: https://aomedia.googlesource.com/aom/
 Version: 0
 Date: Monday October 08 2018
-Branch: master
+Branch: m70-3538
 Commit: a5078bf8d0e7c01eab670cfc1cfe7b9fb065e931
 License: BSD
 License File: source/libaom/LICENSE
diff --git a/third_party/tcmalloc/chromium/src/base/basictypes.h b/third_party/tcmalloc/chromium/src/base/basictypes.h
index 42dbe5c..24a6a8a6 100644
--- a/third_party/tcmalloc/chromium/src/base/basictypes.h
+++ b/third_party/tcmalloc/chromium/src/base/basictypes.h
@@ -83,7 +83,7 @@
 const  int8  kint8min   = (   (  int8) 0x80);
 const  int16 kint16min  = (   ( int16) 0x8000);
 const  int32 kint32min  = (   ( int32) 0x80000000);
-const  int64 kint64min =  ( (((uint64) kint32min) << 32) | 0 );
+const  int64 kint64min =  (-kint64max - 1LL);
 
 // Define the "portable" printf and scanf macros, if they're not
 // already there (via the inttypes.h we #included above, hopefully).
diff --git a/third_party/tcmalloc/chromium/src/base/logging.h b/third_party/tcmalloc/chromium/src/base/logging.h
index 659605ace..b9a0e16 100644
--- a/third_party/tcmalloc/chromium/src/base/logging.h
+++ b/third_party/tcmalloc/chromium/src/base/logging.h
@@ -199,7 +199,7 @@
 inline void LogPrintf(int severity, const char* pat, va_list ap) {
   // We write directly to the stderr file descriptor and avoid FILE
   // buffering because that may invoke malloc()
-  char buf[600];
+  char buf[1600];
   perftools_vsnprintf(buf, sizeof(buf)-1, pat, ap);
   if (buf[0] != '\0' && buf[strlen(buf)-1] != '\n') {
     assert(strlen(buf)+1 < sizeof(buf));
diff --git a/third_party/tcmalloc/chromium/src/page_heap.h b/third_party/tcmalloc/chromium/src/page_heap.h
index bf50394..5e9cc4a 100644
--- a/third_party/tcmalloc/chromium/src/page_heap.h
+++ b/third_party/tcmalloc/chromium/src/page_heap.h
@@ -85,18 +85,6 @@
   typedef TCMalloc_PageMap3<BITS-kPageShift> Type;
 };
 
-#ifndef TCMALLOC_SMALL_BUT_SLOW
-// x86-64 and arm64 are using 48 bits of address space. So we can use
-// just two level map, but since initial ram consumption of this mode
-// is a bit on the higher side, we opt-out of it in
-// TCMALLOC_SMALL_BUT_SLOW mode.
-template <> class MapSelector<48> {
- public:
-  typedef TCMalloc_PageMap2<48-kPageShift> Type;
-};
-
-#endif // TCMALLOC_SMALL_BUT_SLOW
-
 // A two-level map for 32-bit machines
 template <> class MapSelector<32> {
  public:
diff --git a/third_party/tcmalloc/chromium/src/tcmalloc.cc b/third_party/tcmalloc/chromium/src/tcmalloc.cc
index d828590..328ea24 100644
--- a/third_party/tcmalloc/chromium/src/tcmalloc.cc
+++ b/third_party/tcmalloc/chromium/src/tcmalloc.cc
@@ -311,6 +311,9 @@
   //    Windows: _msize()
   size_t tc_malloc_size(void* p) PERFTOOLS_NOTHROW
       ATTRIBUTE_SECTION(google_malloc);
+
+  void* tc_malloc_skip_new_handler(size_t size)
+      ATTRIBUTE_SECTION(google_malloc);
 }  // extern "C"
 #endif  // #ifndef _WIN32
 
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index b1d380f..d430992b 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -3656,6 +3656,7 @@
   <int value="1" label="No dialog: blocked, no user gesture"/>
   <int value="2" label="No dialog: blocked, multiple confirmation panels"/>
   <int value="3" label="Show dialog"/>
+  <int value="4" label="No dialog: auto_cancel was true"/>
 </enum>
 
 <enum name="BillingIdStatus">
@@ -17319,7 +17320,7 @@
   <int value="131" label="kSocket"/>
   <int value="132" label="kStartupPages"/>
   <int value="133" label="kStorage"/>
-  <int value="134" label="kStreamsPrivate"/>
+  <int value="134" label="kDeleted_StreamsPrivate"/>
   <int value="135" label="kSyncFileSystem"/>
   <int value="136" label="kSystemPrivate"/>
   <int value="137" label="kSystemDisplay"/>
@@ -51188,14 +51189,15 @@
   <int value="2" label="SuccessAlreadyPresenting"/>
   <int value="3" label="VRDisplayCannotPresent"/>
   <int value="4" label="PresentationNotSupportedByDisplay"/>
-  <int value="5" label="VRDisplayNotFound"/>
+  <int value="5" label="VRDisplayNotFound (obsolete)"/>
   <int value="6" label="NotInitiatedByUserGesture"/>
   <int value="7" label="InvalidNumberOfLayers"/>
   <int value="8" label="InvalidLayerSource"/>
   <int value="9" label="LayerSourceMissingWebGLContext"/>
   <int value="10" label="InvalidLayerBounds"/>
-  <int value="11" label="ServiceInactive"/>
-  <int value="12" label="RequestDenied"/>
+  <int value="11" label="ServiceInactive (obsolete)"/>
+  <int value="12" label="RequestDenied (obsolete)"/>
+  <int value="13" label="FullscreenNotEnabled (obsolete in M59)"/>
 </enum>
 
 <enum name="VRPresentationStartAction">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index f3445f7..749c2aa4 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -7540,6 +7540,17 @@
   </summary>
 </histogram>
 
+<histogram name="Autofill.StrikeDatabase.NthStrikeAdded.CreditCardSave"
+    units="strikes" expires_after="2019-03-18">
+  <owner>jsaul@google.com</owner>
+  <owner>annelim@google.com</owner>
+  <summary>
+    Records the number of &quot;strikes&quot; a given card has, when a user
+    dismisses a prompt to save a new credit card. The strike count is
+    incremented each time the user dismisses the prompt.
+  </summary>
+</histogram>
+
 <histogram name="Autofill.SubmittedCardState" enum="AutofillSubmittedCardState">
   <owner>dlkumar@google.com</owner>
   <summary>
@@ -42869,7 +42880,7 @@
 </histogram>
 
 <histogram name="Media.D3D11.WasVideoSupported"
-    enum="D3D11VideoNotSupportedReason" expires_after="M70">
+    enum="D3D11VideoNotSupportedReason" expires_after="2019-12-31">
   <owner>liberato@chromium.org</owner>
   <owner>sandersd@chromium.org</owner>
   <owner>tmathmeyer@chromium.org</owner>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index 220b11f..e93eb33f 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -42,6 +42,51 @@
   </metric>
 </event>
 
+<event name="AdPageLoad">
+  <owner>johnidel@chromium.org</owner>
+  <owner>jkarlin@chromium.org</owner>
+  <summary>
+    Recorded when a page has loadded non-zero ad bytes, and the page is being
+    destroyed/navigated.
+  </summary>
+  <metric name="AdBytes">
+    <summary>
+      Amount of bytes used to load ad resource on the page. Includes resources
+      that did not finish, and top-level ads.
+    </summary>
+  </metric>
+  <metric name="AdBytesPerSecond">
+    <summary>
+      Amount of bytes used to load ad resources on the page, per second the page
+      was alive after commit.
+    </summary>
+  </metric>
+  <metric name="AdBytesPerSecondAfterInteractive">
+    <summary>
+      Amount of bytes used to load ad resources on the page per second after the
+      page was interactive.
+    </summary>
+  </metric>
+  <metric name="AdJavascriptBytes">
+    <summary>
+      Amount of bytes used to load ad resources with a supported javascript mime
+      type on the page.
+    </summary>
+  </metric>
+  <metric name="AdVideoBytes">
+    <summary>
+      Amount of bytes used to load ad resources with a video mime type on the
+      page.
+    </summary>
+  </metric>
+  <metric name="TotalBytes">
+    <summary>
+      Amount of bytes used to load resources on the page. Includes resources
+      that did not finish.
+    </summary>
+  </metric>
+</event>
+
 <event name="AbusiveExperienceHeuristic.TabUnder">
   <owner>csharrison@chromium.org</owner>
   <metric name="DidTabUnder">
diff --git a/tools/perf/benchmark.csv b/tools/perf/benchmark.csv
index 5425e0c5..1b9d8d8 100644
--- a/tools/perf/benchmark.csv
+++ b/tools/perf/benchmark.csv
@@ -4,7 +4,7 @@
 angle_perftests,"jmadill@chromium.org, chrome-gpu-perf-owners@chromium.org",Internals>GPU>ANGLE,,
 blink_perf.accessibility,dmazzoni@chromium.org,['Blink>Accessibility'],https://bit.ly/blink-perf-benchmarks,
 blink_perf.bindings,"jbroman@chromium.org, yukishiino@chromium.org, haraken@chromium.org",,https://bit.ly/blink-perf-benchmarks,
-blink_perf.canvas,fserb@chromium.org,,https://bit.ly/blink-perf-benchmarks,
+blink_perf.canvas,fserb@chromium.org,Blink>Canvas,https://bit.ly/blink-perf-benchmarks,
 blink_perf.css,"futhark@chromium.org, andruud@chromium.org",Blink>CSS,https://bit.ly/blink-perf-benchmarks,
 blink_perf.dom,"hayato@chromium.org, tkent@chromium.org, yosin@chromium.org",Blink>DOM,https://bit.ly/blink-perf-benchmarks,
 blink_perf.events,hayato@chromium.org,Blink>DOM,https://bit.ly/blink-perf-benchmarks,
diff --git a/tools/perf/benchmarks/blink_perf.py b/tools/perf/benchmarks/blink_perf.py
index 9e8fb856..9d0eb9f 100644
--- a/tools/perf/benchmarks/blink_perf.py
+++ b/tools/perf/benchmarks/blink_perf.py
@@ -395,7 +395,8 @@
 
 
 @benchmark.Info(emails=['fserb@chromium.org'],
-                documentation_url='https://bit.ly/blink-perf-benchmarks')
+                documentation_url='https://bit.ly/blink-perf-benchmarks',
+                component='Blink>Canvas')
 class BlinkPerfCanvas(_BlinkPerfBenchmark):
   subdir = 'canvas'
 
diff --git a/ui/accessibility/platform/ax_platform_node_mac.mm b/ui/accessibility/platform/ax_platform_node_mac.mm
index 89f6b3d..2a8fe64f8 100644
--- a/ui/accessibility/platform/ax_platform_node_mac.mm
+++ b/ui/accessibility/platform/ax_platform_node_mac.mm
@@ -259,6 +259,8 @@
 
 EventMap BuildEventMap() {
   const EventMap::value_type events[] = {
+      {ax::mojom::Event::kCheckedStateChanged,
+       NSAccessibilityValueChangedNotification},
       {ax::mojom::Event::kFocus,
        NSAccessibilityFocusedUIElementChangedNotification},
       {ax::mojom::Event::kFocusContext,
@@ -763,6 +765,13 @@
   if (ui::IsNameExposedInAXValueForRole(role))
     return [self getStringAttribute:ax::mojom::StringAttribute::kName];
 
+  if (node_->HasIntAttribute(ax::mojom::IntAttribute::kCheckedState)) {
+    // Mixed checkbox state not currently supported in views, but could be.
+    // See browser_accessibility_cocoa.mm for details.
+    const auto checkedState = static_cast<ax::mojom::CheckedState>(
+        node_->GetIntAttribute(ax::mojom::IntAttribute::kCheckedState));
+    return checkedState == ax::mojom::CheckedState::kTrue ? @1 : @0;
+  }
   return [self getStringAttribute:ax::mojom::StringAttribute::kValue];
 }
 
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index 9e493e3..15faebd 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -5598,6 +5598,7 @@
   switch (event) {
     case ax::mojom::Event::kAlert:
       return EVENT_SYSTEM_ALERT;
+    case ax::mojom::Event::kCheckedStateChanged:
     case ax::mojom::Event::kExpandedChanged:
       return EVENT_OBJECT_STATECHANGE;
     case ax::mojom::Event::kFocus:
diff --git a/ui/aura/mus/window_tree_client.cc b/ui/aura/mus/window_tree_client.cc
index 9a5c9e6b..ca699f5 100644
--- a/ui/aura/mus/window_tree_client.cc
+++ b/ui/aura/mus/window_tree_client.cc
@@ -124,31 +124,6 @@
   return key == client::kModalKey;
 }
 
-// Create and return a MouseEvent or TouchEvent from |event| if |event| is a
-// PointerEvent, otherwise return the copy of |event|.
-std::unique_ptr<ui::Event> MapEvent(const ui::Event& event) {
-  if (event.IsPointerEvent()) {
-    const ui::PointerEvent& pointer_event = *event.AsPointerEvent();
-    // Use a switch statement in case more pointer types are added.
-    switch (pointer_event.pointer_details().pointer_type) {
-      case ui::EventPointerType::POINTER_TYPE_MOUSE:
-        if (event.type() == ui::ET_POINTER_WHEEL_CHANGED)
-          return std::make_unique<ui::MouseWheelEvent>(pointer_event);
-        return std::make_unique<ui::MouseEvent>(pointer_event);
-      case ui::EventPointerType::POINTER_TYPE_TOUCH:
-      case ui::EventPointerType::POINTER_TYPE_PEN:
-        return std::make_unique<ui::TouchEvent>(pointer_event);
-      case ui::EventPointerType::POINTER_TYPE_ERASER:
-        NOTIMPLEMENTED();
-        break;
-      case ui::EventPointerType::POINTER_TYPE_UNKNOWN:
-        NOTREACHED();
-        break;
-    }
-  }
-  return ui::Event::Clone(event);
-}
-
 }  // namespace
 
 // static
@@ -1295,10 +1270,22 @@
   DCHECK(event);
   WindowMus* window = GetWindowByServerId(window_id);  // May be null.
 
+  DCHECK(!event->IsPointerEvent());
+
   if (matches_pointer_watcher && has_pointer_watcher_) {
-    DCHECK(event->IsPointerEvent());
-    std::unique_ptr<ui::Event> event_in_dip(ui::Event::Clone(*event));
-    NotifyPointerEventObserved(event_in_dip->AsPointerEvent(), display_id,
+    // TODO(sky): remove this once PointerWatcher doesn't need PointerEvent.
+    // https://crbug.com/865781
+    std::unique_ptr<ui::Event> pointer_event;
+    if (event->IsMouseEvent()) {
+      pointer_event =
+          std::make_unique<ui::PointerEvent>(*event->AsMouseEvent());
+    } else if (event->IsTouchEvent()) {
+      pointer_event =
+          std::make_unique<ui::PointerEvent>(*event->AsTouchEvent());
+    } else {
+      NOTREACHED();
+    }
+    NotifyPointerEventObserved(pointer_event->AsPointerEvent(), display_id,
                                window);
   }
 
@@ -1307,13 +1294,10 @@
   if (!window || !window->GetWindow()->GetHost()) {
     EnvInputStateController* env_controller =
         Env::GetInstance()->env_controller();
-    std::unique_ptr<ui::Event> mapped_event = MapEvent(*event.get());
-    if (mapped_event->IsMouseEvent()) {
-      env_controller->UpdateStateForMouseEvent(nullptr,
-                                               *mapped_event->AsMouseEvent());
-    } else if (mapped_event->IsTouchEvent()) {
-      env_controller->UpdateStateForTouchEvent(*mapped_event->AsTouchEvent());
-    }
+    if (event->IsMouseEvent())
+      env_controller->UpdateStateForMouseEvent(nullptr, *event->AsMouseEvent());
+    else if (event->IsTouchEvent())
+      env_controller->UpdateStateForTouchEvent(*event->AsTouchEvent());
     tree_->OnWindowInputEventAck(event_id, ws::mojom::EventResult::UNHANDLED);
     return;
   }
@@ -1327,10 +1311,6 @@
     }
   }
 
-  // TODO(moshayedi): crbug.com/617222. No need to convert to ui::MouseEvent or
-  // ui::TouchEvent once we have proper support for pointer events.
-  std::unique_ptr<ui::Event> mapped_event = MapEvent(*event.get());
-  ui::Event* event_to_dispatch = mapped_event.get();
   // |ack_handler| may use |event_to_dispatch| from its destructor, so it needs
   // to be destroyed after |event_to_dispatch| is destroyed.
   EventAckHandler ack_handler(CreateEventResultCallback(event_id));
@@ -1338,12 +1318,12 @@
   if (!event->IsKeyEvent()) {
     // Set |window| as the target, except for key events. Key events go to the
     // focused window, which may have changed by the time we process the event.
-    ui::Event::DispatcherApi(event_to_dispatch).set_target(window->GetWindow());
+    ui::Event::DispatcherApi(event.get()).set_target(window->GetWindow());
   }
 
-  GetWindowTreeHostMus(window)->SendEventToSink(event_to_dispatch);
+  GetWindowTreeHostMus(window)->SendEventToSink(event.get());
 
-  ack_handler.set_handled(event_to_dispatch->handled());
+  ack_handler.set_handled(event->handled());
 }
 
 void WindowTreeClient::OnPointerEventObserved(std::unique_ptr<ui::Event> event,
diff --git a/ui/aura/mus/window_tree_client_unittest.cc b/ui/aura/mus/window_tree_client_unittest.cc
index 003f0278..2ca4cce 100644
--- a/ui/aura/mus/window_tree_client_unittest.cc
+++ b/ui/aura/mus/window_tree_client_unittest.cc
@@ -947,13 +947,13 @@
   const gfx::Point event_location(2, 3);
   const uint32_t event_id = 1;
   window_delegate.set_event_id(event_id);
-  ui::PointerEvent pointer_event(
-      ui::ET_POINTER_MOVED, event_location, gfx::Point(), ui::EF_NONE, 0,
-      ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE, 0),
-      base::TimeTicks());
+  ui::MouseEvent mouse_event(
+      ui::ET_MOUSE_MOVED, event_location, event_location, ui::EventTimeForNow(),
+      ui::EF_NONE, ui::EF_NONE,
+      ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE, 0));
   window_tree_client()->OnWindowInputEvent(event_id, server_id(&child),
                                            window_tree_host.display_id(),
-                                           ui::Event::Clone(pointer_event), 0);
+                                           ui::Event::Clone(mouse_event), 0);
   EXPECT_TRUE(window_tree()->WasEventAcked(event_id));
   EXPECT_EQ(ws::mojom::EventResult::HANDLED,
             window_tree()->GetEventResult(event_id));
@@ -983,13 +983,13 @@
   const gfx::Point event_location(2, 3);
   const uint32_t event_id = 1;
   window_delegate.set_event_id(event_id);
-  ui::PointerEvent pointer_event(
-      ui::ET_POINTER_DOWN, event_location, gfx::Point(), ui::EF_NONE, 0,
-      ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_PEN, 0),
-      ui::EventTimeForNow());
+  ui::MouseEvent mouse_event(
+      ui::ET_MOUSE_PRESSED, event_location, event_location,
+      ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE,
+      ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_PEN, 0));
   window_tree_client()->OnWindowInputEvent(event_id, server_id(&child),
                                            window_tree_host.display_id(),
-                                           ui::Event::Clone(pointer_event), 0);
+                                           ui::Event::Clone(mouse_event), 0);
 
   // Pen event was handled.
   EXPECT_TRUE(window_tree()->WasEventAcked(event_id));
@@ -1283,14 +1283,13 @@
   const gfx::Point event_location(2, 3);
   uint32_t event_id = 1;
   window_delegate.set_event_id(event_id);
-  ui::PointerEvent pointer_event_down(
-      ui::ET_POINTER_DOWN, event_location, event_location,
-      ui::EF_LEFT_MOUSE_BUTTON, 0,
-      ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE, 0),
-      ui::EventTimeForNow());
+  ui::MouseEvent mouse_event_down(
+      ui::ET_MOUSE_PRESSED, event_location, event_location,
+      ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0,
+      ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE, 0));
   window_tree_client()->OnWindowInputEvent(
       event_id, server_id(&child), window_tree_host.display_id(),
-      ui::Event::Clone(pointer_event_down), 0);
+      ui::Event::Clone(mouse_event_down), 0);
   EXPECT_TRUE(window_tree()->WasEventAcked(event_id));
   EXPECT_EQ(ws::mojom::EventResult::HANDLED,
             window_tree()->GetEventResult(event_id));
@@ -1303,14 +1302,13 @@
   const gfx::Point event_location1(4, 5);
   event_id = 2;
   window_delegate.set_event_id(event_id);
-  ui::PointerEvent pointer_event_up(
-      ui::ET_POINTER_UP, event_location1, event_location,
-      ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON,
-      ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE, 0),
-      ui::EventTimeForNow());
-  window_tree_client()->OnWindowInputEvent(
-      event_id, kInvalidServerId, window_tree_host.display_id(),
-      ui::Event::Clone(pointer_event_up), 0);
+  ui::MouseEvent mouse_event_up(
+      ui::ET_MOUSE_RELEASED, event_location1, event_location,
+      ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON,
+      ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE, 0));
+  window_tree_client()->OnWindowInputEvent(event_id, kInvalidServerId,
+                                           window_tree_host.display_id(),
+                                           ui::Event::Clone(mouse_event_up), 0);
   EXPECT_TRUE(window_tree()->WasEventAcked(event_id));
   // WindowTreeClient::OnWindowInputEvent cannot find a target window with
   // kInvalidServerId but should use the event to update event states kept in
@@ -1347,13 +1345,12 @@
   const gfx::Point event_location(2, 3);
   uint32_t event_id = 1;
   window_delegate.set_event_id(event_id);
-  ui::PointerEvent pointer_event_down(
-      ui::ET_POINTER_DOWN, event_location, gfx::Point(), 0, 0,
-      ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 0),
-      ui::EventTimeForNow());
+  ui::TouchEvent touch_event_down(
+      ui::ET_TOUCH_PRESSED, event_location, ui::EventTimeForNow(),
+      ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 0));
   window_tree_client()->OnWindowInputEvent(
       event_id, server_id(&child), window_tree_host.display_id(),
-      ui::Event::Clone(pointer_event_down), 0);
+      ui::Event::Clone(touch_event_down), 0);
   EXPECT_TRUE(window_tree()->WasEventAcked(event_id));
   EXPECT_EQ(ws::mojom::EventResult::HANDLED,
             window_tree()->GetEventResult(event_id));
@@ -1363,13 +1360,12 @@
 
   event_id = 2;
   window_delegate.set_event_id(event_id);
-  ui::PointerEvent pointer_event_up(
-      ui::ET_POINTER_UP, event_location, gfx::Point(), 0, 0,
-      ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 0),
-      ui::EventTimeForNow());
-  window_tree_client()->OnWindowInputEvent(
-      event_id, kInvalidServerId, window_tree_host.display_id(),
-      ui::Event::Clone(pointer_event_up), 0);
+  ui::TouchEvent touch_event_up(
+      ui::ET_TOUCH_RELEASED, event_location, ui::EventTimeForNow(),
+      ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 0));
+  window_tree_client()->OnWindowInputEvent(event_id, kInvalidServerId,
+                                           window_tree_host.display_id(),
+                                           ui::Event::Clone(touch_event_up), 0);
   EXPECT_TRUE(window_tree()->WasEventAcked(event_id));
   // WindowTreeClient::OnWindowInputEvent cannot find a target window with
   // kInvalidServerId but should use the event to update event states kept in
@@ -1480,12 +1476,12 @@
   window_tree_client_impl()->StartPointerWatcher(false /* want_moves */);
 
   // Simulate the server dispatching an event that also matched the observer.
-  std::unique_ptr<ui::PointerEvent> pointer_event_down(new ui::PointerEvent(
-      ui::ET_POINTER_DOWN, gfx::Point(), gfx::Point(), ui::EF_CONTROL_DOWN, 0,
+  ui::TouchEvent touch_event_down(
+      ui::ET_TOUCH_PRESSED, gfx::Point(), ui::EventTimeForNow(),
       ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 1),
-      base::TimeTicks::Now()));
-  window_tree_client()->OnWindowInputEvent(1, server_id(top_level), 0,
-                                           std::move(pointer_event_down), true);
+      ui::EF_CONTROL_DOWN);
+  window_tree_client()->OnWindowInputEvent(
+      1, server_id(top_level), 0, ui::Event::Clone(touch_event_down), true);
 
   // Delegate sensed the event.
   const ui::Event* last_event = last_event_observed();
diff --git a/ui/chromeos/search_box/search_box_view_base.cc b/ui/chromeos/search_box/search_box_view_base.cc
index 879b340..a0ddae6e 100644
--- a/ui/chromeos/search_box/search_box_view_base.cc
+++ b/ui/chromeos/search_box/search_box_view_base.cc
@@ -351,8 +351,6 @@
     search_box_->DestroyTouchSelection();
   }
 
-  search_box_right_space_->SetVisible(!active);
-
   UpdateSearchBoxBorder();
   UpdateKeyboardVisibility();
   UpdateButtonsVisisbility();
@@ -481,19 +479,25 @@
 void SearchBoxViewBase::UpdateButtonsVisisbility() {
   DCHECK(close_button_ && assistant_button_);
 
-  bool should_show_close_button =
+  const bool should_show_close_button =
       !search_box_->text().empty() ||
       (show_close_button_when_active_ && is_search_box_active_);
-  bool should_show_assistant_button =
+  const bool should_show_assistant_button =
       show_assistant_button_ && !should_show_close_button;
+  const bool should_show_search_box_right_space =
+      !(should_show_close_button || should_show_assistant_button);
 
   if (close_button_->visible() == should_show_close_button &&
-      assistant_button_->visible() == should_show_assistant_button) {
-    return;
+      assistant_button_->visible() == should_show_assistant_button &&
+      search_box_right_space_->visible() ==
+      should_show_search_box_right_space) {
+      return;
   }
 
   close_button_->SetVisible(should_show_close_button);
   assistant_button_->SetVisible(should_show_assistant_button);
+  search_box_right_space_->SetVisible(should_show_search_box_right_space);
+
   content_container_->Layout();
 }
 
diff --git a/ui/gl/gl_image.cc b/ui/gl/gl_image.cc
index 8525c6c..48b5a04 100644
--- a/ui/gl/gl_image.cc
+++ b/ui/gl/gl_image.cc
@@ -19,4 +19,21 @@
   return Type::NONE;
 }
 
+#if defined(OS_ANDROID)
+std::unique_ptr<GLImage::ScopedHardwareBuffer> GLImage::GetAHardwareBuffer() {
+  return nullptr;
+}
+
+GLImage::ScopedHardwareBuffer::ScopedHardwareBuffer(
+    base::android::ScopedHardwareBufferHandle handle,
+    base::ScopedFD fence_fd)
+    : handle_(std::move(handle)), fence_fd_(std::move(fence_fd)) {}
+
+GLImage::ScopedHardwareBuffer::~ScopedHardwareBuffer() = default;
+
+base::ScopedFD GLImage::ScopedHardwareBuffer::TakeFence() {
+  return std::move(fence_fd_);
+}
+#endif
+
 }  // namespace gl
diff --git a/ui/gl/gl_image.h b/ui/gl/gl_image.h
index 3402173..640ad8ed 100644
--- a/ui/gl/gl_image.h
+++ b/ui/gl/gl_image.h
@@ -22,6 +22,12 @@
 #include "ui/gfx/overlay_transform.h"
 #include "ui/gl/gl_export.h"
 
+#if defined(OS_ANDROID)
+#include <android/hardware_buffer.h>
+#include "base/android/scoped_hardware_buffer_handle.h"
+#include "base/files/scoped_file.h"
+#endif
+
 namespace base {
 namespace trace_event {
 class ProcessMemoryDump;
@@ -105,8 +111,32 @@
   // removed. https://crbug.com/581777#c36
   virtual bool EmulatingRGB() const;
 
+#if defined(OS_ANDROID)
+  class GL_EXPORT ScopedHardwareBuffer {
+   public:
+    ScopedHardwareBuffer(base::android::ScopedHardwareBufferHandle handle,
+                         base::ScopedFD fence_fd);
+    virtual ~ScopedHardwareBuffer();
+
+    AHardwareBuffer* buffer() const { return handle_.get(); }
+    base::ScopedFD TakeFence();
+
+   private:
+    base::android::ScopedHardwareBufferHandle handle_;
+    base::ScopedFD fence_fd_;
+  };
+
+  // Provides the buffer backing this image, if it is backed by an
+  // AHardwareBuffer. The ScopedHardwareBuffer returned may include a fence
+  // which will be signaled when all pending work for the buffer has been
+  // finished and it can be safely read from.
+  // The buffer is guaranteed to be valid until the lifetime of the object
+  // returned.
+  virtual std::unique_ptr<ScopedHardwareBuffer> GetAHardwareBuffer();
+#endif
+
   // An identifier for subclasses. Necessary for safe downcasting.
-  enum class Type { NONE, MEMORY, IOSURFACE, DXGI_IMAGE, A_HARDWARE_BUFFER };
+  enum class Type { NONE, MEMORY, IOSURFACE, DXGI_IMAGE };
   virtual Type GetType() const;
 
  protected:
diff --git a/ui/gl/gl_image_ahardwarebuffer.cc b/ui/gl/gl_image_ahardwarebuffer.cc
index f6530e65..89e97dc 100644
--- a/ui/gl/gl_image_ahardwarebuffer.cc
+++ b/ui/gl/gl_image_ahardwarebuffer.cc
@@ -55,15 +55,11 @@
     uint64_t process_tracing_id,
     const std::string& dump_name) {}
 
-GLImage::Type GLImageAHardwareBuffer::GetType() const {
-  return Type::A_HARDWARE_BUFFER;
-}
-
-// static
-GLImageAHardwareBuffer* GLImageAHardwareBuffer::FromGLImage(GLImage* image) {
-  if (image->GetType() != Type::A_HARDWARE_BUFFER)
-    return nullptr;
-  return static_cast<GLImageAHardwareBuffer*>(image);
+std::unique_ptr<GLImage::ScopedHardwareBuffer>
+GLImageAHardwareBuffer::GetAHardwareBuffer() {
+  return std::make_unique<ScopedHardwareBuffer>(
+      base::android::ScopedHardwareBufferHandle::Create(handle_.get()),
+      base::ScopedFD());
 }
 
 }  // namespace gl
diff --git a/ui/gl/gl_image_ahardwarebuffer.h b/ui/gl/gl_image_ahardwarebuffer.h
index 9eb1583d..c2241db 100644
--- a/ui/gl/gl_image_ahardwarebuffer.h
+++ b/ui/gl/gl_image_ahardwarebuffer.h
@@ -19,9 +19,6 @@
 
   // Create an EGLImage from a given Android hardware buffer.
   bool Initialize(AHardwareBuffer* buffer, bool preserved);
-  const base::android::ScopedHardwareBufferHandle& handle() const {
-    return handle_;
-  }
 
   // Overridden from GLImage:
   unsigned GetInternalFormat() override;
@@ -41,10 +38,7 @@
   void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
                     uint64_t process_tracing_id,
                     const std::string& dump_name) override;
-  Type GetType() const override;
-
-  // Downcasts from |image|. Returns |nullptr| on failure.
-  static GLImageAHardwareBuffer* FromGLImage(GLImage* image);
+  std::unique_ptr<ScopedHardwareBuffer> GetAHardwareBuffer() override;
 
  protected:
   ~GLImageAHardwareBuffer() override;
diff --git a/ui/gl/gl_surface_egl_surface_control.cc b/ui/gl/gl_surface_egl_surface_control.cc
index 48a0f57b..4a7cbb9 100644
--- a/ui/gl/gl_surface_egl_surface_control.cc
+++ b/ui/gl/gl_surface_egl_surface_control.cc
@@ -47,8 +47,42 @@
 
 gfx::SwapResult GLSurfaceEGLSurfaceControl::SwapBuffers(
     const PresentationCallback& callback) {
+  NOTREACHED();
+  return gfx::SwapResult::SWAP_FAILED;
+}
+
+void GLSurfaceEGLSurfaceControl::SwapBuffersAsync(
+    const SwapCompletionCallback& completion_callback,
+    const PresentationCallback& presentation_callback) {
+  CommitPendingTransaction(completion_callback, presentation_callback);
+}
+
+gfx::SwapResult GLSurfaceEGLSurfaceControl::CommitOverlayPlanes(
+    const PresentationCallback& callback) {
+  NOTREACHED();
+  return gfx::SwapResult::SWAP_FAILED;
+}
+
+void GLSurfaceEGLSurfaceControl::CommitOverlayPlanesAsync(
+    const SwapCompletionCallback& completion_callback,
+    const PresentationCallback& presentation_callback) {
+  CommitPendingTransaction(completion_callback, presentation_callback);
+}
+
+void GLSurfaceEGLSurfaceControl::CommitPendingTransaction(
+    const SwapCompletionCallback& completion_callback,
+    const PresentationCallback& present_callback) {
   DCHECK(pending_transaction_);
 
+  // Release resources for the current frame once the next frame is acked.
+  ResourceRefs resources_to_release;
+  resources_to_release.swap(current_frame_resources_);
+  current_frame_resources_.clear();
+
+  // Track resources to be owned by the framework after this transaction.
+  current_frame_resources_.swap(pending_frame_resources_);
+  pending_frame_resources_.clear();
+
   pending_transaction_->Apply();
   pending_transaction_.reset();
 
@@ -65,11 +99,9 @@
       base::TimeDelta::FromMicroseconds(kRefreshIntervalInMicroseconds),
       0 /* flags */);
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(callback, feedback));
-
-  // TODO(khushalsagar): Need to hook up transaction ack from the framework to
-  // delay this ack.
-  return gfx::SwapResult::SWAP_ACK;
+      FROM_HERE,
+      base::BindOnce(OnTransactionAck, feedback, present_callback,
+                     completion_callback, std::move(resources_to_release)));
 }
 
 gfx::Size GLSurfaceEGLSurfaceControl::GetSize() {
@@ -109,21 +141,19 @@
     // TODO(khushalsagar): Forward the transform once the NDK API is in place.
   }
 
-  auto* ahb_image = GLImageAHardwareBuffer::FromGLImage(image);
-  auto hardware_buffer =
-      ahb_image ? base::android::ScopedHardwareBufferHandle::Create(
-                      ahb_image->handle().get())
-                : base::android::ScopedHardwareBufferHandle();
-  if (uninitialized ||
-      surface_state.hardware_buffer.get() != hardware_buffer.get()) {
-    surface_state.hardware_buffer = std::move(hardware_buffer);
+  AHardwareBuffer* hardware_buffer = nullptr;
+  base::ScopedFD fence_fd;
+  auto scoped_hardware_buffer = image->GetAHardwareBuffer();
+  if (scoped_hardware_buffer) {
+    hardware_buffer = scoped_hardware_buffer->buffer();
+    fence_fd = scoped_hardware_buffer->TakeFence();
+    pending_frame_resources_.push_back(std::move(scoped_hardware_buffer));
+  }
 
-    // TODO(khushalsagar): We are currently using the same fence for all
-    // overlays but that won't work for video frames where the fence needs to
-    // come from the media codec by AImageReader. The release of this buffer to
-    // the AImageReader also needs to be tied to the transaction callbacks.
-    base::ScopedFD fence_fd;
-    if (gpu_fence && surface_state.hardware_buffer.get()) {
+  if (uninitialized || surface_state.hardware_buffer != hardware_buffer) {
+    surface_state.hardware_buffer = hardware_buffer;
+
+    if (!fence_fd.is_valid() && gpu_fence && surface_state.hardware_buffer) {
       auto fence_handle =
           gfx::CloneHandleForIPC(gpu_fence->GetGpuFenceHandle());
       DCHECK(!fence_handle.is_null());
@@ -131,7 +161,7 @@
     }
 
     pending_transaction_->SetBuffer(surface_state.surface,
-                                    surface_state.hardware_buffer.get(),
+                                    surface_state.hardware_buffer,
                                     std::move(fence_fd));
   }
 
@@ -170,6 +200,10 @@
   return nullptr;
 }
 
+bool GLSurfaceEGLSurfaceControl::SupportsAsyncSwap() {
+  return true;
+}
+
 bool GLSurfaceEGLSurfaceControl::SupportsPlaneGpuFences() const {
   return true;
 }
@@ -187,6 +221,17 @@
   return true;
 }
 
+// static
+void GLSurfaceEGLSurfaceControl::OnTransactionAck(
+    const gfx::PresentationFeedback& feedback,
+    const PresentationCallback& present_callback,
+    const SwapCompletionCallback& completion_callback,
+    ResourceRefs resources) {
+  completion_callback.Run(gfx::SwapResult::SWAP_ACK, nullptr);
+  present_callback.Run(feedback);
+  resources.clear();
+}
+
 GLSurfaceEGLSurfaceControl::SurfaceState::SurfaceState(
     SurfaceComposer* composer)
     : surface(composer,
diff --git a/ui/gl/gl_surface_egl_surface_control.h b/ui/gl/gl_surface_egl_surface_control.h
index edd16b6..dcfea68b 100644
--- a/ui/gl/gl_surface_egl_surface_control.h
+++ b/ui/gl/gl_surface_egl_surface_control.h
@@ -29,6 +29,14 @@
               bool has_alpha) override;
   bool IsOffscreen() override;
   gfx::SwapResult SwapBuffers(const PresentationCallback& callback) override;
+  void SwapBuffersAsync(
+      const SwapCompletionCallback& completion_callback,
+      const PresentationCallback& presentation_callback) override;
+  gfx::SwapResult CommitOverlayPlanes(
+      const PresentationCallback& callback) override;
+  void CommitOverlayPlanesAsync(
+      const SwapCompletionCallback& completion_callback,
+      const PresentationCallback& presentation_callback) override;
   gfx::Size GetSize() override;
   bool OnMakeCurrent(gl::GLContext* context) override;
   bool ScheduleOverlayPlane(int z_order,
@@ -41,6 +49,7 @@
   bool IsSurfaceless() const override;
   void* GetHandle() override;
 
+  bool SupportsAsyncSwap() override;
   bool SupportsPlaneGpuFences() const override;
   bool SupportsPresentationCallback() override;
   bool SupportsSwapBuffersWithBounds() override;
@@ -59,7 +68,7 @@
 
     int z_order = 0;
     gfx::OverlayTransform transform = gfx::OVERLAY_TRANSFORM_INVALID;
-    base::android::ScopedHardwareBufferHandle hardware_buffer;
+    AHardwareBuffer* hardware_buffer = nullptr;
     gfx::Rect bounds_rect;
     gfx::Rect crop_rect;
     bool opaque = true;
@@ -67,6 +76,19 @@
     gl::SurfaceComposer::Surface surface;
   };
 
+  using ResourceRefs =
+      std::vector<std::unique_ptr<GLImage::ScopedHardwareBuffer>>;
+
+  void CommitPendingTransaction(
+      const SwapCompletionCallback& completion_callback,
+      const PresentationCallback& callback);
+
+  static void OnTransactionAck(
+      const gfx::PresentationFeedback& feedback,
+      const PresentationCallback& present_callback,
+      const SwapCompletionCallback& completion_callback,
+      ResourceRefs resources);
+
   // Holds the surface state changes made since the last call to SwapBuffers.
   base::Optional<gl::SurfaceComposer::Transaction> pending_transaction_;
 
@@ -80,6 +102,17 @@
   std::vector<SurfaceState> surface_list_;
   size_t pending_surfaces_count_ = 0u;
 
+  // Resources in the pending frame, for which updates are being
+  // collected in |pending_transaction_|. These are resources for which the
+  // pending transaction has a ref but they have not been applied and
+  // transferred to the framework.
+  ResourceRefs pending_frame_resources_;
+
+  // Resources in the current frame sent to the framework. The
+  // framework is assumed to retain ownership of these resources until the next
+  // frame update.
+  ResourceRefs current_frame_resources_;
+
   std::unique_ptr<gl::SurfaceComposer> surface_composer_;
 };
 
diff --git a/ui/shell_dialogs/base_shell_dialog_win.cc b/ui/shell_dialogs/base_shell_dialog_win.cc
index ab670621..a61a9e7 100644
--- a/ui/shell_dialogs/base_shell_dialog_win.cc
+++ b/ui/shell_dialogs/base_shell_dialog_win.cc
@@ -6,11 +6,32 @@
 
 #include <algorithm>
 
-#include "base/threading/thread.h"
+#include "base/task/post_task.h"
 #include "base/win/scoped_com_initializer.h"
 
 namespace ui {
 
+namespace {
+
+// Creates a SingleThreadTaskRunner to run a shell dialog on. Each dialog
+// requires its own dedicated single-threaded sequence otherwise in some
+// situations where a singleton owns a single instance of this object we can
+// have a situation where a modal dialog in one window blocks the appearance
+// of a modal dialog in another.
+scoped_refptr<base::SingleThreadTaskRunner> CreateDialogTaskRunner() {
+  return CreateCOMSTATaskRunnerWithTraits(
+      {base::TaskPriority::USER_BLOCKING,
+       base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN, base::MayBlock()},
+      base::SingleThreadTaskRunnerThreadMode::DEDICATED);
+}
+
+}  // namespace
+
+BaseShellDialogImpl::RunState::RunState() = default;
+BaseShellDialogImpl::RunState::~RunState() = default;
+
+BaseShellDialogImpl::RunState::RunState(const RunState& run_state) = default;
+
 // static
 BaseShellDialogImpl::Owners BaseShellDialogImpl::owners_;
 int BaseShellDialogImpl::instance_count_ = 0;
@@ -32,7 +53,7 @@
   // entries in our map for the same top level window.
   DCHECK(!owner || owner == GetAncestor(owner, GA_ROOT));
   RunState run_state;
-  run_state.dialog_thread = CreateDialogThread();
+  run_state.dialog_task_runner = CreateDialogTaskRunner();
   run_state.owner = owner;
   if (owner) {
     owners_.insert(owner);
@@ -48,8 +69,6 @@
     DCHECK(owners_.find(run_state.owner) != owners_.end());
     owners_.erase(run_state.owner);
   }
-  DCHECK(run_state.dialog_thread);
-  delete run_state.dialog_thread;
 }
 
 bool BaseShellDialogImpl::IsRunningDialogForOwner(HWND owner) const {
@@ -61,16 +80,6 @@
     EnableWindow(owner, FALSE);
 }
 
-// static
-base::Thread* BaseShellDialogImpl::CreateDialogThread() {
-  base::Thread* thread = new base::Thread("Chrome_ShellDialogThread");
-  // Many shell dialogs require a COM Single-Threaded Apartment (STA) to run.
-  thread->init_com_with_mta(false);
-  bool started = thread->Start();
-  DCHECK(started);
-  return thread;
-}
-
 void BaseShellDialogImpl::EnableOwner(HWND owner) {
   if (IsWindow(owner))
     EnableWindow(owner, TRUE);
diff --git a/ui/shell_dialogs/base_shell_dialog_win.h b/ui/shell_dialogs/base_shell_dialog_win.h
index ca5ce0bd..37959ba6 100644
--- a/ui/shell_dialogs/base_shell_dialog_win.h
+++ b/ui/shell_dialogs/base_shell_dialog_win.h
@@ -9,11 +9,12 @@
 #include <set>
 
 #include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
 #include "ui/shell_dialogs/base_shell_dialog.h"
 #include "ui/shell_dialogs/shell_dialogs_export.h"
 
 namespace base {
-class Thread;
+class SingleThreadTaskRunner;
 }
 
 namespace ui {
@@ -28,17 +29,22 @@
 
  protected:
   // Represents a run of a dialog.
-  struct RunState {
+  struct SHELL_DIALOGS_EXPORT RunState {
+    RunState();
+    ~RunState();
+
+    RunState(const RunState& run_state);
+
     // Owning HWND, may be null.
     HWND owner;
 
-    // Thread dialog is run on.
-    base::Thread* dialog_thread;
+    // Dedicated sequence on which the dialog runs.
+    scoped_refptr<base::SingleThreadTaskRunner> dialog_task_runner;
   };
 
   // Called at the beginning of a modal dialog run. Disables the owner window
-  // and tracks it. Returns the message loop of the thread that the dialog will
-  // be run on.
+  // and tracks it. Returns the dedicated single-threaded sequence that the
+  // dialog will be run on.
   RunState BeginRun(HWND owner);
 
   // Cleans up after a dialog run. If the run_state has a valid HWND this makes
@@ -54,24 +60,17 @@
   bool IsRunningDialogForOwner(HWND owner) const;
 
   // Disables the window |owner|. Can be run from either the ui or the dialog
-  // thread. Can be called on either the UI or the dialog thread. This function
-  // is called on the dialog thread after the modal Windows Common dialog
-  // functions return because Windows automatically re-enables the owning
-  // window when those functions return, but we don't actually want them to be
-  // re-enabled until the response of the dialog propagates back to the UI
-  // thread, so we disable the owner manually after the Common dialog function
-  // returns.
+  // thread. This function is called on the dialog thread after the modal
+  // Windows Common dialog functions return because Windows automatically
+  // re-enables the owning window when those functions return, but we don't
+  // actually want them to be re-enabled until the response of the dialog
+  // propagates back to the UI thread, so we disable the owner manually after
+  // the Common dialog function returns.
   void DisableOwner(HWND owner);
 
  private:
   typedef std::set<HWND> Owners;
 
-  // Creates a thread to run a shell dialog on. Each dialog requires its own
-  // thread otherwise in some situations where a singleton owns a single
-  // instance of this object we can have a situation where a modal dialog in
-  // one window blocks the appearance of a modal dialog in another.
-  static base::Thread* CreateDialogThread();
-
   // Enables the window |owner_|. Can only be run from the ui thread.
   void EnableOwner(HWND owner);
 
diff --git a/ui/shell_dialogs/select_file_dialog_win.cc b/ui/shell_dialogs/select_file_dialog_win.cc
index c2208ef..5f30fef 100644
--- a/ui/shell_dialogs/select_file_dialog_win.cc
+++ b/ui/shell_dialogs/select_file_dialog_win.cc
@@ -23,7 +23,6 @@
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
 #include "base/single_thread_task_runner.h"
-#include "base/threading/thread.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/win/registry.h"
 #include "base/win/shortcut.h"
@@ -274,7 +273,7 @@
   // Runs a Folder selection dialog box, passes back the selected folder in
   // |path| and returns true if the user clicks OK. If the user cancels the
   // dialog box the value in |path| is not modified and returns false. Run
-  // on the dialog thread.
+  // on the dedicated dialog sequence.
   bool RunSelectFolderDialog(const ExecuteSelectParams& params,
                              base::FilePath* path);
 
@@ -344,7 +343,7 @@
                                      default_path, file_types, file_type_index,
                                      default_extension, BeginRun(owner),
                                      owner, params);
-  execute_params.run_state.dialog_thread->task_runner()->PostTask(
+  execute_params.run_state.dialog_task_runner->PostTask(
       FROM_HERE, base::BindOnce(&SelectFileDialogImpl::ExecuteSelectFile, this,
                                 execute_params));
 }
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn
index b7fa6d3..4a7b1741 100644
--- a/ui/views/BUILD.gn
+++ b/ui/views/BUILD.gn
@@ -289,6 +289,7 @@
     "bubble/bubble_border.cc",
     "bubble/bubble_dialog_delegate_view.cc",
     "bubble/bubble_frame_view.cc",
+    "bubble/footnote_container_view.cc",
     "bubble/info_bubble.cc",
     "bubble/tooltip_icon.cc",
     "button_drag_utils.cc",
@@ -972,6 +973,7 @@
     "controls/image_view_unittest.cc",
     "controls/label_unittest.cc",
     "controls/menu/menu_controller_unittest.cc",
+    "controls/menu/menu_footnote_unittest.cc",
     "controls/menu/menu_item_view_unittest.cc",
     "controls/menu/menu_model_adapter_unittest.cc",
     "controls/menu/menu_runner_cocoa_unittest.mm",
diff --git a/ui/views/bubble/bubble_frame_view.cc b/ui/views/bubble/bubble_frame_view.cc
index 02aa4a0..65bcbbaa 100644
--- a/ui/views/bubble/bubble_frame_view.cc
+++ b/ui/views/bubble/bubble_frame_view.cc
@@ -25,6 +25,7 @@
 #include "ui/strings/grit/ui_strings.h"
 #include "ui/views/bubble/bubble_border.h"
 #include "ui/views/bubble/bubble_dialog_delegate_view.h"
+#include "ui/views/bubble/footnote_container_view.h"
 #include "ui/views/controls/button/image_button.h"
 #include "ui/views/controls/button/image_button_factory.h"
 #include "ui/views/controls/image_view.h"
@@ -68,21 +69,6 @@
 
 }  // namespace
 
-// A container that changes visibility with its contents.
-class FootnoteContainerView : public View {
- public:
-  FootnoteContainerView() {}
-
-  // View:
-  void ChildVisibilityChanged(View* child) override {
-    DCHECK_EQ(child_count(), 1);
-    SetVisible(child->visible());
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(FootnoteContainerView);
-};
-
 // static
 const char BubbleFrameView::kViewClassName[] = "BubbleFrameView";
 
@@ -449,6 +435,10 @@
 
 void BubbleFrameView::SetBubbleBorder(std::unique_ptr<BubbleBorder> border) {
   bubble_border_ = border.get();
+
+  if (footnote_container_)
+    footnote_container_->SetCornerRadius(border->GetBorderCornerRadius());
+
   SetBorder(std::move(border));
 
   // Update the background, which relies on the border.
@@ -460,15 +450,9 @@
     return;
 
   DCHECK(!footnote_container_);
-  footnote_container_ = new FootnoteContainerView();
-  footnote_container_->SetLayoutManager(
-      std::make_unique<BoxLayout>(BoxLayout::kVertical, footnote_margins_, 0));
-  footnote_container_->SetBackground(
-      CreateSolidBackground(gfx::kGoogleGrey050));
-  footnote_container_->SetBorder(
-      CreateSolidSidedBorder(1, 0, 0, 0, gfx::kGoogleGrey200));
-  footnote_container_->AddChildView(view);
-  footnote_container_->SetVisible(view->visible());
+  int radius = bubble_border_ ? bubble_border_->GetBorderCornerRadius() : 0;
+  footnote_container_ =
+      new FootnoteContainerView(footnote_margins_, view, radius);
   AddChildView(footnote_container_);
 }
 
diff --git a/ui/views/bubble/bubble_frame_view.h b/ui/views/bubble/bubble_frame_view.h
index bfb407a..40175e1 100644
--- a/ui/views/bubble/bubble_frame_view.h
+++ b/ui/views/bubble/bubble_frame_view.h
@@ -18,6 +18,7 @@
 namespace views {
 
 class BubbleBorder;
+class FootnoteContainerView;
 class ImageView;
 
 // The non-client frame view of bubble-styled widgets.
@@ -183,7 +184,7 @@
   Button* close_;
 
   // A view to contain the footnote view, if it exists.
-  View* footnote_container_;
+  FootnoteContainerView* footnote_container_;
 
   // Whether the close button was clicked.
   bool close_button_clicked_;
diff --git a/ui/views/bubble/bubble_frame_view_unittest.cc b/ui/views/bubble/bubble_frame_view_unittest.cc
index 38930c3..bd244a5b 100644
--- a/ui/views/bubble/bubble_frame_view_unittest.cc
+++ b/ui/views/bubble/bubble_frame_view_unittest.cc
@@ -19,6 +19,7 @@
 #include "ui/gfx/text_utils.h"
 #include "ui/views/bubble/bubble_border.h"
 #include "ui/views/bubble/bubble_dialog_delegate_view.h"
+#include "ui/views/bubble/footnote_container_view.h"
 #include "ui/views/controls/button/label_button.h"
 #include "ui/views/metrics.h"
 #include "ui/views/test/test_layout_provider.h"
diff --git a/ui/views/bubble/footnote_container_view.cc b/ui/views/bubble/footnote_container_view.cc
new file mode 100644
index 0000000..4e0d62e
--- /dev/null
+++ b/ui/views/bubble/footnote_container_view.cc
@@ -0,0 +1,73 @@
+// Copyright 2018 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 "ui/views/bubble/footnote_container_view.h"
+
+#include "cc/paint/paint_flags.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/color_palette.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/views/background.h"
+#include "ui/views/border.h"
+#include "ui/views/layout/box_layout.h"
+
+namespace views {
+
+namespace {
+
+// A solid color background where the bottom two corners are rounded.
+class HalfRoundedRectBackground : public Background {
+ public:
+  explicit HalfRoundedRectBackground(SkColor color, float radius)
+      : radius_(radius) {
+    SetNativeControlColor(color);
+  }
+  ~HalfRoundedRectBackground() override = default;
+
+  // Background:
+  void Paint(gfx::Canvas* canvas, View* view) const override {
+    cc::PaintFlags flags;
+    flags.setAntiAlias(true);
+    flags.setStyle(cc::PaintFlags::kFill_Style);
+    flags.setColor(get_color());
+    // Draw a rounded rect that spills outside of the clipping area, so that the
+    // rounded corners only show in the bottom 2 corners.
+    gfx::RectF spilling_rect(view->GetLocalBounds());
+    spilling_rect.set_y(spilling_rect.x() - radius_);
+    spilling_rect.set_height(spilling_rect.height() + radius_);
+    canvas->DrawRoundRect(spilling_rect, radius_, flags);
+  }
+
+ private:
+  float radius_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(HalfRoundedRectBackground);
+};
+
+}  // namespace
+
+FootnoteContainerView::FootnoteContainerView(const gfx::Insets& margins,
+                                             View* child_view,
+                                             float corner_radius) {
+  SetLayoutManager(
+      std::make_unique<BoxLayout>(BoxLayout::kVertical, margins, 0));
+  SetCornerRadius(corner_radius);
+  SetBorder(CreateSolidSidedBorder(1, 0, 0, 0, gfx::kGoogleGrey200));
+  AddChildView(child_view);
+  SetVisible(child_view->visible());
+}
+
+FootnoteContainerView::~FootnoteContainerView() = default;
+
+void FootnoteContainerView::SetCornerRadius(float corner_radius) {
+  SetBackground(std::make_unique<HalfRoundedRectBackground>(gfx::kGoogleGrey050,
+                                                            corner_radius));
+}
+
+void FootnoteContainerView::ChildVisibilityChanged(View* child) {
+  DCHECK_EQ(child_count(), 1);
+  SetVisible(child->visible());
+}
+
+}  // namespace views
diff --git a/ui/views/bubble/footnote_container_view.h b/ui/views/bubble/footnote_container_view.h
new file mode 100644
index 0000000..2b4bea9
--- /dev/null
+++ b/ui/views/bubble/footnote_container_view.h
@@ -0,0 +1,32 @@
+// Copyright 2018 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 UI_VIEWS_BUBBLE_FOOTNOTE_CONTAINER_VIEW_H_
+#define UI_VIEWS_BUBBLE_FOOTNOTE_CONTAINER_VIEW_H_
+
+#include "ui/views/view.h"
+
+namespace views {
+
+// A container that changes visibility with its contents, and draws a solid
+// background with rounded corners at the bottom.
+class FootnoteContainerView : public View {
+ public:
+  FootnoteContainerView(const gfx::Insets& margins,
+                        View* child_view,
+                        float corner_radius);
+  ~FootnoteContainerView() override;
+
+  void SetCornerRadius(float corner_radius);
+
+  // View:
+  void ChildVisibilityChanged(View* child) override;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(FootnoteContainerView);
+};
+
+}  // namespace views
+
+#endif  // UI_VIEWS_BUBBLE_FOOTNOTE_CONTAINER_VIEW_H_
diff --git a/ui/views/controls/button/checkbox.cc b/ui/views/controls/button/checkbox.cc
index 91e398e..1a84d97 100644
--- a/ui/views/controls/button/checkbox.cc
+++ b/ui/views/controls/button/checkbox.cc
@@ -55,7 +55,10 @@
 }
 
 void Checkbox::SetChecked(bool checked) {
-  checked_ = checked;
+  if (checked_ != checked) {
+    checked_ = checked;
+    NotifyAccessibilityEvent(ax::mojom::Event::kCheckedStateChanged, true);
+  }
   UpdateImage();
 }
 
diff --git a/ui/views/controls/menu/menu_delegate.cc b/ui/views/controls/menu/menu_delegate.cc
index 56c3c51c..308ffe3 100644
--- a/ui/views/controls/menu/menu_delegate.cc
+++ b/ui/views/controls/menu/menu_delegate.cc
@@ -152,4 +152,8 @@
   return true;
 }
 
+View* MenuDelegate::CreateFootnoteView() {
+  return nullptr;
+}
+
 }  // namespace views
diff --git a/ui/views/controls/menu/menu_delegate.h b/ui/views/controls/menu/menu_delegate.h
index 70660518..7544162 100644
--- a/ui/views/controls/menu/menu_delegate.h
+++ b/ui/views/controls/menu/menu_delegate.h
@@ -35,6 +35,7 @@
 
 class MenuButton;
 class MenuItemView;
+class View;
 
 // MenuDelegate --------------------------------------------------------------
 
@@ -233,6 +234,11 @@
   // Returns true if the labels should reserve additional spacing for e.g.
   // submenu indicators at the end of the line.
   virtual bool ShouldReserveSpaceForSubmenuIndicator() const;
+
+  // Override this function to display a footnote view below the menu-items in a
+  // top-level menu. Overrides may construct the view; this will only be called
+  // once per menu.
+  virtual View* CreateFootnoteView();
 };
 
 }  // namespace views
diff --git a/ui/views/controls/menu/menu_footnote_unittest.cc b/ui/views/controls/menu/menu_footnote_unittest.cc
new file mode 100644
index 0000000..02374fd
--- /dev/null
+++ b/ui/views/controls/menu/menu_footnote_unittest.cc
@@ -0,0 +1,121 @@
+// Copyright 2018 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 "ui/views/controls/menu/submenu_view.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/views/controls/menu/menu_controller.h"
+#include "ui/views/controls/menu/menu_delegate.h"
+#include "ui/views/controls/menu/menu_item_view.h"
+#include "ui/views/test/menu_test_utils.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+namespace test {
+
+namespace {
+
+class MockMenuDelegate : public MenuDelegate {
+ public:
+  MockMenuDelegate() = default;
+  ~MockMenuDelegate() override = default;
+
+  void set_create_footnote_view_value(View* view) {
+    create_footnote_view_value_ = view;
+  }
+  int create_footnote_view_count() { return create_footnote_view_count_; }
+
+  View* CreateFootnoteView() override {
+    create_footnote_view_count_++;
+    return create_footnote_view_value_;
+  }
+
+ private:
+  // The return value for the next CreateFootnoteView call.
+  View* create_footnote_view_value_ = nullptr;
+
+  // The number of times CreateFootnoteView was called.
+  int create_footnote_view_count_ = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(MockMenuDelegate);
+};
+
+}  // namespace
+
+class MenuFootnoteTest : public ViewsTestBase {
+ public:
+  MenuFootnoteTest();
+  ~MenuFootnoteTest() override;
+
+  void SetUp() override {
+    ViewsTestBase::SetUp();
+
+    menu_delegate_ = std::make_unique<MockMenuDelegate>();
+    menu_item_view_ = new MenuItemView(menu_delegate_.get());
+    item_with_submenu_ = menu_item_view_->AppendSubMenu(0, base::string16());
+
+    owner_ = std::make_unique<Widget>();
+    Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+    params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+    owner_->Init(params);
+    owner_->Show();
+
+    menu_runner_ = std::make_unique<MenuRunner>(menu_item_view_, 0);
+  }
+
+  MenuItemView* menu_item_view() { return menu_item_view_; }
+  MenuItemView* item_with_submenu() { return item_with_submenu_; }
+  MockMenuDelegate* menu_delegate() { return menu_delegate_.get(); }
+  MenuRunner* menu_runner() { return menu_runner_.get(); }
+  Widget* owner() { return owner_.get(); }
+
+  // ViewsTestBase:
+  void TearDown() override {
+    if (owner_)
+      owner_->CloseNow();
+    ViewsTestBase::TearDown();
+  }
+
+ private:
+  // Owned by menu_runner_.
+  MenuItemView* menu_item_view_ = nullptr;
+
+  // An item with a submenu, in menu_item_view_.
+  MenuItemView* item_with_submenu_ = nullptr;
+
+  std::unique_ptr<MockMenuDelegate> menu_delegate_;
+  std::unique_ptr<MenuRunner> menu_runner_;
+  std::unique_ptr<Widget> owner_;
+
+  DISALLOW_COPY_AND_ASSIGN(MenuFootnoteTest);
+};
+
+MenuFootnoteTest::MenuFootnoteTest() = default;
+
+MenuFootnoteTest::~MenuFootnoteTest() = default;
+
+TEST_F(MenuFootnoteTest, TopLevelContainerShowsFootnote) {
+  View* footnote = new View();
+  menu_delegate()->set_create_footnote_view_value(footnote);
+  menu_runner()->RunMenuAt(owner(), nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT,
+                           ui::MENU_SOURCE_NONE);
+  EXPECT_EQ(1, menu_delegate()->create_footnote_view_count());
+  EXPECT_TRUE(menu_item_view()->GetSubmenu()->Contains(footnote));
+}
+
+TEST_F(MenuFootnoteTest, SubmenuDoesNotShowFootnote) {
+  View* footnote = new View();
+  menu_delegate()->set_create_footnote_view_value(footnote);
+  menu_runner()->RunMenuAt(owner(), nullptr, gfx::Rect(), MENU_ANCHOR_TOPLEFT,
+                           ui::MENU_SOURCE_NONE);
+  // Trigger the code that would create a footnote, then check that the footnote
+  // was not created.
+  item_with_submenu()->GetSubmenu()->GetScrollViewContainer();
+  EXPECT_FALSE(item_with_submenu()->GetSubmenu()->Contains(footnote));
+  EXPECT_EQ(1, menu_delegate()->create_footnote_view_count());
+}
+
+}  // namespace test
+}  // namespace views
diff --git a/ui/views/controls/menu/menu_scroll_view_container.cc b/ui/views/controls/menu/menu_scroll_view_container.cc
index ecbd5d7..ab37a2c 100644
--- a/ui/views/controls/menu/menu_scroll_view_container.cc
+++ b/ui/views/controls/menu/menu_scroll_view_container.cc
@@ -12,6 +12,7 @@
 #include "ui/gfx/color_palette.h"
 #include "ui/views/border.h"
 #include "ui/views/bubble/bubble_border.h"
+#include "ui/views/bubble/footnote_container_view.h"
 #include "ui/views/controls/menu/menu_config.h"
 #include "ui/views/controls/menu/menu_controller.h"
 #include "ui/views/controls/menu/menu_item_view.h"
@@ -172,9 +173,7 @@
 // MenuScrollViewContainer ----------------------------------------------------
 
 MenuScrollViewContainer::MenuScrollViewContainer(SubmenuView* content_view)
-    : content_view_(content_view),
-      arrow_(BubbleBorder::NONE),
-      bubble_border_(NULL) {
+    : content_view_(content_view) {
   scroll_up_button_ = new MenuScrollButton(content_view, true);
   scroll_down_button_ = new MenuScrollButton(content_view, false);
   AddChildView(scroll_up_button_);
@@ -186,10 +185,7 @@
   arrow_ = BubbleBorderTypeFromAnchor(
       content_view_->GetMenuItem()->GetMenuController()->GetAnchorPosition());
 
-  if (arrow_ != BubbleBorder::NONE)
-    CreateBubbleBorder();
-  else
-    CreateDefaultBorder();
+  CreateBorder();
 }
 
 bool MenuScrollViewContainer::HasBubbleBorder() {
@@ -201,6 +197,21 @@
   bubble_border_->set_arrow_offset(offset);
 }
 
+void MenuScrollViewContainer::SetFootnoteView(View* view) {
+  DCHECK(view);
+  DCHECK(!footnote_container_);
+  footnote_container_ = new FootnoteContainerView(gfx::Insets(), view, 0);
+  content_view_->AddChildView(footnote_container_);
+  // Recreate the border. This updates the corner-radius for
+  // |footnote_container_| and margins, so |footnote_container_| can draw the
+  // bottom of the menu.
+  CreateBorder();
+}
+
+bool MenuScrollViewContainer::HasVisibleFootnote() {
+  return footnote_container_ && footnote_container_->visible();
+}
+
 gfx::Size MenuScrollViewContainer::CalculatePreferredSize() const {
   gfx::Size prefsize = scroll_view_->GetContents()->GetPreferredSize();
   gfx::Insets insets = GetInsets();
@@ -217,6 +228,10 @@
   if (!scroll_up_button_->visible()) {
     scroll_view_->SetBounds(x, y, width, content_height);
     scroll_view_->Layout();
+    if (footnote_container_ && bubble_border_) {
+      int radius = bubble_border_->GetBorderCornerRadius();
+      footnote_container_->SetCornerRadius(radius);
+    }
     return;
   }
 
@@ -231,13 +246,17 @@
                                  width, pref.height());
   content_height -= pref.height();
 
+  // Don't round the footnote when the scroll button is visible.
+  if (footnote_container_)
+    footnote_container_->SetCornerRadius(0);
+
   scroll_view_->SetBounds(x, scroll_view_y, width, content_height);
   scroll_view_->Layout();
 }
 
 void MenuScrollViewContainer::OnNativeThemeChanged(
     const ui::NativeTheme* theme) {
-  if (arrow_ == BubbleBorder::NONE)
+  if (!HasBubbleBorder())
     CreateDefaultBorder();
 }
 
@@ -270,6 +289,13 @@
   Layout();
 }
 
+void MenuScrollViewContainer::CreateBorder() {
+  if (HasBubbleBorder())
+    CreateBubbleBorder();
+  else
+    CreateDefaultBorder();
+}
+
 void MenuScrollViewContainer::CreateDefaultBorder() {
   DCHECK_EQ(arrow_, BubbleBorder::NONE);
   bubble_border_ = nullptr;
@@ -292,6 +318,8 @@
   const int horizontal_inset =
       menu_config.menu_horizontal_border_size + padding;
 
+  int bottom_inset = HasVisibleFootnote() ? 0 : horizontal_inset;
+
   if (use_outer_border) {
     SkColor color = GetNativeTheme()
                         ? GetNativeTheme()->GetSystemColor(
@@ -299,10 +327,11 @@
                         : gfx::kPlaceholderColor;
     SetBorder(views::CreateBorderPainter(
         std::make_unique<views::RoundRectPainter>(color, corner_radius),
-        gfx::Insets(vertical_inset, horizontal_inset)));
+        gfx::Insets(vertical_inset, horizontal_inset, bottom_inset,
+                    horizontal_inset)));
   } else {
-    SetBorder(CreateEmptyBorder(vertical_inset, horizontal_inset,
-                                vertical_inset, horizontal_inset));
+    SetBorder(CreateEmptyBorder(vertical_inset, horizontal_inset, bottom_inset,
+                                horizontal_inset));
   }
 }
 
@@ -316,8 +345,10 @@
     bubble_border_->SetCornerRadius(menu_config.touchable_corner_radius);
     bubble_border_->set_md_shadow_elevation(
         menu_config.touchable_menu_shadow_elevation);
-    scroll_view_->GetContents()->SetBorder(CreateEmptyBorder(
-        gfx::Insets(menu_config.vertical_touchable_menu_item_padding, 0)));
+    gfx::Insets insets(menu_config.vertical_touchable_menu_item_padding, 0);
+    if (HasVisibleFootnote())
+      insets.Set(menu_config.vertical_touchable_menu_item_padding, 0, 0, 0);
+    scroll_view_->GetContents()->SetBorder(CreateEmptyBorder(insets));
   }
 
   SetBorder(std::unique_ptr<Border>(bubble_border_));
diff --git a/ui/views/controls/menu/menu_scroll_view_container.h b/ui/views/controls/menu/menu_scroll_view_container.h
index f083419..ea02becc 100644
--- a/ui/views/controls/menu/menu_scroll_view_container.h
+++ b/ui/views/controls/menu/menu_scroll_view_container.h
@@ -12,6 +12,7 @@
 
 namespace views {
 
+class FootnoteContainerView;
 class SubmenuView;
 
 // MenuScrollViewContainer contains the SubmenuView (through a MenuScrollView)
@@ -31,6 +32,8 @@
   // Offsets the Arrow from the default location.
   void SetBubbleArrowOffset(int offset);
 
+  void SetFootnoteView(View* view);
+
   // View overrides.
   gfx::Size CalculatePreferredSize() const override;
   void Layout() override;
@@ -43,6 +46,9 @@
   void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
 
  private:
+  // Create a default border or bubble border, as appropriate.
+  void CreateBorder();
+
   // Create the default border.
   void CreateDefaultBorder();
 
@@ -51,6 +57,8 @@
 
   BubbleBorder::Arrow BubbleBorderTypeFromAnchor(MenuAnchorPosition anchor);
 
+  bool HasVisibleFootnote();
+
   class MenuScrollView;
 
   // The scroll buttons.
@@ -64,10 +72,13 @@
   SubmenuView* content_view_;
 
   // If set the currently set border is a bubble border.
-  BubbleBorder::Arrow arrow_;
+  BubbleBorder::Arrow arrow_ = BubbleBorder::NONE;
 
   // Weak reference to the currently set border.
-  BubbleBorder* bubble_border_;
+  BubbleBorder* bubble_border_ = nullptr;
+
+  // A view to contain the footnote view, if it exists.
+  FootnoteContainerView* footnote_container_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(MenuScrollViewContainer);
 };
diff --git a/ui/views/controls/menu/submenu_view.cc b/ui/views/controls/menu/submenu_view.cc
index 36865a5..f88f565 100644
--- a/ui/views/controls/menu/submenu_view.cc
+++ b/ui/views/controls/menu/submenu_view.cc
@@ -469,6 +469,13 @@
 MenuScrollViewContainer* SubmenuView::GetScrollViewContainer() {
   if (!scroll_view_container_) {
     scroll_view_container_ = new MenuScrollViewContainer(this);
+    if (GetMenuItem()->GetParentMenuItem() == nullptr) {
+      // Top-level menu, this may have a footnote. Submenus can't have a
+      // footnote, because they share the |MenuDelegate| with their parent.
+      View* footnote_view = GetMenuItem()->GetDelegate()->CreateFootnoteView();
+      if (footnote_view)
+        scroll_view_container_->SetFootnoteView(footnote_view);
+    }
     // Otherwise MenuHost would delete us.
     scroll_view_container_->set_owned_by_client();
   }