diff --git a/.gitignore b/.gitignore
index 29ca847..2bdbac3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -256,6 +256,7 @@
 /sql/sql_unittests_run.xml
 /sync/sync.xml
 /sync_testserver.log
+/testing/libfuzzer/fuzzer_corpus_for_bots/
 /testserver.log
 # See third_party/.gitignore for entries covering src/third_party.
 /tools/.bisect-builds-cache.json
diff --git a/DEPS b/DEPS
index 8a71399..74cc005 100644
--- a/DEPS
+++ b/DEPS
@@ -121,11 +121,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': '8cb7376b2d9a470a601966889ba26fa6f82bbdf9',
+  'skia_revision': '980b231f5772d01e06cfd4374d942c108a3fe0a6',
   # 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': 'd2c054eeda2bb03b814a128b50a816f0cc6166da',
+  'v8_revision': 'e57bbd5488edfbabae36a55e3a1db459f9c3b8e2',
   # 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.
@@ -133,7 +133,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': '98a3550bce48a056cd1529d28430384ee30ae0fc',
+  'angle_revision': '73397e8e86bff666fc8191b6b30a96d35908acae',
   # 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.
@@ -145,7 +145,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '05ec64c7fbd0c2fb9077f0fee160c4f6a99fe2f1',
+  'pdfium_revision': '399958ef38caf620316a70a7ab517d2601264d52',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -679,7 +679,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '84fe948c97a95c980ac0d6c01d41e6a82d88922f',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '0fdbd33799f739ce79661dd9c2197048bb24cec9',
       'condition': 'checkout_linux',
   },
 
@@ -739,7 +739,7 @@
   },
 
   'src/third_party/ffmpeg':
-    Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '5340b1eb263ae3c59d438830ba4080cc10492201',
+    Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '67e9e0337185f05a0d8d362473e63d8a9dfdebed',
 
   'src/third_party/flac':
     Var('chromium_git') + '/chromium/deps/flac.git' + '@' + 'af862024c8c8fa0ae07ced05e89013d881b00596',
@@ -1036,7 +1036,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  'adc060d0462d5f43301a16e4d46012f121873853',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '0e14e4babc1f91e995c3d95f3b0b3f75b97b5cad',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
@@ -1147,7 +1147,7 @@
     Var('chromium_git') + '/external/smhasher.git' + '@' + 'e87738e57558e0ec472b2fc3a643b838e5b6e88f',
 
   'src/third_party/snappy/src':
-    Var('chromium_git') + '/external/github.com/google/snappy.git' + '@' + 'ea660b57d65d68d521287c903459b6dd3b2804d0',
+    Var('chromium_git') + '/external/github.com/google/snappy.git' + '@' + '3f194acb57e0487531c96b97af61dcbd025a78a3',
 
   'src/third_party/sqlite4java': {
       'packages': [
@@ -1199,7 +1199,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'f22b9ad8d75bf99652dfc3b1db40e73d9fdd3840',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'c610e26be55e312d2e1ecd6ba3fb649d17afa181',
+    Var('webrtc_git') + '/src.git' + '@' + '00a6ab568bf021a2861ef15e4a679812c58250cb',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1230,7 +1230,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@22686954302cd389ef96d67e30f56e241e7d834d',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@4c468fd8eaeda11fa8401da936a416f555bf2696',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/browser/net_network_service/android_stream_reader_url_loader_unittest.cc b/android_webview/browser/net_network_service/android_stream_reader_url_loader_unittest.cc
index f2a2b2f5d..bb7826e 100644
--- a/android_webview/browser/net_network_service/android_stream_reader_url_loader_unittest.cc
+++ b/android_webview/browser/net_network_service/android_stream_reader_url_loader_unittest.cc
@@ -95,7 +95,8 @@
   DISALLOW_COPY_AND_ASSIGN(AndroidStreamReaderURLLoaderTest);
 };
 
-TEST_F(AndroidStreamReaderURLLoaderTest, ReadFakeStream) {
+// crbug.com/919929
+TEST_F(AndroidStreamReaderURLLoaderTest, DISABLED_ReadFakeStream) {
   network::ResourceRequest request =
       CreateRequest(GURL("https://www.example.com/"));
   std::unique_ptr<network::TestURLLoaderClient> client =
@@ -121,7 +122,8 @@
   EXPECT_EQ(net::ERR_FAILED, client->completion_status().error_code);
 }
 
-TEST_F(AndroidStreamReaderURLLoaderTest, ValidRangeRequest) {
+// crbug.com/919929
+TEST_F(AndroidStreamReaderURLLoaderTest, DISABLED_ValidRangeRequest) {
   network::ResourceRequest request =
       CreateRequest(GURL("https://www.example.com/"));
   request.headers.SetHeader(net::HttpRequestHeaders::kRange, "bytes=10-200");
diff --git a/android_webview/browser/surfaces_instance.cc b/android_webview/browser/surfaces_instance.cc
index 041c0583..8917d97 100644
--- a/android_webview/browser/surfaces_instance.cc
+++ b/android_webview/browser/surfaces_instance.cc
@@ -144,7 +144,8 @@
   surface_quad->SetNew(quad_state, gfx::Rect(quad_state->quad_layer_rect),
                        gfx::Rect(quad_state->quad_layer_rect),
                        viz::SurfaceRange(base::nullopt, child_id),
-                       SK_ColorWHITE, false);
+                       SK_ColorWHITE, /*stretch_content_to_fill_bounds=*/false,
+                       /*ignores_input_event=*/false);
 
   viz::CompositorFrame frame;
   // We draw synchronously, so acknowledge a manual BeginFrame.
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index c341d521..e64feb84 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -1363,6 +1363,9 @@
     "//cc/paint:paint",
     "//chromeos",
     "//chromeos/assistant:buildflags",
+
+    # TODO(stevenjb): Investigate whether this is OK. https://crbug.com/644336.
+    "//chromeos/audio",
     "//chromeos/components/multidevice/logging",
 
     # TODO(stevenjb): Remove cryptohome dependency. htps://crbug.com/918922.
@@ -1550,6 +1553,9 @@
     "//base:i18n",
     "//chrome:packed_resources",
     "//chromeos",
+
+    # TODO(stevenjb): Investigate whether this is OK. https://crbug.com/644336.
+    "//chromeos/audio",
     "//components/discardable_memory/public/interfaces",
     "//components/services/font:lib",
     "//components/services/font/public/interfaces",
@@ -1923,6 +1929,9 @@
     "//chromeos",
     "//chromeos:test_support",
     "//chromeos:test_support_without_gmock",
+
+    # TODO(stevenjb): Investigate whether this is OK. https://crbug.com/644336.
+    "//chromeos/audio",
     "//chromeos/dbus:power_manager_proto",
     "//chromeos/services/assistant:test_support",
     "//chromeos/services/multidevice_setup/public/cpp:test_support",
@@ -2193,6 +2202,9 @@
     "//chromeos",
     "//chromeos:test_support_without_gmock",
 
+    # TODO(stevenjb): Investigate whether this is OK. https://crbug.com/644336.
+    "//chromeos/audio",
+
     # TODO(stevenjb): Remove cryptohome dependency. htps://crbug.com/918922.
     "//chromeos/cryptohome",
     "//components/account_id",
diff --git a/ash/app_list/views/app_list_view.cc b/ash/app_list/views/app_list_view.cc
index 70c4945..75662d9 100644
--- a/ash/app_list/views/app_list_view.cc
+++ b/ash/app_list/views/app_list_view.cc
@@ -1083,6 +1083,12 @@
 
 void AppListView::OnTabletModeChanged(bool started) {
   is_tablet_mode_ = started;
+
+  // Bottom shelf is enforced in tablet mode. When tablet mode ends, the
+  // AppListView is destroyed so no need to update |is_side_shelf_|.
+  if (started)
+    is_side_shelf_ = false;
+
   search_box_view_->OnTabletModeChanged(started);
   search_model_->SetTabletMode(started);
   GetAppsContainerView()->OnTabletModeChanged(started);
diff --git a/ash/system/tray/actionable_view.cc b/ash/system/tray/actionable_view.cc
index 61a934f..c8011a2 100644
--- a/ash/system/tray/actionable_view.cc
+++ b/ash/system/tray/actionable_view.cc
@@ -16,6 +16,7 @@
 #include "ui/views/animation/ink_drop_impl.h"
 #include "ui/views/animation/ink_drop_mask.h"
 #include "ui/views/painter.h"
+#include "ui/views/view_properties.h"
 
 namespace ash {
 
@@ -63,6 +64,13 @@
   node_data->SetName(GetAccessibleName());
 }
 
+void ActionableView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
+  SetProperty(
+      views::kHighlightPathKey,
+      TrayPopupUtils::CreateHighlightPath(ink_drop_style_, this).release());
+  Button::OnBoundsChanged(previous_bounds);
+}
+
 std::unique_ptr<views::InkDrop> ActionableView::CreateInkDrop() {
   return TrayPopupUtils::CreateInkDrop(this);
 }
@@ -78,10 +86,6 @@
   return TrayPopupUtils::CreateInkDropHighlight(ink_drop_style_, this);
 }
 
-std::unique_ptr<views::InkDropMask> ActionableView::CreateInkDropMask() const {
-  return TrayPopupUtils::CreateInkDropMask(ink_drop_style_, this);
-}
-
 void ActionableView::ButtonPressed(Button* sender, const ui::Event& event) {
   bool destroyed = false;
   destroyed_ = &destroyed;
diff --git a/ash/system/tray/actionable_view.h b/ash/system/tray/actionable_view.h
index bb07a805..65c8f9a 100644
--- a/ash/system/tray/actionable_view.h
+++ b/ash/system/tray/actionable_view.h
@@ -49,11 +49,11 @@
   const char* GetClassName() const override;
   bool OnKeyPressed(const ui::KeyEvent& event) override;
   void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
+  void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
   std::unique_ptr<views::InkDrop> CreateInkDrop() override;
   std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override;
   std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight()
       const override;
-  std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override;
 
   // Overridden from views::ButtonListener.
   void ButtonPressed(Button* sender, const ui::Event& event) override;
diff --git a/ash/system/tray/system_menu_button.cc b/ash/system/tray/system_menu_button.cc
index 7fb759cd..0ce3661 100644
--- a/ash/system/tray/system_menu_button.cc
+++ b/ash/system/tray/system_menu_button.cc
@@ -17,6 +17,7 @@
 #include "ui/views/animation/ink_drop_mask.h"
 #include "ui/views/animation/square_ink_drop_ripple.h"
 #include "ui/views/painter.h"
+#include "ui/views/view_properties.h"
 
 namespace ash {
 
@@ -62,6 +63,14 @@
   ink_drop_color_ = color;
 }
 
+void SystemMenuButton::OnBoundsChanged(const gfx::Rect& previous_bounds) {
+  SetProperty(views::kHighlightPathKey,
+              TrayPopupUtils::CreateHighlightPath(
+                  TrayPopupInkDropStyle::HOST_CENTERED, this)
+                  .release());
+  ImageButton::OnBoundsChanged(previous_bounds);
+}
+
 std::unique_ptr<views::InkDrop> SystemMenuButton::CreateInkDrop() {
   return TrayPopupUtils::CreateInkDrop(this);
 }
@@ -81,10 +90,4 @@
       ink_drop_color_.value_or(kTrayPopupInkDropBaseColor));
 }
 
-std::unique_ptr<views::InkDropMask> SystemMenuButton::CreateInkDropMask()
-    const {
-  return TrayPopupUtils::CreateInkDropMask(TrayPopupInkDropStyle::HOST_CENTERED,
-                                           this);
-}
-
 }  // namespace ash
diff --git a/ash/system/tray/system_menu_button.h b/ash/system/tray/system_menu_button.h
index e81ca20..2eccad49 100644
--- a/ash/system/tray/system_menu_button.h
+++ b/ash/system/tray/system_menu_button.h
@@ -45,11 +45,11 @@
   void SetInkDropColor(SkColor color);
 
   // views::ImageButton:
+  void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
   std::unique_ptr<views::InkDrop> CreateInkDrop() override;
   std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override;
   std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight()
       const override;
-  std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override;
 
  private:
   // Returns the size that the ink drop should be constructed with.
diff --git a/ash/system/tray/tray_background_view.cc b/ash/system/tray/tray_background_view.cc
index 2cce998b..0d220d3 100644
--- a/ash/system/tray/tray_background_view.cc
+++ b/ash/system/tray/tray_background_view.cc
@@ -463,14 +463,8 @@
   path->addRoundRect(gfx::RectToSkRect(GetBackgroundBounds()), border_radius,
                      border_radius);
   SetProperty(views::kHighlightPathKey, path.release());
-  ActionableView::OnBoundsChanged(previous_bounds);
-}
-
-std::unique_ptr<views::InkDropMask> TrayBackgroundView::CreateInkDropMask()
-    const {
-  // Bypass ActionableView to use the default ink-drop mask created from the
-  // highlight path.
-  return Button::CreateInkDropMask();
+  // Bypass ActionableView::OnBoundsChanged which sets its own highlight path.
+  Button::OnBoundsChanged(previous_bounds);
 }
 
 bool TrayBackgroundView::ShouldEnterPushedState(const ui::Event& event) {
diff --git a/ash/system/tray/tray_background_view.h b/ash/system/tray/tray_background_view.h
index b2cbd5a..069917b 100644
--- a/ash/system/tray/tray_background_view.h
+++ b/ash/system/tray/tray_background_view.h
@@ -130,7 +130,6 @@
  protected:
   // ActionableView:
   void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
-  std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override;
   bool ShouldEnterPushedState(const ui::Event& event) override;
   bool PerformAction(const ui::Event& event) override;
   void HandlePerformActionResult(bool action_performed,
diff --git a/ash/system/tray/tray_popup_utils.cc b/ash/system/tray/tray_popup_utils.cc
index 382c6f8..93a589d 100644
--- a/ash/system/tray/tray_popup_utils.cc
+++ b/ash/system/tray/tray_popup_utils.cc
@@ -291,35 +291,31 @@
   return highlight;
 }
 
-std::unique_ptr<views::InkDropMask> TrayPopupUtils::CreateInkDropMask(
+std::unique_ptr<SkPath> TrayPopupUtils::CreateHighlightPath(
     TrayPopupInkDropStyle ink_drop_style,
     const views::View* host) {
-  if (ink_drop_style == TrayPopupInkDropStyle::FILL_BOUNDS)
-    return nullptr;
+  auto path = std::make_unique<SkPath>();
 
-  const gfx::Size layer_size = host->size();
+  const gfx::Rect mask_bounds =
+      GetInkDropBounds(TrayPopupInkDropStyle::HOST_CENTERED, host);
   switch (ink_drop_style) {
     case TrayPopupInkDropStyle::HOST_CENTERED: {
-      const gfx::Rect mask_bounds =
-          GetInkDropBounds(TrayPopupInkDropStyle::HOST_CENTERED, host);
+      gfx::Point center_point = mask_bounds.CenterPoint();
       const int radius =
           std::min(mask_bounds.width(), mask_bounds.height()) / 2;
-      return std::make_unique<views::CircleInkDropMask>(
-          layer_size, mask_bounds.CenterPoint(), radius);
+      path->addCircle(center_point.x(), center_point.y(), radius);
+      break;
     }
-    case TrayPopupInkDropStyle::INSET_BOUNDS: {
-      const gfx::Insets mask_insets =
-          GetInkDropInsets(TrayPopupInkDropStyle::INSET_BOUNDS);
-      return std::make_unique<views::RoundRectInkDropMask>(
-          layer_size, mask_insets, kTrayPopupInkDropCornerRadius);
-    }
+    case TrayPopupInkDropStyle::INSET_BOUNDS:
+      path->addRoundRect(RectToSkRect(mask_bounds),
+                         kTrayPopupInkDropCornerRadius,
+                         kTrayPopupInkDropCornerRadius);
+      break;
     case TrayPopupInkDropStyle::FILL_BOUNDS:
-      // Handled by quick return above.
+      path->addRect(RectToSkRect(mask_bounds));
       break;
   }
-  // Required by some compilers.
-  NOTREACHED();
-  return nullptr;
+  return path;
 }
 
 gfx::Insets TrayPopupUtils::GetInkDropInsets(
diff --git a/ash/system/tray/tray_popup_utils.h b/ash/system/tray/tray_popup_utils.h
index ff1f369..548f0d2 100644
--- a/ash/system/tray/tray_popup_utils.h
+++ b/ash/system/tray/tray_popup_utils.h
@@ -21,7 +21,6 @@
 class InkDropRipple;
 class InkDropHighlight;
 class InkDropHostView;
-class InkDropMask;
 class Label;
 class LabelButton;
 class Painter;
@@ -177,12 +176,9 @@
       const views::View* host,
       SkColor color = kTrayPopupInkDropBaseColor);
 
-  // Creates in InkDropMask instance for |host| according to the
-  // |ink_drop_style|. May return null.
-  //
-  // All targetable views in the system menu should delegate
-  // InkDropHost::CreateInkDropMask() calls here.
-  static std::unique_ptr<views::InkDropMask> CreateInkDropMask(
+  // Creates a SkPath matching the TrayPopupInkDropStyle. This path is normally
+  // used to generate the focus ring and ink drop shapes.
+  static std::unique_ptr<SkPath> CreateHighlightPath(
       TrayPopupInkDropStyle ink_drop_style,
       const views::View* host);
 
diff --git a/cc/animation/animation_host.cc b/cc/animation/animation_host.cc
index b78c578..f5d6109 100644
--- a/cc/animation/animation_host.cc
+++ b/cc/animation/animation_host.cc
@@ -158,10 +158,17 @@
   scoped_refptr<ElementAnimations> element_animations =
       GetElementAnimationsForElementId(element_id);
   DCHECK(element_animations);
+
+  // |ClearAffectedElementTypes| requires an ElementId map in order to update
+  // the property trees. Generating that map requires walking the keyframe
+  // effects, so we have to do it before removing this one.
+  PropertyToElementIdMap element_id_map =
+      element_animations->GetPropertyToElementIdMap();
+
   element_animations->RemoveKeyframeEffect(keyframe_effect);
 
   if (element_animations->IsEmpty()) {
-    element_animations->ClearAffectedElementTypes();
+    element_animations->ClearAffectedElementTypes(element_id_map);
     element_to_animations_map_.erase(element_animations->element_id());
     element_animations->SetAnimationHost(nullptr);
   }
diff --git a/cc/animation/element_animations.cc b/cc/animation/element_animations.cc
index 01722e1..dda8db9 100644
--- a/cc/animation/element_animations.cc
+++ b/cc/animation/element_animations.cc
@@ -84,7 +84,8 @@
   return properties;
 }
 
-void ElementAnimations::ClearAffectedElementTypes() {
+void ElementAnimations::ClearAffectedElementTypes(
+    const PropertyToElementIdMap& element_id_map) {
   DCHECK(animation_host_);
 
   TargetProperties disable_properties = GetPropertiesMaskForAnimationState();
@@ -96,7 +97,7 @@
   // mutator_host_client() to be null.
   if (has_element_in_active_list() && animation_host()->mutator_host_client()) {
     animation_host()->mutator_host_client()->ElementIsAnimatingChanged(
-        element_id(), ElementListType::ACTIVE, disabled_state_mask,
+        element_id_map, ElementListType::ACTIVE, disabled_state_mask,
         disabled_state);
   }
   set_has_element_in_active_list(false);
@@ -104,7 +105,7 @@
   if (has_element_in_pending_list() &&
       animation_host()->mutator_host_client()) {
     animation_host()->mutator_host_client()->ElementIsAnimatingChanged(
-        element_id(), ElementListType::PENDING, disabled_state_mask,
+        element_id_map, ElementListType::PENDING, disabled_state_mask,
         disabled_state);
   }
   set_has_element_in_pending_list(false);
@@ -349,15 +350,17 @@
   DCHECK(pending_state_.IsValid());
   DCHECK(active_state_.IsValid());
 
+  PropertyToElementIdMap element_id_map = GetPropertyToElementIdMap();
+
   if (has_element_in_active_list() && prev_active != active_state_) {
     PropertyAnimationState diff_active = prev_active ^ active_state_;
     animation_host()->mutator_host_client()->ElementIsAnimatingChanged(
-        element_id(), ElementListType::ACTIVE, diff_active, active_state_);
+        element_id_map, ElementListType::ACTIVE, diff_active, active_state_);
   }
   if (has_element_in_pending_list() && prev_pending != pending_state_) {
     PropertyAnimationState diff_pending = prev_pending ^ pending_state_;
     animation_host()->mutator_host_client()->ElementIsAnimatingChanged(
-        element_id(), ElementListType::PENDING, diff_pending, pending_state_);
+        element_id_map, ElementListType::PENDING, diff_pending, pending_state_);
   }
 }
 
@@ -467,6 +470,60 @@
   return gfx::ScrollOffset();
 }
 
+PropertyToElementIdMap ElementAnimations::GetPropertyToElementIdMap() const {
+  // As noted in the header documentation, this method assumes that each
+  // property type maps to at most one ElementId. This is not conceptually true
+  // for cc/animations, but it is true for the current clients:
+  //
+  //   * ui/ does not set per-keyframe-model ElementIds, so this map will be
+  //   each property type mapping to the same ElementId (i.e. element_id()).
+  //
+  //   * blink guarantees that any two keyframe models that it creates which
+  //   target the same property on the same target will have the same ElementId.
+  //
+  // In order to make this as little of a footgun as possible for future-us,
+  // this method DCHECKs that the assumption holds.
+
+  std::vector<PropertyToElementIdMap::value_type> entries;
+  for (int property_index = TargetProperty::FIRST_TARGET_PROPERTY;
+       property_index <= TargetProperty::LAST_TARGET_PROPERTY;
+       ++property_index) {
+    TargetProperty::Type property =
+        static_cast<TargetProperty::Type>(property_index);
+    ElementId element_id_for_property;
+    for (auto& keyframe_effect : keyframe_effects_list_) {
+      KeyframeModel* model = keyframe_effect.GetKeyframeModel(property);
+      if (model) {
+        // We deliberately use two branches here so that the DCHECK can
+        // differentiate between models with different element ids, and the case
+        // where some models don't have an element id.
+        // TODO(crbug.com/900241): All KeyframeModels should have an ElementId.
+        if (model->element_id()) {
+          DCHECK(!element_id_for_property ||
+                 element_id_for_property == model->element_id())
+              << "Different KeyframeModels for the same target must have the "
+              << "same ElementId";
+          element_id_for_property = model->element_id();
+        } else {
+          // This DCHECK isn't perfect; you could have a case where one model
+          // has an ElementId and the other doesn't, but model->element_id() ==
+          // this->element_id() and so the DCHECK passes. That is unlikely
+          // enough that we don't bother guarding against it specifically.
+          DCHECK(!element_id_for_property ||
+                 element_id_for_property == element_id())
+              << "Either all models should have an ElementId or none should";
+          element_id_for_property = element_id();
+        }
+      }
+    }
+
+    if (element_id_for_property)
+      entries.emplace_back(property, element_id_for_property);
+  }
+
+  return PropertyToElementIdMap(std::move(entries));
+}
+
 bool ElementAnimations::KeyframeModelAffectsActiveElements(
     KeyframeModel* keyframe_model) const {
   // When we force a keyframe_model update due to a notification, we do not have
diff --git a/cc/animation/element_animations.h b/cc/animation/element_animations.h
index 7c51dc7..629379a 100644
--- a/cc/animation/element_animations.h
+++ b/cc/animation/element_animations.h
@@ -55,7 +55,7 @@
   void SetAnimationHost(AnimationHost* host);
 
   void InitAffectedElementTypes();
-  void ClearAffectedElementTypes();
+  void ClearAffectedElementTypes(const PropertyToElementIdMap& element_id_map);
 
   void ElementRegistered(ElementId element_id, ElementListType list_type);
   void ElementUnregistered(ElementId element_id, ElementListType list_type);
@@ -164,6 +164,15 @@
 
   gfx::ScrollOffset ScrollOffsetForAnimation() const;
 
+  // Returns a map of target property to the ElementId for that property, for
+  // KeyframeEffects associated with this ElementAnimations.
+  //
+  // This method makes the assumption that a given target property doesn't map
+  // to more than one ElementId. While conceptually this isn't true for
+  // cc/animations, it is true for the two current clients (ui/ and blink) and
+  // this is required to let BGPT ship (see http://crbug.com/912574).
+  PropertyToElementIdMap GetPropertyToElementIdMap() const;
+
  private:
   friend class base::RefCounted<ElementAnimations>;
 
diff --git a/cc/layers/surface_layer_impl.cc b/cc/layers/surface_layer_impl.cc
index 02da1fd..3b411aa7 100644
--- a/cc/layers/surface_layer_impl.cc
+++ b/cc/layers/surface_layer_impl.cc
@@ -180,7 +180,8 @@
       render_pass->CreateAndAppendDrawQuad<viz::SurfaceDrawQuad>();
   surface_draw_quad->SetNew(shared_quad_state, quad_rect, visible_quad_rect,
                             surface_range, background_color(),
-                            stretch_content_to_fill_bounds_);
+                            stretch_content_to_fill_bounds_,
+                            has_pointer_events_none_);
 
   return surface_draw_quad;
 }
diff --git a/cc/mojo_embedder/async_layer_tree_frame_sink_unittest.cc b/cc/mojo_embedder/async_layer_tree_frame_sink_unittest.cc
index 15842fa..cbab4a78 100644
--- a/cc/mojo_embedder/async_layer_tree_frame_sink_unittest.cc
+++ b/cc/mojo_embedder/async_layer_tree_frame_sink_unittest.cc
@@ -251,7 +251,8 @@
                   /*visible_rect=*/rect3_0,
                   viz::SurfaceRange(base::nullopt, child_surface_id),
                   SK_ColorBLACK,
-                  /*stretch_content_to_fill_bounds=*/false);
+                  /*stretch_content_to_fill_bounds=*/false,
+                  /*ignores_input_event=*/false);
   pass_list.push_back(std::move(pass3_0));
 
   auto pass3_1 = viz::RenderPass::Create();
@@ -324,7 +325,8 @@
                   /*visible_rect=*/rect2_0,
                   viz::SurfaceRange(base::nullopt, child_surface_id),
                   SK_ColorBLACK,
-                  /*stretch_content_to_fill_bounds=*/false);
+                  /*stretch_content_to_fill_bounds=*/false,
+                  /*ignores_input_event=*/false);
   pass_list.push_back(std::move(pass2_0));
 
   auto pass2_1 = viz::RenderPass::Create();
diff --git a/cc/test/animation_timelines_test_common.cc b/cc/test/animation_timelines_test_common.cc
index 4199443..a015f50 100644
--- a/cc/test/animation_timelines_test_common.cc
+++ b/cc/test/animation_timelines_test_common.cc
@@ -126,18 +126,17 @@
 }
 
 void TestHostClient::ElementIsAnimatingChanged(
-    ElementId element_id,
+    const PropertyToElementIdMap& element_id_map,
     ElementListType list_type,
     const PropertyAnimationState& mask,
     const PropertyAnimationState& state) {
-  TestLayer* layer = FindTestLayer(element_id, list_type);
-  if (!layer)
-    return;
+  for (const auto& it : element_id_map) {
+    TestLayer* layer = FindTestLayer(it.second, list_type);
+    if (!layer)
+      continue;
 
-  for (int property = TargetProperty::FIRST_TARGET_PROPERTY;
-       property <= TargetProperty::LAST_TARGET_PROPERTY; ++property) {
-    TargetProperty::Type target_property =
-        static_cast<TargetProperty::Type>(property);
+    TargetProperty::Type target_property = it.first;
+    int property = static_cast<int>(target_property);
     if (mask.potentially_animating[property])
       layer->set_has_potential_animation(target_property,
                                          state.potentially_animating[property]);
diff --git a/cc/test/animation_timelines_test_common.h b/cc/test/animation_timelines_test_common.h
index ff76f1d..b18a516 100644
--- a/cc/test/animation_timelines_test_common.h
+++ b/cc/test/animation_timelines_test_common.h
@@ -119,7 +119,7 @@
       ElementListType list_type,
       const gfx::ScrollOffset& scroll_offset) override;
 
-  void ElementIsAnimatingChanged(ElementId element_id,
+  void ElementIsAnimatingChanged(const PropertyToElementIdMap& element_id_map,
                                  ElementListType list_type,
                                  const PropertyAnimationState& mask,
                                  const PropertyAnimationState& state) override;
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index 605b3723..9889b94 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -1718,12 +1718,12 @@
 }
 
 void LayerTreeHost::ElementIsAnimatingChanged(
-    ElementId element_id,
+    const PropertyToElementIdMap& element_id_map,
     ElementListType list_type,
     const PropertyAnimationState& mask,
     const PropertyAnimationState& state) {
   DCHECK_EQ(ElementListType::ACTIVE, list_type);
-  property_trees()->ElementIsAnimatingChanged(mutator_host(), element_id,
+  property_trees()->ElementIsAnimatingChanged(mutator_host(), element_id_map,
                                               list_type, mask, state, true);
 }
 
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index 59563f3..b8489c3 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -638,7 +638,7 @@
       ElementListType list_type,
       const gfx::ScrollOffset& scroll_offset) override;
 
-  void ElementIsAnimatingChanged(ElementId element_id,
+  void ElementIsAnimatingChanged(const PropertyToElementIdMap& element_id_map,
                                  ElementListType list_type,
                                  const PropertyAnimationState& mask,
                                  const PropertyAnimationState& state) override;
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 318b967..9c82ca5 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -5544,7 +5544,7 @@
 }
 
 void LayerTreeHostImpl::ElementIsAnimatingChanged(
-    ElementId element_id,
+    const PropertyToElementIdMap& element_id_map,
     ElementListType list_type,
     const PropertyAnimationState& mask,
     const PropertyAnimationState& state) {
@@ -5552,8 +5552,9 @@
       list_type == ElementListType::ACTIVE ? active_tree() : pending_tree();
   // TODO(wkorman): Explore enabling DCHECK in ElementIsAnimatingChanged()
   // below. Currently enabling causes batch of unit test failures.
-  if (tree && tree->property_trees()->ElementIsAnimatingChanged(
-                  mutator_host(), element_id, list_type, mask, state, false))
+  if (tree &&
+      tree->property_trees()->ElementIsAnimatingChanged(
+          mutator_host(), element_id_map, list_type, mask, state, false))
     tree->set_needs_update_draw_properties();
 }
 
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 11489c6..25acecad4f 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -354,7 +354,7 @@
       ElementId element_id,
       ElementListType list_type,
       const gfx::ScrollOffset& scroll_offset) override;
-  void ElementIsAnimatingChanged(ElementId element_id,
+  void ElementIsAnimatingChanged(const PropertyToElementIdMap& element_id_map,
                                  ElementListType list_type,
                                  const PropertyAnimationState& mask,
                                  const PropertyAnimationState& state) override;
diff --git a/cc/trees/mutator_host_client.h b/cc/trees/mutator_host_client.h
index d3a3e0e..f070e67 100644
--- a/cc/trees/mutator_host_client.h
+++ b/cc/trees/mutator_host_client.h
@@ -44,7 +44,7 @@
 
   // Allows to change IsAnimating value for a set of properties.
   virtual void ElementIsAnimatingChanged(
-      ElementId element_id,
+      const PropertyToElementIdMap& element_id_map,
       ElementListType list_type,
       const PropertyAnimationState& mask,
       const PropertyAnimationState& state) = 0;
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc
index 1e74c89..2b78d1a2 100644
--- a/cc/trees/property_tree.cc
+++ b/cc/trees/property_tree.cc
@@ -1837,7 +1837,7 @@
 
 bool PropertyTrees::ElementIsAnimatingChanged(
     const MutatorHost* mutator_host,
-    ElementId element_id,
+    const PropertyToElementIdMap& element_id_map,
     ElementListType list_type,
     const PropertyAnimationState& mask,
     const PropertyAnimationState& state,
@@ -1849,6 +1849,19 @@
         !mask.potentially_animating[property])
       continue;
 
+    // The mask represents which properties have had their state changed. This
+    // can include properties for which there are no longer any animations, in
+    // which case there will not be an entry in the map.
+    //
+    // It is unclear whether this is desirable; it may be that we are missing
+    // updates to property nodes here because we no longer have the required
+    // ElementId to look them up. See http://crbug.com/912574 for context around
+    // why this code was rewritten.
+    auto it = element_id_map.find(static_cast<TargetProperty::Type>(property));
+    if (it == element_id_map.end())
+      continue;
+
+    const ElementId element_id = it->second;
     switch (property) {
       case TargetProperty::TRANSFORM:
         if (TransformNode* transform_node =
diff --git a/cc/trees/property_tree.h b/cc/trees/property_tree.h
index dcf8cb9..27281e0 100644
--- a/cc/trees/property_tree.h
+++ b/cc/trees/property_tree.h
@@ -657,7 +657,7 @@
   // this property tree. Returns whether a draw property update is
   // needed.
   bool ElementIsAnimatingChanged(const MutatorHost* mutator_host,
-                                 ElementId element_id,
+                                 const PropertyToElementIdMap& element_id_map,
                                  ElementListType list_type,
                                  const PropertyAnimationState& mask,
                                  const PropertyAnimationState& state,
diff --git a/cc/trees/target_property.h b/cc/trees/target_property.h
index 93fa839..f28649c 100644
--- a/cc/trees/target_property.h
+++ b/cc/trees/target_property.h
@@ -7,6 +7,8 @@
 
 #include <bitset>
 
+#include "base/containers/flat_map.h"
+
 namespace cc {
 
 static constexpr size_t kMaxTargetPropertyIndex = 32u;
@@ -32,6 +34,13 @@
 // A set of target properties.
 using TargetProperties = std::bitset<kMaxTargetPropertyIndex>;
 
+// A map of target property to ElementId.
+// flat_map was chosen because there are expected to be relatively few entries
+// in the map. For low number of entries, flat_map is known to perform better
+// than other map implementations.
+struct ElementId;
+using PropertyToElementIdMap = base::flat_map<TargetProperty::Type, ElementId>;
+
 }  // namespace cc
 
 #endif  // CC_TREES_TARGET_PROPERTY_H_
diff --git a/cc/trees/tree_synchronizer.cc b/cc/trees/tree_synchronizer.cc
index c31289f4..80b912a 100644
--- a/cc/trees/tree_synchronizer.cc
+++ b/cc/trees/tree_synchronizer.cc
@@ -9,6 +9,8 @@
 #include <set>
 
 #include "base/containers/flat_set.h"
+#include "base/debug/crash_logging.h"
+#include "base/debug/dump_without_crashing.h"
 #include "base/logging.h"
 #include "base/stl_util.h"
 #include "base/trace_event/trace_event.h"
@@ -154,6 +156,50 @@
 template <typename Iterator>
 static void PushLayerPropertiesInternal(Iterator source_layers_begin,
                                         Iterator source_layers_end,
+                                        LayerTreeHost* host_tree,
+                                        LayerTreeImpl* target_impl_tree) {
+  for (Iterator it = source_layers_begin; it != source_layers_end; ++it) {
+    auto* source_layer = *it;
+    LayerImpl* target_layer = target_impl_tree->LayerById(source_layer->id());
+    DCHECK(target_layer);
+    // TODO(enne): http://crbug.com/918126 debugging
+    if (!target_layer) {
+      bool host_set_on_source = source_layer->layer_tree_host() == host_tree;
+
+      bool source_found_by_iterator = false;
+      for (auto it = host_tree->begin(); it != host_tree->end(); ++it) {
+        if (*it == source_layer) {
+          source_found_by_iterator = true;
+          break;
+        }
+      }
+
+      bool root_layer_valid = !!host_tree->root_layer();
+      bool found_root = false;
+      Layer* layer = source_layer;
+      while (layer) {
+        if (layer == host_tree->root_layer()) {
+          found_root = true;
+          break;
+        }
+        layer = layer->parent();
+      }
+
+      auto str = base::StringPrintf(
+          "hs: %d, sf: %d, rlv: %d, fr: %d", host_set_on_source,
+          source_found_by_iterator, root_layer_valid, found_root);
+      static auto* crash_key = base::debug::AllocateCrashKeyString(
+          "cc_null_layer_sync", base::debug::CrashKeySize::Size32);
+      base::debug::SetCrashKeyString(crash_key, str);
+      base::debug::DumpWithoutCrashing();
+    }
+    source_layer->PushPropertiesTo(target_layer);
+  }
+}
+
+template <typename Iterator>
+static void PushLayerPropertiesInternal(Iterator source_layers_begin,
+                                        Iterator source_layers_end,
                                         LayerTreeImpl* target_impl_tree) {
   for (Iterator it = source_layers_begin; it != source_layers_end; ++it) {
     auto* source_layer = *it;
@@ -183,7 +229,8 @@
   auto layers = host_tree->LayersThatShouldPushProperties();
   TRACE_EVENT1("cc", "TreeSynchronizer::PushLayerPropertiesTo.Main",
                "layer_count", layers.size());
-  PushLayerPropertiesInternal(layers.begin(), layers.end(), impl_tree);
+  PushLayerPropertiesInternal(layers.begin(), layers.end(), host_tree,
+                              impl_tree);
   // When using layer lists, we may not have layers for all property tree
   // node ids and need to synchronize the registered id list.
   if (host_tree->IsUsingLayerLists())
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index ba25f8f..094d9ee5 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -1161,6 +1161,9 @@
         <receiver android:name="org.chromium.chrome.browser.offlinepages.prefetch.PrefetchedPagesNotifier$SettingsReceiver"
             android:exported="false"/>
 
+        <receiver android:name="org.chromium.chrome.browser.offlinepages.AutoFetchNotifier$ClickReceiver"
+            android:exported="false"/>
+
         <service android:name="org.chromium.chrome.browser.media.MediaCaptureNotificationService"
             android:exported="false"/>
         <service android:name="org.chromium.chrome.browser.media.ui.MediaNotificationManager$PlaybackListenerService"
diff --git a/chrome/android/java/AndroidManifest_trichrome_library.xml b/chrome/android/java/AndroidManifest_trichrome_library.xml
index 42274131..8e06286 100644
--- a/chrome/android/java/AndroidManifest_trichrome_library.xml
+++ b/chrome/android/java/AndroidManifest_trichrome_library.xml
@@ -10,11 +10,12 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     package="{{ manifest_package }}"
-    tools:ignore="MissingVersion">
+    tools:ignore="MissingVersion,MissingLeanbackLauncher">
 
     <uses-sdk android:minSdkVersion="{{min_sdk_version}}" android:targetSdkVersion="{{target_sdk_version}}" />
     <uses-feature android:glEsVersion="0x00020000" />
     <uses-feature android:name="android.hardware.touchscreen" android:required="false" />
+    <uses-feature android:name="android.software.leanback" android:required="false" />
 
     <!-- TODO(torne): we should specify an icon, roundIcon, and label from resources. -->
     <application
diff --git a/chrome/android/java/res/drawable-hdpi/infobar_3d_blocked.png b/chrome/android/java/res/drawable-hdpi/infobar_3d_blocked.png
deleted file mode 100644
index 99869ab..0000000
--- a/chrome/android/java/res/drawable-hdpi/infobar_3d_blocked.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/infobar_3d_blocked.png b/chrome/android/java/res/drawable-mdpi/infobar_3d_blocked.png
deleted file mode 100644
index afc66b5..0000000
--- a/chrome/android/java/res/drawable-mdpi/infobar_3d_blocked.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/infobar_3d_blocked.png b/chrome/android/java/res/drawable-xhdpi/infobar_3d_blocked.png
deleted file mode 100644
index dd1d962..0000000
--- a/chrome/android/java/res/drawable-xhdpi/infobar_3d_blocked.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/infobar_3d_blocked.png b/chrome/android/java/res/drawable-xxhdpi/infobar_3d_blocked.png
deleted file mode 100644
index b6b658ff..0000000
--- a/chrome/android/java/res/drawable-xxhdpi/infobar_3d_blocked.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/infobar_3d_blocked.png b/chrome/android/java/res/drawable-xxxhdpi/infobar_3d_blocked.png
deleted file mode 100644
index e001933b..0000000
--- a/chrome/android/java/res/drawable-xxxhdpi/infobar_3d_blocked.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index b87a061..2e411a4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -1242,17 +1242,8 @@
                     Tab currentTab = getActivityTab();
                     if (currentTab != null) {
                         TabRedirectHandler.from(currentTab).updateIntent(intent);
-                        int transitionType = PageTransition.LINK | PageTransition.FROM_API;
-                        LoadUrlParams loadUrlParams = new LoadUrlParams(url);
-                        loadUrlParams.setIntentReceivedTimestamp(mIntentHandlingTimeMs);
-                        loadUrlParams.setHasUserGesture(hasUserGesture);
-                        loadUrlParams.setTransitionType(IntentHandler.getTransitionTypeFromIntent(
-                                intent, transitionType));
-                        if (referer != null) {
-                            loadUrlParams.setReferrer(new Referrer(
-                                    referer, IntentHandler.getReferrerPolicyFromIntent(intent)));
-                        }
-                        currentTab.loadUrl(loadUrlParams);
+                        currentTab.loadUrl(ChromeTabbedActivity.createLoadUrlParamsForIntent(
+                                url, referer, hasUserGesture, mIntentHandlingTimeMs, intent));
                     } else {
                         launchIntent(url, referer, headers, externalAppId, true, intent);
                     }
@@ -1260,6 +1251,31 @@
                 case TabOpenType.REUSE_APP_ID_MATCHING_TAB_ELSE_NEW_TAB:
                     openNewTab(url, referer, headers, externalAppId, intent, false);
                     break;
+                case TabOpenType.REUSE_TAB_MATCHING_ID_ELSE_NEW_TAB:
+                    int tabId = IntentUtils.safeGetIntExtra(
+                            intent, TabOpenType.REUSE_TAB_MATCHING_ID_STRING, Tab.INVALID_TAB_ID);
+                    if (tabId != Tab.INVALID_TAB_ID) {
+                        mTabModelSelectorImpl.tryToRestoreTabStateForId(tabId);
+                        int matchingTabIndex = TabModelUtils.getTabIndexById(tabModel, tabId);
+                        boolean loaded = false;
+                        if (matchingTabIndex != TabModel.INVALID_TAB_INDEX) {
+                            Tab tab = tabModel.getTabAt(matchingTabIndex);
+                            if (tab.getUrl().equals(url)) {
+                                tabModel.setIndex(matchingTabIndex, TabSelectionType.FROM_USER);
+                                LoadUrlParams loadUrlParams =
+                                        ChromeTabbedActivity.createLoadUrlParamsForIntent(url,
+                                                referer, hasUserGesture, mIntentHandlingTimeMs,
+                                                intent);
+                                loadUrlParams.setVerbatimHeaders(headers);
+                                tab.loadUrl(loadUrlParams);
+                                loaded = true;
+                            }
+                        }
+                        if (!loaded) {
+                            openNewTab(url, referer, headers, externalAppId, intent, false);
+                        }
+                    }
+                    break;
                 case TabOpenType.OPEN_NEW_TAB:
                     if (fromLauncherShortcut) {
                         recordLauncherShortcutAction(false);
@@ -1908,6 +1924,24 @@
     }
 
     /**
+     * Create a LoadUrlParams for handling a VIEW intent.
+     */
+    private static LoadUrlParams createLoadUrlParamsForIntent(String url, String referer,
+            boolean hasUserGesture, long intentHandlingTimeMs, Intent intent) {
+        LoadUrlParams loadUrlParams = new LoadUrlParams(url);
+        loadUrlParams.setIntentReceivedTimestamp(intentHandlingTimeMs);
+        loadUrlParams.setHasUserGesture(hasUserGesture);
+        int transitionType = PageTransition.LINK | PageTransition.FROM_API;
+        loadUrlParams.setTransitionType(
+                IntentHandler.getTransitionTypeFromIntent(intent, transitionType));
+        if (referer != null) {
+            loadUrlParams.setReferrer(
+                    new Referrer(referer, IntentHandler.getReferrerPolicyFromIntent(intent)));
+        }
+        return loadUrlParams;
+    }
+
+    /**
      * Launch a URL from an intent.
      *
      * @param url           The url from the intent.
@@ -1935,12 +1969,13 @@
             LoadUrlParams loadUrlParams = new LoadUrlParams(url);
             loadUrlParams.setIntentReceivedTimestamp(mIntentHandlingTimeMs);
             loadUrlParams.setVerbatimHeaders(headers);
-            return getTabCreator(isIncognito).createNewTab(
-                    loadUrlParams,
-                    fromLauncherShortcut ? TabLaunchType.FROM_LAUNCHER_SHORTCUT
-                            : TabLaunchType.FROM_LINK,
-                    null,
-                    intent);
+            @TabLaunchType
+            Integer launchType = IntentHandler.getTabLaunchType(intent);
+            if (launchType == null) {
+                launchType = fromLauncherShortcut ? TabLaunchType.FROM_LAUNCHER_SHORTCUT
+                                                  : TabLaunchType.FROM_LINK;
+            }
+            return getTabCreator(isIncognito).createNewTab(loadUrlParams, launchType, null, intent);
         } else {
             // Check if the tab is being created from a Reader Mode navigation.
             if (ReaderModeManager.isEnabled(this)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
index afce41d0..14b8b294 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
@@ -60,6 +60,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 
 /**
  * Handles all browser-related Intents.
@@ -280,7 +281,8 @@
 
     @IntDef({TabOpenType.OPEN_NEW_TAB, TabOpenType.REUSE_URL_MATCHING_TAB_ELSE_NEW_TAB,
             TabOpenType.REUSE_APP_ID_MATCHING_TAB_ELSE_NEW_TAB, TabOpenType.CLOBBER_CURRENT_TAB,
-            TabOpenType.BRING_TAB_TO_FRONT, TabOpenType.OPEN_NEW_INCOGNITO_TAB})
+            TabOpenType.BRING_TAB_TO_FRONT, TabOpenType.OPEN_NEW_INCOGNITO_TAB,
+            TabOpenType.REUSE_TAB_MATCHING_ID_ELSE_NEW_TAB})
     @Retention(RetentionPolicy.SOURCE)
     public @interface TabOpenType {
         int OPEN_NEW_TAB = 0;
@@ -292,8 +294,13 @@
         int BRING_TAB_TO_FRONT = 4;
         // Opens a new incognito tab.
         int OPEN_NEW_INCOGNITO_TAB = 5;
+        // Tab is reused only if the tab ID exists (tab ID is specified with the integer extra
+        // REUSE_TAB_MATCHING_ID_STRING), and if the tab matches the requested URL.
+        // Otherwise, the URL is opened in a new tab.
+        int REUSE_TAB_MATCHING_ID_ELSE_NEW_TAB = 6;
 
         String BRING_TAB_TO_FRONT_STRING = "BRING_TAB_TO_FRONT";
+        String REUSE_TAB_MATCHING_ID_STRING = "REUSE_TAB_MATCHING_ID";
     }
 
     /**
@@ -727,6 +734,26 @@
     }
 
     /**
+     * Sets the Extra field 'EXTRA_HEADERS' on intent. If |extraHeaders| is empty or null,
+     * removes 'EXTRA_HEADERS' from intent.
+     *
+     * @param extraHeaders   A map containing the set of headers. May be null.
+     * @param intent         The intent to modify.
+     */
+    public static void setIntentExtraHeaders(
+            @Nullable Map<String, String> extraHeaders, Intent intent) {
+        if (extraHeaders == null || extraHeaders.isEmpty()) {
+            intent.removeExtra(Browser.EXTRA_HEADERS);
+        } else {
+            Bundle bundle = new Bundle();
+            for (Map.Entry<String, String> header : extraHeaders.entrySet()) {
+                bundle.putString(header.getKey(), header.getValue());
+            }
+            intent.putExtra(Browser.EXTRA_HEADERS, bundle);
+        }
+    }
+
+    /**
      * Calls {@link #getExtraHeadersFromIntent(Intent, boolean)} with shouldLogHeaders as false.
      */
     public static String getExtraHeadersFromIntent(Intent intent) {
@@ -1015,6 +1042,12 @@
             return TabOpenType.OPEN_NEW_TAB;
         }
 
+        int tabId = IntentUtils.safeGetIntExtra(
+                intent, TabOpenType.REUSE_TAB_MATCHING_ID_STRING, Tab.INVALID_TAB_ID);
+        if (tabId != Tab.INVALID_TAB_ID) {
+            return TabOpenType.REUSE_TAB_MATCHING_ID_ELSE_NEW_TAB;
+        }
+
         // Intents from chrome open in the same tab by default, all others only clobber
         // tabs created by the same app.
         return mPackageName.equals(appId) ? TabOpenType.CLOBBER_CURRENT_TAB
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AbstractAutofillAssistantUiController.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AbstractAutofillAssistantUiController.java
index 93bc2f2..6d9fc29 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AbstractAutofillAssistantUiController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AbstractAutofillAssistantUiController.java
@@ -12,7 +12,4 @@
  * merges to M72.
  */
 abstract class AbstractAutofillAssistantUiController
-        implements AutofillAssistantUiDelegate.Client, UiDelegateHolder.Listener {
-    /** Interface called to initiate controller. */
-    public void init(UiDelegateHolder delegateHolder, Details details) {}
-}
\ No newline at end of file
+        implements AutofillAssistantUiDelegate.Client, UiDelegateHolder.Listener {}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantClient.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantClient.java
new file mode 100644
index 0000000..9baeaad
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantClient.java
@@ -0,0 +1,223 @@
+// 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.autofill_assistant;
+
+import android.accounts.Account;
+import android.content.Context;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.telephony.TelephonyManager;
+
+import org.chromium.base.ContextUtils;
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+import org.chromium.components.signin.AccountManagerFacade;
+import org.chromium.components.signin.OAuth2TokenService;
+import org.chromium.content_public.browser.WebContents;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * An Autofill Assistant client, associated with a specific WebContents.
+ *
+ * This mainly a bridge to autofill_assistant::ClientAndroid.
+ */
+@JNINamespace("autofill_assistant")
+class AutofillAssistantClient {
+    /** OAuth2 scope that RPCs require. */
+    private static final String AUTH_TOKEN_TYPE =
+            "oauth2:https://www.googleapis.com/auth/userinfo.profile";
+    private static final String PARAMETER_USER_EMAIL = "USER_EMAIL";
+
+    /**
+     * Pointer to the corresponding native autofill_assistant::ClientAndroid instance. Might be 0 if
+     * the native instance has been deleted. Always check before use.
+     */
+    private long mNativeClientAndroid;
+
+    /**
+     * Indicates whether {@link mAccount} has been initialized.
+     */
+    private boolean mAccountInitialized;
+
+    /**
+     * Account that was used to initiate AutofillAssistant.
+     *
+     * <p>This account is used to  authenticate when sending RPCs and as default account for Payment
+     * Request. Not relevant until the accounts have been fetched, and mAccountInitialized set to
+     * true. Can still be null after the accounts are fetched, in which case authentication is
+     * disabled.
+     */
+    @Nullable
+    private Account mAccount;
+
+    /** If set, fetch the access token once the accounts are fetched. */
+    private boolean mShouldFetchAccessToken;
+
+    /** Returns the client for the given web contents, creating it if necessary. */
+    public static AutofillAssistantClient fromWebContents(WebContents webContents) {
+        return nativeFromWebContents(webContents);
+    }
+
+    private AutofillAssistantClient(long nativeClientAndroid) {
+        mNativeClientAndroid = nativeClientAndroid;
+    }
+
+    /**
+     * Launches Autofill Assistant on the current web contents, expecting autostart.
+     */
+    public void start(String initialUrl, Map<String, String> parameters, Bundle intentExtras) {
+        if (mNativeClientAndroid == 0) {
+            throw new IllegalStateException("Native instance is dead");
+        }
+        nativeAutostart(mNativeClientAndroid, initialUrl,
+                parameters.keySet().toArray(new String[parameters.size()]),
+                parameters.values().toArray(new String[parameters.size()]));
+        chooseAccountAsync(parameters.get(PARAMETER_USER_EMAIL), intentExtras);
+    }
+
+    @CalledByNative
+    private static AutofillAssistantClient create(long nativeClientAndroid) {
+        return new AutofillAssistantClient(nativeClientAndroid);
+    }
+
+    private void chooseAccountAsync(@Nullable String accountFromParameter, Bundle extras) {
+        AccountManagerFacade.get().tryGetGoogleAccounts(accounts -> {
+            if (mNativeClientAndroid == 0) return;
+            if (accounts.size() == 1) {
+                // If there's only one account, there aren't any doubts.
+                onAccountChosen(accounts.get(0));
+                return;
+            }
+            Account signedIn =
+                    findAccountByName(accounts, nativeGetPrimaryAccountName(mNativeClientAndroid));
+            if (signedIn != null) {
+                // TODO(crbug.com/806868): Compare against account name from extras and complain if
+                // they don't match.
+                onAccountChosen(signedIn);
+                return;
+            }
+
+            if (accountFromParameter != null) {
+                Account account = findAccountByName(accounts, accountFromParameter);
+                if (account != null) {
+                    onAccountChosen(account);
+                    return;
+                }
+            }
+
+            for (String extra : extras.keySet()) {
+                // TODO(crbug.com/806868): Deprecate ACCOUNT_NAME.
+                if (extra.endsWith("ACCOUNT_NAME")) {
+                    Account account = findAccountByName(accounts, extras.getString(extra));
+                    if (account != null) {
+                        onAccountChosen(account);
+                        return;
+                    }
+                }
+            }
+            onAccountChosen(null);
+        });
+    }
+
+    private void onAccountChosen(@Nullable Account account) {
+        mAccount = account;
+        mAccountInitialized = true;
+        // TODO(crbug.com/806868): Consider providing a way of signing in this case, to enforce
+        // that all calls are authenticated.
+
+        if (mShouldFetchAccessToken) {
+            mShouldFetchAccessToken = false;
+            fetchAccessToken();
+        }
+    }
+
+    private static Account findAccountByName(List<Account> accounts, String name) {
+        for (int i = 0; i < accounts.size(); i++) {
+            Account account = accounts.get(i);
+            if (account.name.equals(name)) {
+                return account;
+            }
+        }
+        return null;
+    }
+
+    @CalledByNative
+    private void fetchAccessToken() {
+        if (!mAccountInitialized) {
+            // Still getting the account list. Fetch the token as soon as an account is available.
+            mShouldFetchAccessToken = true;
+            return;
+        }
+        if (mAccount == null) {
+            if (mNativeClientAndroid != 0) nativeOnAccessToken(mNativeClientAndroid, true, "");
+            return;
+        }
+
+        OAuth2TokenService.getAccessToken(
+                mAccount, AUTH_TOKEN_TYPE, new OAuth2TokenService.GetAccessTokenCallback() {
+                    @Override
+                    public void onGetTokenSuccess(String token) {
+                        if (mNativeClientAndroid != 0) {
+                            nativeOnAccessToken(mNativeClientAndroid, true, token);
+                        }
+                    }
+
+                    @Override
+                    public void onGetTokenFailure(boolean isTransientError) {
+                        if (!isTransientError && mNativeClientAndroid != 0) {
+                            nativeOnAccessToken(mNativeClientAndroid, false, "");
+                        }
+                    }
+                });
+    }
+
+    @CalledByNative
+    private void invalidateAccessToken(String accessToken) {
+        if (mAccount == null) {
+            return;
+        }
+
+        OAuth2TokenService.invalidateAccessToken(accessToken);
+    }
+
+    /** Returns the e-mail address that corresponds to the access token or an empty string. */
+    @CalledByNative
+    private String getAccountEmailAddress() {
+        return mAccount != null ? mAccount.name : "";
+    }
+
+    /**
+     * Returns the country that the device is currently located in. This currently only works
+     * for devices with active SIM cards. For a more general solution, we should probably use
+     * the LocationManager together with the Geocoder.
+     */
+    @CalledByNative
+    private String getCountryCode() {
+        TelephonyManager telephonyManager =
+                (TelephonyManager) ContextUtils.getApplicationContext().getSystemService(
+                        Context.TELEPHONY_SERVICE);
+
+        // According to API, location for CDMA networks is unreliable
+        if (telephonyManager != null
+                && telephonyManager.getPhoneType() != TelephonyManager.PHONE_TYPE_CDMA)
+            return telephonyManager.getNetworkCountryIso();
+
+        return null;
+    }
+
+    @CalledByNative
+    private void clearNativePtr() {
+        mNativeClientAndroid = 0;
+    }
+
+    private static native AutofillAssistantClient nativeFromWebContents(WebContents webContents);
+    private native void nativeAutostart(long nativeClientAndroid, String initialUrl,
+            String[] parameterNames, String[] parameterValues);
+    private native void nativeOnAccessToken(
+            long nativeClientAndroid, boolean success, String accessToken);
+    private native String nativeGetPrimaryAccountName(long nativeClientAndroid);
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java
index 40c7a6f..074d2a4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java
@@ -11,12 +11,8 @@
 import android.support.annotation.VisibleForTesting;
 
 import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.base.Callback;
 import org.chromium.chrome.browser.ChromeActivity;
-import org.chromium.chrome.browser.tab.EmptyTabObserver;
-import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver;
-import org.chromium.chrome.browser.tabmodel.TabModel;
-import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType;
 import org.chromium.chrome.browser.util.IntentUtils;
 
 import java.util.HashMap;
@@ -60,69 +56,42 @@
 
     /** Starts Autofill Assistant on the given {@code activity}. */
     public static void start(ChromeActivity activity) {
-        startInternal(activity, /* controller= */ null);
+        startWithCallback(activity, (canStart) -> {
+            if (canStart) {
+                initiateAutofillAssistant(activity);
+            }
+        });
     }
 
+    /**
+     * Decides whether to start Autofill Assistant. If necessary, start the first-time screen
+     * to let the user choose.
+     */
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
-    static void startInternal(
-            ChromeActivity activity, @Nullable AbstractAutofillAssistantUiController controller) {
-        Map<String, String> parameters = extractParameters(activity.getInitialIntent().getExtras());
-        parameters.remove(PARAMETER_ENABLED);
-
-        final AbstractAutofillAssistantUiController targetController = controller == null
-                ? new AutofillAssistantUiController(activity, parameters)
-                : controller;
+    static void startWithCallback(ChromeActivity activity, Callback<Boolean> startCallback) {
         if (canStart(activity.getInitialIntent())) {
-            initiateAutofillAssistant(activity, parameters, targetController);
+            startCallback.onResult(true);
             return;
         }
         if (AutofillAssistantPreferencesUtil.getShowOnboarding()) {
-            FirstRunScreen.show(activity, (result) -> {
-                if (result) initiateAutofillAssistant(activity, parameters, targetController);
-            });
+            FirstRunScreen.show(activity, startCallback);
             return;
         }
-
         // We don't have consent to start Autofill Assistant and cannot show initial screen.
-        // Do nothing.
+        startCallback.onResult(false);
     }
 
     /**
      * Instantiates all essential Autofill Assistant components and starts it.
      */
-    private static void initiateAutofillAssistant(ChromeActivity activity,
-            Map<String, String> parameters, AbstractAutofillAssistantUiController controller) {
-        UiDelegateHolder delegateHolder = new UiDelegateHolder(
-                new AutofillAssistantUiDelegate(activity, controller), controller);
-        initTabObservers(activity, delegateHolder);
+    private static void initiateAutofillAssistant(ChromeActivity activity) {
+        Map<String, String> parameters = extractParameters(activity.getInitialIntent().getExtras());
+        parameters.remove(PARAMETER_ENABLED);
+        String initialUrl = activity.getInitialIntent().getDataString();
 
-        controller.init(delegateHolder, Details.makeFromParameters(parameters));
-    }
-
-    private static void initTabObservers(ChromeActivity activity, UiDelegateHolder delegateHolder) {
-        // Shut down Autofill Assistant when the tab is detached from the activity.
-        //
-        // Note: For now this logic assumes that |activity| is a CustomTabActivity.
-        Tab activityTab = activity.getActivityTab();
-        activityTab.addObserver(new EmptyTabObserver() {
-            @Override
-            public void onActivityAttachmentChanged(Tab tab, boolean isAttached) {
-                if (!isAttached) {
-                    activityTab.removeObserver(this);
-                    delegateHolder.shutdown();
-                }
-            }
-        });
-
-        // Shut down Autofill Assistant when the selected tab (foreground tab) is changed.
-        TabModel currentTabModel = activity.getTabModelSelector().getCurrentModel();
-        currentTabModel.addObserver(new EmptyTabModelObserver() {
-            @Override
-            public void didSelectTab(Tab tab, @TabSelectionType int type, int lastId) {
-                currentTabModel.removeObserver(this);
-                delegateHolder.giveUp();
-            }
-        });
+        AutofillAssistantClient client =
+                AutofillAssistantClient.fromWebContents(activity.getActivityTab().getWebContents());
+        client.start(initialUrl, parameters, activity.getInitialIntent().getExtras());
     }
 
     /** Return the value if the given boolean parameter from the extras. */
@@ -132,7 +101,7 @@
     }
 
     /** Returns a map containing the extras starting with {@link #INTENT_EXTRA_PREFIX}. */
-    private static Map<String, String> extractParameters(@Nullable Bundle extras) {
+    static Map<String, String> extractParameters(@Nullable Bundle extras) {
         Map<String, String> result = new HashMap<>();
         if (extras != null) {
             for (String key : extras.keySet()) {
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 3b7ad58..29d5867 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
@@ -4,22 +4,14 @@
 
 package org.chromium.chrome.browser.autofill_assistant;
 
-import android.accounts.Account;
-import android.content.Context;
 import android.graphics.RectF;
-import android.os.Bundle;
 import android.support.annotation.Nullable;
-import android.telephony.TelephonyManager;
 
-import org.chromium.base.ContextUtils;
-import org.chromium.base.LocaleUtils;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.chrome.autofill_assistant.R;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.autofill.PersonalDataManager;
-import org.chromium.components.signin.AccountManagerFacade;
-import org.chromium.components.signin.OAuth2TokenService;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.payments.mojom.PaymentOptions;
 
@@ -28,7 +20,6 @@
 import java.util.Collections;
 import java.util.Date;
 import java.util.List;
-import java.util.Map;
 
 /**
  * Bridge to native side autofill_assistant::UiControllerAndroid. It allows native side to control
@@ -36,70 +27,48 @@
  */
 @JNINamespace("autofill_assistant")
 public class AutofillAssistantUiController extends AbstractAutofillAssistantUiController {
-    /** OAuth2 scope that RPCs require. */
-    private static final String AUTH_TOKEN_TYPE =
-            "oauth2:https://www.googleapis.com/auth/userinfo.profile";
-    private static final String PARAMETER_USER_EMAIL = "USER_EMAIL";
-
     private final WebContents mWebContents;
-    private final String mInitialUrl;
 
     // TODO(crbug.com/806868): Move mCurrentDetails and mStatusMessage to a Model (refactor to MVC).
     private Details mCurrentDetails = Details.EMPTY_DETAILS;
     private String mStatusMessage;
 
     /** Native pointer to the UIController. */
-    private long mUiControllerAndroid;
+    private long mNativeUiController;
 
     private UiDelegateHolder mUiDelegateHolder;
 
     /**
-     * Indicates whether {@link mAccount} has been initialized.
-     */
-    private boolean mAccountInitialized;
-
-    /**
-     * Account that was used to initiate AutofillAssistant.
+     * Creates the UI Controller and UI.
      *
-     * <p>This account is used to  authenticate when sending RPCs and as default account for Payment
-     * Request. Not relevant until the accounts have been fetched, and mAccountInitialized set to
-     * true. Can still be null after the accounts are fetched, in which case authentication is
-     * disabled.
+     * @param webContents WebContents the controller is associated to
+     * @param mNativeUiController native autofill_assistant::NativeUiController instance
      */
-    @Nullable
-    private Account mAccount;
+    @CalledByNative
+    private static AutofillAssistantUiController createAndStartUi(
+            WebContents webContents, long nativeUiController) {
+        ChromeActivity activity = ChromeActivity.fromWebContents(webContents);
+        assert activity != null;
+        // TODO(crbug.com/806868): Keep details on the native side and get rid of this duplicated,
+        // misplaced, call to extractParameters.
+        Details details = Details.makeFromParameters(
+                AutofillAssistantFacade.extractParameters(activity.getInitialIntent().getExtras()));
+        AutofillAssistantUiController controller =
+                new AutofillAssistantUiController(webContents, nativeUiController, details);
+        controller.mUiDelegateHolder = AutofillAssistantUiDelegate.start(activity, controller);
+        return controller;
+    }
 
-    /** If set, fetch the access token once the accounts are fetched. */
-    private boolean mShouldFetchAccessToken;
-
-    /**
-     * Construct Autofill Assistant UI controller.
-     *
-     * @param activity The ChromeActivity of the controller associated with.
-     */
-    public AutofillAssistantUiController(ChromeActivity activity, Map<String, String> parameters) {
-        mWebContents = activity.getActivityTab().getWebContents();
-        mInitialUrl = activity.getInitialIntent().getDataString();
-
-        mUiControllerAndroid =
-                nativeInit(mWebContents, parameters.keySet().toArray(new String[parameters.size()]),
-                        parameters.values().toArray(new String[parameters.size()]),
-                        LocaleUtils.getDefaultLocaleString(), getCountryIso());
-
-        chooseAccountAsync(
-                parameters.get(PARAMETER_USER_EMAIL), activity.getInitialIntent().getExtras());
+    private AutofillAssistantUiController(
+            WebContents webContents, long nativeUiController, Details details) {
+        mWebContents = webContents;
+        mNativeUiController = nativeUiController;
+        mCurrentDetails = details;
     }
 
     @CalledByNative
-    private void onNativeDestroy() {
-        mUiControllerAndroid = 0;
-    }
-
-    @Override
-    public void init(UiDelegateHolder delegateHolder, Details details) {
-        mUiDelegateHolder = delegateHolder;
-        maybeUpdateDetails(details);
-        if (mUiControllerAndroid != 0) nativeStart(mUiControllerAndroid, mInitialUrl);
+    private void clearNativePtr() {
+        mNativeUiController = 0;
     }
 
     @Override
@@ -124,55 +93,55 @@
 
     @Override
     public void updateTouchableArea() {
-        if (mUiControllerAndroid != 0) nativeUpdateTouchableArea(mUiControllerAndroid);
+        if (mNativeUiController != 0) nativeUpdateTouchableArea(mNativeUiController);
     }
 
     @Override
     public void onUserInteractionInsideTouchableArea() {
-        if (mUiControllerAndroid != 0)
-            nativeOnUserInteractionInsideTouchableArea(mUiControllerAndroid);
+        if (mNativeUiController != 0)
+            nativeOnUserInteractionInsideTouchableArea(mNativeUiController);
     }
 
     @Override
     public void onScriptSelected(String scriptPath) {
-        if (mUiControllerAndroid != 0) nativeOnScriptSelected(mUiControllerAndroid, scriptPath);
+        if (mNativeUiController != 0) nativeOnScriptSelected(mNativeUiController, scriptPath);
     }
 
     @Override
     public void onChoice(byte[] serverPayload) {
-        if (mUiControllerAndroid != 0) nativeOnChoice(mUiControllerAndroid, serverPayload);
+        if (mNativeUiController != 0) nativeOnChoice(mNativeUiController, serverPayload);
     }
 
     @Override
     public void onAddressSelected(String guid) {
-        if (mUiControllerAndroid != 0) nativeOnAddressSelected(mUiControllerAndroid, guid);
+        if (mNativeUiController != 0) nativeOnAddressSelected(mNativeUiController, guid);
     }
 
     @Override
     public void onCardSelected(String guid) {
-        if (mUiControllerAndroid != 0) nativeOnCardSelected(mUiControllerAndroid, guid);
+        if (mNativeUiController != 0) nativeOnCardSelected(mNativeUiController, guid);
     }
 
     @Override
     public void onDetailsAcknowledged(Details displayedDetails, boolean canContinue) {
         mCurrentDetails = displayedDetails;
-        if (mUiControllerAndroid != 0) nativeOnShowDetails(mUiControllerAndroid, canContinue);
+        if (mNativeUiController != 0) nativeOnShowDetails(mNativeUiController, canContinue);
     }
 
     @Override
     public String getDebugContext() {
-        if (mUiControllerAndroid == 0) return "";
-        return nativeOnRequestDebugContext(mUiControllerAndroid);
+        if (mNativeUiController == 0) return "";
+        return nativeOnRequestDebugContext(mNativeUiController);
     }
 
     @Override
     public void onCompleteShutdown() {
-        if (mUiControllerAndroid != 0) nativeDestroy(mUiControllerAndroid);
+        if (mNativeUiController != 0) nativeStop(mNativeUiController);
     }
 
     @CalledByNative
     private void onAllowShowingSoftKeyboard(boolean allowed) {
-        this.mUiDelegateHolder.performUiOperation(
+        mUiDelegateHolder.performUiOperation(
                 uiDelegate -> uiDelegate.allowShowingSoftKeyboard(allowed));
     }
 
@@ -275,9 +244,9 @@
     }
 
     @CalledByNative
-    private void onRequestPaymentInformation(boolean requestShipping, boolean requestPayerName,
-            boolean requestPayerPhone, boolean requestPayerEmail, int shippingType, String title,
-            String[] supportedBasicCardNetworks) {
+    private void onRequestPaymentInformation(String defaultEmail, boolean requestShipping,
+            boolean requestPayerName, boolean requestPayerPhone, boolean requestPayerEmail,
+            int shippingType, String title, String[] supportedBasicCardNetworks) {
         PaymentOptions paymentOptions = new PaymentOptions();
         paymentOptions.requestShipping = requestShipping;
         paymentOptions.requestPayerName = requestPayerName;
@@ -285,15 +254,13 @@
         paymentOptions.requestPayerEmail = requestPayerEmail;
         paymentOptions.shippingType = shippingType;
 
-        String defaultEmail = mAccount != null ? mAccount.name : "";
-
         mUiDelegateHolder.performUiOperation(uiDelegate -> {
             uiDelegate.showPaymentRequest(mWebContents, paymentOptions, title,
                     supportedBasicCardNetworks, defaultEmail, (selectedPaymentInformation -> {
                         uiDelegate.closePaymentRequest();
                         if (selectedPaymentInformation.succeed) {
-                            if (mUiControllerAndroid != 0) {
-                                nativeOnGetPaymentInformation(mUiControllerAndroid,
+                            if (mNativeUiController != 0) {
+                                nativeOnGetPaymentInformation(mNativeUiController,
                                         selectedPaymentInformation.succeed,
                                         selectedPaymentInformation.card,
                                         selectedPaymentInformation.address,
@@ -320,8 +287,8 @@
     void maybeUpdateDetails(Details newDetails) {
         if (mCurrentDetails.isEmpty() && newDetails.isEmpty()) {
             // No update on UI needed.
-            if (mUiControllerAndroid != 0) {
-                nativeOnShowDetails(mUiControllerAndroid, /* canContinue= */ true);
+            if (mNativeUiController != 0) {
+                nativeOnShowDetails(mNativeUiController, /* canContinue= */ true);
             }
             return;
         }
@@ -377,134 +344,13 @@
                 uiDelegate -> { uiDelegate.updateTouchableArea(enabled, boxes); });
     }
 
-
-    @CalledByNative
-    private void fetchAccessToken() {
-        if (!mAccountInitialized) {
-            // Still getting the account list. Fetch the token as soon as an account is available.
-            mShouldFetchAccessToken = true;
-            return;
-        }
-        if (mAccount == null) {
-            if (mUiControllerAndroid != 0) nativeOnAccessToken(mUiControllerAndroid, true, "");
-            return;
-        }
-
-        OAuth2TokenService.getAccessToken(
-                mAccount, AUTH_TOKEN_TYPE, new OAuth2TokenService.GetAccessTokenCallback() {
-                    @Override
-                    public void onGetTokenSuccess(String token) {
-                        if (mUiControllerAndroid != 0) {
-                            nativeOnAccessToken(mUiControllerAndroid, true, token);
-                        }
-                    }
-
-                    @Override
-                    public void onGetTokenFailure(boolean isTransientError) {
-                        if (!isTransientError && mUiControllerAndroid != 0) {
-                            nativeOnAccessToken(mUiControllerAndroid, false, "");
-                        }
-                    }
-                });
-    }
-
-    @CalledByNative
-    private void invalidateAccessToken(String accessToken) {
-        if (mAccount == null) {
-            return;
-        }
-
-        OAuth2TokenService.invalidateAccessToken(accessToken);
-    }
-
     @CalledByNative
     private void expandBottomSheet() {
         mUiDelegateHolder.performUiOperation(AutofillAssistantUiDelegate::expandBottomSheet);
     }
 
-    /** Choose an account to authenticate as for making RPCs to the backend. */
-    private void chooseAccountAsync(@Nullable String accountFromParameter, Bundle extras) {
-        AccountManagerFacade.get().tryGetGoogleAccounts(accounts -> {
-            if (mUiControllerAndroid == 0) return;
-            if (accounts.size() == 1) {
-                // If there's only one account, there aren't any doubts.
-                onAccountChosen(accounts.get(0));
-                return;
-            }
-            Account signedIn =
-                    findAccountByName(accounts, nativeGetPrimaryAccountName(mUiControllerAndroid));
-            if (signedIn != null) {
-                // TODO(crbug.com/806868): Compare against account name from extras and complain if
-                // they don't match.
-                onAccountChosen(signedIn);
-                return;
-            }
-
-            if (accountFromParameter != null) {
-                Account account = findAccountByName(accounts, accountFromParameter);
-                if (account != null) {
-                    onAccountChosen(account);
-                    return;
-                }
-            }
-
-            for (String extra : extras.keySet()) {
-                // TODO(crbug.com/806868): Deprecate ACCOUNT_NAME.
-                if (extra.endsWith("ACCOUNT_NAME")) {
-                    Account account = findAccountByName(accounts, extras.getString(extra));
-                    if (account != null) {
-                        onAccountChosen(account);
-                        return;
-                    }
-                }
-            }
-            onAccountChosen(null);
-        });
-    }
-
-    private void onAccountChosen(@Nullable Account account) {
-        mAccount = account;
-        mAccountInitialized = true;
-        // TODO(crbug.com/806868): Consider providing a way of signing in this case, to enforce
-        // that all calls are authenticated.
-
-        if (mShouldFetchAccessToken) {
-            mShouldFetchAccessToken = false;
-            fetchAccessToken();
-        }
-    }
-
-    private static Account findAccountByName(List<Account> accounts, String name) {
-        for (int i = 0; i < accounts.size(); i++) {
-            Account account = accounts.get(i);
-            if (account.name.equals(name)) {
-                return account;
-            }
-        }
-        return null;
-    }
-
-    /** Returns the country that the device is currently located in. This currently only works
-     * for devices with active SIM cards. For a more general solution, we should probably use
-     * the LocationManager together with the Geocoder.*/
-    private String getCountryIso() {
-        TelephonyManager telephonyManager =
-                (TelephonyManager) ContextUtils.getApplicationContext().getSystemService(
-                        Context.TELEPHONY_SERVICE);
-
-        // According to API, location for CDMA networks is unreliable
-        if (telephonyManager != null
-                && telephonyManager.getPhoneType() != TelephonyManager.PHONE_TYPE_CDMA)
-            return telephonyManager.getNetworkCountryIso();
-        else
-            return null;
-    }
-
     // native methods.
-    private native long nativeInit(WebContents webContents, String[] parameterNames,
-            String[] parameterValues, String locale, String countryCode);
-    private native void nativeStart(long nativeUiControllerAndroid, String initialUrl);
-    private native void nativeDestroy(long nativeUiControllerAndroid);
+    private native void nativeStop(long nativeUiControllerAndroid);
     private native void nativeUpdateTouchableArea(long nativeUiControllerAndroid);
     private native void nativeOnUserInteractionInsideTouchableArea(long nativeUiControllerAndroid);
     private native void nativeOnScriptSelected(long nativeUiControllerAndroid, String scriptPath);
@@ -517,8 +363,5 @@
             @Nullable PersonalDataManager.AutofillProfile address, @Nullable String payerName,
             @Nullable String payerPhone, @Nullable String payerEmail,
             boolean isTermsAndConditionsAccepted);
-    private native void nativeOnAccessToken(
-            long nativeUiControllerAndroid, boolean success, String accessToken);
-    private native String nativeGetPrimaryAccountName(long nativeUiControllerAndroid);
     private native String nativeOnRequestDebugContext(long nativeUiControllerAndroid);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiDelegate.java
index 869f191..d75fa794 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiDelegate.java
@@ -52,6 +52,11 @@
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.snackbar.Snackbar;
 import org.chromium.chrome.browser.snackbar.SnackbarManager;
+import org.chromium.chrome.browser.tab.EmptyTabObserver;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver;
+import org.chromium.chrome.browser.tabmodel.TabModel;
+import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.payments.mojom.PaymentOptions;
 import org.chromium.ui.KeyboardVisibilityDelegate.KeyboardVisibilityListener;
@@ -253,13 +258,53 @@
         int BUTTON_HAIRLINE = 2;
     }
 
+    /** Starts the UI with the given controller. */
+    static UiDelegateHolder start(
+            ChromeActivity activity, AbstractAutofillAssistantUiController controller) {
+        UiDelegateHolder delegateHolder = new UiDelegateHolder(
+                new AutofillAssistantUiDelegate(activity, controller), controller);
+        initForCustomTab(activity, delegateHolder);
+        Details initialDetails = controller.getDetails();
+        if (!initialDetails.isEmpty()) {
+            delegateHolder.performUiOperation(
+                    (uiDelegate) -> uiDelegate.showDetails(initialDetails));
+        }
+        return delegateHolder;
+    }
+
+    private static void initForCustomTab(ChromeActivity activity, UiDelegateHolder delegateHolder) {
+        if (!(activity instanceof CustomTabActivity)) {
+            return;
+        }
+        Tab activityTab = activity.getActivityTab();
+        activityTab.addObserver(new EmptyTabObserver() {
+            @Override
+            public void onActivityAttachmentChanged(Tab tab, boolean isAttached) {
+                if (!isAttached) {
+                    activityTab.removeObserver(this);
+                    delegateHolder.shutdown();
+                }
+            }
+        });
+
+        // Shut down Autofill Assistant when the selected tab (foreground tab) is changed.
+        TabModel currentTabModel = activity.getTabModelSelector().getCurrentModel();
+        currentTabModel.addObserver(new EmptyTabModelObserver() {
+            @Override
+            public void didSelectTab(Tab tab, @TabSelectionType int type, int lastId) {
+                currentTabModel.removeObserver(this);
+                delegateHolder.giveUp();
+            }
+        });
+    }
+
     /**
      * Constructs an assistant UI delegate.
      *
      * @param activity The ChromeActivity
      * @param client The client to forward events to
      */
-    public AutofillAssistantUiDelegate(ChromeActivity activity, Client client) {
+    private AutofillAssistantUiDelegate(ChromeActivity activity, Client client) {
         mActivity = activity;
         mClient = client;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunSignInProcessor.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunSignInProcessor.java
index 52c9577..2e6ace34 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunSignInProcessor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunSignInProcessor.java
@@ -6,6 +6,7 @@
 
 import android.app.Activity;
 import android.app.Fragment;
+import android.os.Bundle;
 import android.text.TextUtils;
 
 import org.chromium.base.ContextUtils;
@@ -99,12 +100,15 @@
      */
     private static void openSignInSettings(Activity activity) {
         final Class<? extends Fragment> fragment;
+        final Bundle arguments;
         if (ChromeFeatureList.isEnabled(ChromeFeatureList.UNIFIED_CONSENT)) {
             fragment = SyncAndServicesPreferences.class;
+            arguments = SyncAndServicesPreferences.createArguments(true);
         } else {
             fragment = AccountManagementFragment.class;
+            arguments = null;
         }
-        PreferencesLauncher.launchSettingsPage(activity, fragment);
+        PreferencesLauncher.launchSettingsPage(activity, fragment, arguments);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/AutoFetchNotifier.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/AutoFetchNotifier.java
new file mode 100644
index 0000000..547c629ee
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/AutoFetchNotifier.java
@@ -0,0 +1,119 @@
+// 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.offlinepages;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.provider.Browser;
+import android.support.v4.app.NotificationCompat;
+
+import org.chromium.base.ContextUtils;
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.IntentHandler;
+import org.chromium.chrome.browser.IntentHandler.TabOpenType;
+import org.chromium.chrome.browser.notifications.ChromeNotificationBuilder;
+import org.chromium.chrome.browser.notifications.NotificationBuilderFactory;
+import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions;
+import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
+import org.chromium.chrome.browser.util.IntentUtils;
+import org.chromium.components.offline_items_collection.LaunchLocation;
+import org.chromium.content_public.browser.LoadUrlParams;
+
+/**
+ * Implements notifications when pages are automatically fetched after reaching the net-error page.
+ */
+@JNINamespace("offline_pages")
+public class AutoFetchNotifier {
+    private static final String NOTIFICATION_TAG = "OfflinePageAutoFetchNotification";
+    private static final String EXTRA_URL = "org.chromium.chrome.browser.offlinepages.URL";
+
+    /**
+     * Opens the offline page when the notification is tapped.
+     */
+    public static class ClickReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(final Context context, Intent intent) {
+            // TODO(crbug.com/883486): Record UMA.
+
+            // Create a new intent that will be handled by |ChromeTabbedActivity| to open the page.
+            // This |BroadcastReceiver| is only required for collecting UMA.
+            Intent viewIntent = new Intent(Intent.ACTION_VIEW,
+                    Uri.parse(IntentUtils.safeGetStringExtra(intent, EXTRA_URL)));
+            viewIntent.putExtras(intent);
+            viewIntent.setPackage(context.getPackageName());
+            viewIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            IntentHandler.startActivityForTrustedIntent(viewIntent);
+        }
+    }
+
+    /**
+     * Creates a system notification that informs the user when an auto-fetched page is ready.
+     * If the notification is tapped, it opens the offline page in Chrome.
+     *
+     * @param pageTitle     The title of the page. This is displayed on the notification.
+     * @param originalUrl   The originally requested URL (before any redirection).
+     * @param tabId         ID of the tab where the auto-fetch occurred. This tab is used, if
+     *                      available, to open the offline page when the notification is tapped.
+     * @param offlineId     The offlineID for the offline page that was just saved.
+     */
+    @CalledByNative
+    public static void showCompleteNotification(
+            String pageTitle, String originalUrl, int tabId, long offlineId) {
+        Context context = ContextUtils.getApplicationContext();
+        OfflinePageUtils.getLoadUrlParamsForOpeningOfflineVersion(
+                originalUrl, offlineId, LaunchLocation.NOTIFICATION, (params) -> {
+                    showCompleteNotificationWithParams(
+                            pageTitle, tabId, offlineId, originalUrl, params);
+                });
+    }
+
+    private static void showCompleteNotificationWithParams(
+            String pageTitle, int tabId, long offlineId, String originalUrl, LoadUrlParams params) {
+        Context context = ContextUtils.getApplicationContext();
+        // Create an intent to be handled by ClickReceiver.
+        Intent intent = new Intent(context, ClickReceiver.class);
+        intent.putExtra(EXTRA_URL, originalUrl);
+        IntentHandler.setIntentExtraHeaders(params.getExtraHeaders(), intent);
+        intent.putExtra(TabOpenType.REUSE_TAB_MATCHING_ID_STRING, tabId);
+        intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
+        IntentHandler.setTabLaunchType(intent, TabLaunchType.FROM_CHROME_UI);
+
+        intent.setPackage(context.getPackageName());
+
+        PendingIntent clickIntent = PendingIntent.getBroadcast(
+                context, (int) offlineId /* requestCode */, intent, 0 /* flags */);
+
+        // Create the notification.
+        ChromeNotificationBuilder builder =
+                NotificationBuilderFactory
+                        .createChromeNotificationBuilder(
+                                true /* preferCompat */, ChannelDefinitions.ChannelId.DOWNLOADS)
+                        .setAutoCancel(true)
+                        .setContentIntent(clickIntent)
+                        .setContentTitle(pageTitle)
+                        .setContentText(context.getString(
+                                R.string.offline_pages_auto_fetch_ready_notification_text))
+                        .setGroup(NOTIFICATION_TAG)
+                        .setPriorityBeforeO(NotificationCompat.PRIORITY_LOW)
+                        .setSmallIcon(R.drawable.ic_chrome);
+
+        Notification notification = builder.build();
+        // Use the offline ID for a unique notification ID. Offline ID is a random
+        // 64-bit integer. Truncating to 32 bits isn't ideal, but chances of collision
+        // is still very low, and users should have few of these notifications
+        // anyway.
+        int notificationId = (int) offlineId;
+        NotificationManager manager =
+                (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+        manager.notify(NOTIFICATION_TAG, notificationId, notification);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/downloads/OfflinePageDownloadBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/downloads/OfflinePageDownloadBridge.java
index f6d7cd98..5a7c483 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/downloads/OfflinePageDownloadBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/downloads/OfflinePageDownloadBridge.java
@@ -9,7 +9,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
-import android.os.Bundle;
 import android.provider.Browser;
 import android.support.customtabs.CustomTabsIntent;
 
@@ -43,8 +42,6 @@
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.ui.widget.Toast;
 
-import java.util.Map;
-
 /**
  * Serves as an interface between Download Home UI and offline page related items that are to be
  * displayed in the downloads UI.
@@ -114,7 +111,7 @@
         Activity activity = ApplicationStatus.getLastTrackedFocusedActivity();
         if (activity == null) return;
         Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(params.getUrl()));
-        setIntentHeaders(params, intent);
+        IntentHandler.setIntentExtraHeaders(params.getExtraHeaders(), intent);
         intent.putExtra(
                 Browser.EXTRA_APPLICATION_ID, activity.getApplicationContext().getPackageName());
         intent.setPackage(activity.getApplicationContext().getPackageName());
@@ -135,14 +132,6 @@
         tabDelegate.createNewTab(asyncParams, TabLaunchType.FROM_CHROME_UI, Tab.INVALID_TAB_ID);
     }
 
-    private static void setIntentHeaders(LoadUrlParams params, Intent intent) {
-        Bundle bundle = new Bundle();
-        for (Map.Entry<String, String> entry : params.getExtraHeaders().entrySet()) {
-            bundle.putString(entry.getKey(), entry.getValue());
-        }
-        intent.putExtra(Browser.EXTRA_HEADERS, bundle);
-    }
-
     /**
      * Opens the offline page identified by the given offlineId and the LoadUrlParams in a CCT.
      */
@@ -170,8 +159,7 @@
 
         IntentHandler.addTrustedIntentExtras(intent);
         if (!(context instanceof Activity)) intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-        setIntentHeaders(params, intent);
+        IntentHandler.setIntentExtraHeaders(params.getExtraHeaders(), intent);
 
         context.startActivity(intent);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ContextualSuggestionsPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ContextualSuggestionsPreference.java
index 55b9ed3..a7c5e78 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ContextualSuggestionsPreference.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ContextualSuggestionsPreference.java
@@ -93,8 +93,9 @@
             final NoUnderlineClickableSpan span = new NoUnderlineClickableSpan((widget) -> {
                 if (isUnifiedConsentEnabled) {
                     if (isSignedIn) {
-                        PreferencesLauncher.launchSettingsPage(
-                                context, SyncAndServicesPreferences.class);
+                        PreferencesLauncher.launchSettingsPage(context,
+                                SyncAndServicesPreferences.class,
+                                SyncAndServicesPreferences.createArguments(false));
                     } else {
                         startActivity(SigninActivity.createIntentForPromoChooseAccountFlow(
                                 context, SigninAccessPoint.SETTINGS, null));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncAndServicesPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncAndServicesPreferences.java
index d33fcf1..6ad1698 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncAndServicesPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncAndServicesPreferences.java
@@ -77,6 +77,9 @@
         implements PassphraseDialogFragment.Listener, PassphraseCreationDialogFragment.Listener,
                    PassphraseTypeDialogFragment.Listener, Preference.OnPreferenceChangeListener,
                    ProfileSyncService.SyncStateChangedListener {
+    private static final String IS_FROM_SIGNIN_SCREEN =
+            "SyncAndServicesPreferences.isFromSigninScreen";
+
     @VisibleForTesting
     public static final String FRAGMENT_ENTER_PASSPHRASE = "enter_password";
     @VisibleForTesting
@@ -136,6 +139,8 @@
     private final ManagedPreferenceDelegate mManagedPreferenceDelegate =
             createManagedPreferenceDelegate();
 
+    private boolean mIsFromSigninScreen;
+
     private SignInPreference mSigninPreference;
     private Preference mSyncErrorCard;
     private Preference mSyncErrorCardDivider;
@@ -177,10 +182,23 @@
     private boolean mIsSyncEnabled;
     private @SyncError int mCurrentSyncError = SyncError.NO_ERROR;
 
+    /**
+     * Creates an argument bundle for this fragment.
+     * @param isFromSigninScreen Whether the screen is started from the sign-in screen.
+     */
+    public static Bundle createArguments(boolean isFromSigninScreen) {
+        Bundle result = new Bundle();
+        result.putBoolean(IS_FROM_SIGNIN_SCREEN, isFromSigninScreen);
+        return result;
+    }
+
     @Override
     public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
+        mIsFromSigninScreen =
+                IntentUtils.safeGetBoolean(getArguments(), IS_FROM_SIGNIN_SCREEN, false);
+
         mPrivacyPrefManager.migrateNetworkPredictionPreferences();
 
         getActivity().setTitle(R.string.prefs_sync_and_services);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java
index afd33ce..7f2f6209 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java
@@ -82,8 +82,9 @@
 
             Preference syncAndServicesLink = findPreference(PREF_SYNC_AND_SERVICES_LINK);
             NoUnderlineClickableSpan linkSpan = new NoUnderlineClickableSpan(view -> {
-                PreferencesLauncher.launchSettingsPage(
-                        getActivity(), SyncAndServicesPreferences.class);
+                PreferencesLauncher.launchSettingsPage(getActivity(),
+                        SyncAndServicesPreferences.class,
+                        SyncAndServicesPreferences.createArguments(false));
             });
             syncAndServicesLink.setSummary(
                     SpanApplier.applySpans(getString(R.string.privacy_sync_and_services_link),
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFragment.java
index bf3728b8..c1742e9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFragment.java
@@ -136,8 +136,9 @@
             public void onSignInComplete() {
                 UnifiedConsentServiceBridge.setUnifiedConsentGiven(true);
                 if (settingsClicked) {
-                    PreferencesLauncher.launchSettingsPage(
-                            getActivity(), SyncAndServicesPreferences.class);
+                    PreferencesLauncher.launchSettingsPage(getActivity(),
+                            SyncAndServicesPreferences.class,
+                            SyncAndServicesPreferences.createArguments(true));
                 }
 
                 recordSigninCompletedHistogramAccountInfo();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/sync/OWNERS
index ddeedc5..68a2d2e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/OWNERS
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/OWNERS
@@ -1,4 +1,5 @@
-mastiz@chromium.org
+file://components/sync/OWNERS
+
 nyquist@chromium.org
 yfriedman@chromium.org
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncNotificationController.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncNotificationController.java
index ec69e9f..339d40b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncNotificationController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncNotificationController.java
@@ -9,6 +9,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.os.Bundle;
 import android.util.Log;
 
 import org.chromium.base.ContextUtils;
@@ -147,13 +148,16 @@
      */
     private Intent createSettingsIntent() {
         final String fragmentName;
+        final Bundle fragmentArguments;
         if (ChromeFeatureList.isEnabled(ChromeFeatureList.UNIFIED_CONSENT)) {
             fragmentName = SyncAndServicesPreferences.class.getName();
+            fragmentArguments = SyncAndServicesPreferences.createArguments(false);
         } else {
             fragmentName = AccountManagementFragment.class.getName();
+            fragmentArguments = null;
         }
         return PreferencesLauncher.createIntentForSettingsPage(
-                ContextUtils.getApplicationContext(), fragmentName);
+                ContextUtils.getApplicationContext(), fragmentName, fragmentArguments);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/TabDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/TabDelegate.java
index 0b9e482..45fad71 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/TabDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/TabDelegate.java
@@ -8,7 +8,6 @@
 import android.content.ComponentName;
 import android.content.Intent;
 import android.net.Uri;
-import android.os.Bundle;
 import android.provider.Browser;
 
 import org.chromium.base.ApiCompatibilityUtils;
@@ -28,8 +27,6 @@
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.ui.base.PageTransition;
 
-import java.util.Map;
-
 /**
  * Asynchronously creates Tabs by creating/starting up Activities.
  */
@@ -148,15 +145,8 @@
         } else {
             ChromeTabbedActivity.setNonAliasedComponent(intent, componentName);
         }
-
-        Map<String, String> extraHeaders = asyncParams.getLoadUrlParams().getExtraHeaders();
-        if (extraHeaders != null && !extraHeaders.isEmpty()) {
-            Bundle bundle = new Bundle();
-            for (Map.Entry<String, String> header : extraHeaders.entrySet()) {
-                bundle.putString(header.getKey(), header.getValue());
-            }
-            intent.putExtra(Browser.EXTRA_HEADERS, bundle);
-        }
+        IntentHandler.setIntentExtraHeaders(
+                asyncParams.getLoadUrlParams().getExtraHeaders(), intent);
 
         intent.putExtra(IntentHandler.EXTRA_TAB_ID, assignedTabId);
         intent.putExtra(IntentHandler.EXTRA_OPEN_NEW_INCOGNITO_TAB, mIsIncognito);
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 32f77fb..1469181c 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -3097,6 +3097,10 @@
         <ph name="DOMAIN_NAME"><ex>www.example.com</ex>%1$s</ph> and more sites
       </message>
 
+      <message name="IDS_OFFLINE_PAGES_AUTO_FETCH_READY_NOTIFICATION_TEXT" desc="Text inside a notification explaining that the page has been fetched and is ready to view. This is the subtext of the notification and appars below the web page title. When the notification is tapped, the page is opened in Chrome.">
+        Page is ready to view
+      </message>
+
       <!-- Offline indicator -->
       <message name="IDS_OFFLINE_INDICATOR_OFFLINE_TITLE" desc="Text to be displayed in the snackbar that lets the users know they are offline.">
         No connection
diff --git a/chrome/android/java/strings/android_chrome_strings_grd/IDS_OFFLINE_PAGES_AUTO_FETCH_READY_NOTIFICATION_TEXT.png.sha1 b/chrome/android/java/strings/android_chrome_strings_grd/IDS_OFFLINE_PAGES_AUTO_FETCH_READY_NOTIFICATION_TEXT.png.sha1
new file mode 100644
index 0000000..ff0a6aad
--- /dev/null
+++ b/chrome/android/java/strings/android_chrome_strings_grd/IDS_OFFLINE_PAGES_AUTO_FETCH_READY_NOTIFICATION_TEXT.png.sha1
@@ -0,0 +1 @@
+7ad81db40f419e571d8b7c8079556118fd840505
\ No newline at end of file
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 45fe4338..8be5258 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -133,6 +133,7 @@
   "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetModernViewBinder.java",
   "java/src/org/chromium/chrome/browser/autofill_assistant/AbstractAutofillAssistantUiController.java",
   "java/src/org/chromium/chrome/browser/autofill_assistant/AnimatedProgressBar.java",
+  "java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantClient.java",
   "java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java",
   "java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPaymentRequest.java",
   "java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPreferencesUtil.java",
@@ -1097,6 +1098,7 @@
   "java/src/org/chromium/chrome/browser/offlinepages/TaskExtrasPacker.java",
   "java/src/org/chromium/chrome/browser/offlinepages/TriggerConditions.java",
   "java/src/org/chromium/chrome/browser/offlinepages/downloads/OfflinePageDownloadBridge.java",
+  "java/src/org/chromium/chrome/browser/offlinepages/AutoFetchNotifier.java",
   "java/src/org/chromium/chrome/browser/offlinepages/indicator/ConnectivityDetector.java",
   "java/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorController.java",
   "java/src/org/chromium/chrome/browser/offlinepages/indicator/TopSnackbarManager.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java
index 1c2d997..f6b13700 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java
@@ -4,11 +4,10 @@
 
 package org.chromium.chrome.browser.autofill_assistant;
 
-import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.content.Intent;
 import android.support.test.InstrumentationRegistry;
@@ -30,6 +29,7 @@
 import org.mockito.junit.MockitoRule;
 import org.mockito.stubbing.Answer;
 
+import org.chromium.base.Callback;
 import org.chromium.base.PathUtils;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.library_loader.LibraryLoader;
@@ -48,11 +48,27 @@
 import java.util.Collections;
 import java.util.List;
 
+import javax.annotation.concurrent.GuardedBy;
+
 /**
  * Instrumentation tests for autofill assistant UI.
  */
 @RunWith(ChromeJUnit4ClassRunner.class)
 public class AutofillAssistantUiTest {
+    private static class TestCallback<T> implements Callback<T> {
+        @GuardedBy("this")
+        private T mResult;
+
+        synchronized T getResult() {
+            return mResult;
+        }
+
+        @Override
+        public synchronized void onResult(T result) {
+            mResult = result;
+        }
+    };
+
     private String mTestPage;
     private EmbeddedTestServer mTestServer;
 
@@ -61,8 +77,6 @@
     @Mock
     private AbstractAutofillAssistantUiController mControllerMock;
     @Captor
-    private ArgumentCaptor<UiDelegateHolder> mUiDelegateHolderCaptor;
-    @Captor
     private ArgumentCaptor<String> mLastSelectedScriptPathCaptor;
 
     @Rule
@@ -77,6 +91,7 @@
                 "components/test/data/autofill_assistant/autofill_assistant_target_website.html"));
         PathUtils.setPrivateDataDirectorySuffix("chrome");
         LibraryLoader.getInstance().ensureInitialized(LibraryProcessType.PROCESS_BROWSER);
+        when(mControllerMock.getDetails()).thenReturn(Details.EMPTY_DETAILS);
     }
 
     @After
@@ -101,34 +116,42 @@
         return mCustomTabActivityTestRule.getActivity();
     }
 
+    @Test
+    @MediumTest
+    public void testFirstTimeStartAccept() throws Exception {
+        mCustomTabActivityTestRule.startCustomTabActivityWithIntent(createMinimalCustomTabIntent());
+        // Start autofill assistant UI. The first run screen must be shown first since the
+        // preference hasn't been set.
+
+        TestCallback<Boolean> startCallback = new TestCallback<>();
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> AutofillAssistantFacade.startWithCallback(getActivity(), startCallback));
+        View firstRunScreen = findViewByIdInMainCoordinator(R.id.init_screen);
+        Assert.assertNotNull(firstRunScreen);
+        Assert.assertTrue(firstRunScreen.isShown());
+        Assert.assertNull(startCallback.getResult());
+
+        // Accept on the first run screen to continue.
+        View initOkButton = firstRunScreen.findViewById(R.id.button_init_ok);
+        ThreadUtils.runOnUiThreadBlocking(() -> { initOkButton.performClick(); });
+        Assert.assertEquals(Boolean.TRUE, startCallback.getResult());
+    }
+
     // TODO(crbug.com/806868): Add more UI details test and check, like payment request UI,
     // highlight chips and so on.
     @Test
     @MediumTest
-    public void testStartAndDismiss() throws InterruptedException {
+    public void testStartAndDismiss() throws Exception {
         mCustomTabActivityTestRule.startCustomTabActivityWithIntent(createMinimalCustomTabIntent());
 
-        // Start autofill assistant UI. The first run screen must be shown first since the
-        // preference hasn't been set.
-        ThreadUtils.runOnUiThreadBlocking(
-                () -> AutofillAssistantFacade.startInternal(getActivity(), mControllerMock));
-        View firstRunScreen = findViewByIdInMainCoordinator(R.id.init_screen);
-        Assert.assertNotNull(firstRunScreen);
-        Assert.assertTrue(firstRunScreen.isShown());
-        verify(mControllerMock, never()).init(any(), any());
-
-        // Accept on the first run screen so as to continue.
-        View initOkButton = firstRunScreen.findViewById(R.id.button_init_ok);
-        ThreadUtils.runOnUiThreadBlocking(() -> { initOkButton.performClick(); });
-        verify(mControllerMock, times(1))
-                .init(mUiDelegateHolderCaptor.capture(), any(Details.class));
-        Assert.assertNotNull(mUiDelegateHolderCaptor.getValue());
+        UiDelegateHolder uiDelegateHolder = ThreadUtils.runOnUiThreadBlocking(
+                () -> AutofillAssistantUiDelegate.start(getActivity(), mControllerMock));
 
         // Show and check status message.
         String testStatusMessage = "test message";
         ThreadUtils.runOnUiThreadBlocking(
                 ()
-                        -> mUiDelegateHolderCaptor.getValue().performUiOperation(
+                        -> uiDelegateHolder.performUiOperation(
                                 uiDelegate -> uiDelegate.showStatusMessage(testStatusMessage)));
         View bottomSheet = findViewByIdInMainCoordinator(R.id.autofill_assistant);
         Assert.assertTrue(bottomSheet.isShown());
@@ -136,11 +159,10 @@
         Assert.assertEquals(statusMessageView.getText(), testStatusMessage);
 
         // Show overlay.
-        ThreadUtils.runOnUiThreadBlocking(
-                () -> mUiDelegateHolderCaptor.getValue().performUiOperation(uiDelegate -> {
-                    uiDelegate.showOverlay();
-                    uiDelegate.disableProgressBarPulsing();
-                }));
+        ThreadUtils.runOnUiThreadBlocking(() -> uiDelegateHolder.performUiOperation(uiDelegate -> {
+            uiDelegate.showOverlay();
+            uiDelegate.disableProgressBarPulsing();
+        }));
         View overlay = bottomSheet.findViewById(R.id.touch_event_filter);
         Assert.assertTrue(overlay.isShown());
 
@@ -152,7 +174,7 @@
                 new AutofillAssistantUiDelegate.ScriptHandle("testScript2", false, "path2"));
         ThreadUtils.runOnUiThreadBlocking(
                 ()
-                        -> mUiDelegateHolderCaptor.getValue().performUiOperation(
+                        -> uiDelegateHolder.performUiOperation(
                                 uiDelegate -> uiDelegate.updateScripts(scriptHandles)));
         ViewGroup chipsViewContainer = (ViewGroup) bottomSheet.findViewById(R.id.carousel);
         Assert.assertEquals(2, chipsViewContainer.getChildCount());
@@ -168,7 +190,7 @@
         String movieDescription = "This is a fancy test movie";
         ThreadUtils.runOnUiThreadBlocking(
                 ()
-                        -> mUiDelegateHolderCaptor.getValue().performUiOperation(uiDelegate
+                        -> uiDelegateHolder.performUiOperation(uiDelegate
                                 -> uiDelegate.showDetails(new Details(movieTitle, /* url = */ "",
                                         Calendar.getInstance().getTime(), movieDescription,
                                         /* mId = */ "",
@@ -184,7 +206,7 @@
 
         // Click 'X' button to graceful shutdown.
         doAnswer((Answer<Void>) invocation -> {
-            mUiDelegateHolderCaptor.getValue().dismiss(R.string.autofill_assistant_stopped);
+            uiDelegateHolder.dismiss(R.string.autofill_assistant_stopped);
             return null;
         })
                 .when(mControllerMock)
@@ -193,4 +215,4 @@
                 () -> { bottomSheet.findViewById(R.id.close_button).performClick(); });
         Assert.assertFalse(bottomSheet.isShown());
     }
-}
\ No newline at end of file
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/OWNERS b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/OWNERS
index 4564d014..ed16e83 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/OWNERS
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/OWNERS
@@ -1,7 +1,3 @@
-mastiz@chromium.org
-nyquist@chromium.org
-yfriedman@chromium.org
-
-file://components/sync/OWNERS
+file://chrome/android/java/src/org/chromium/chrome/browser/sync/OWNERS
 
 # COMPONENT: Services>Sync
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 11fbef5e..7f0aaac 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -1441,6 +1441,10 @@
                  desc="The title of a download notification: the current download status is finished successufully.">
                  Download complete
         </message>
+        <message name="IDS_DOWNLOAD_STATUS_PAGE_READY_TITLE"
+                 desc="The title of a download notification for offline pages not stored in Downloads.">
+                 Page is ready to view
+        </message>
         <message name="IDS_DOWNLOAD_NOTIFICATION_STATUS_COMPLETED"
                  desc="Size and units downloaded, and the origin domain.">
           <ph name="DOWNLOAD_RECEIVED">$1<ex>154 MB</ex></ph> from <ph name="DOWNLOAD_DOMAIN">$2<ex>example.com</ex></ph>
diff --git a/chrome/app/generated_resources_grd/IDS_DOWNLOAD_STATUS_PAGE_READY_TITLE.png.sha1 b/chrome/app/generated_resources_grd/IDS_DOWNLOAD_STATUS_PAGE_READY_TITLE.png.sha1
new file mode 100644
index 0000000..ff0a6aad
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_DOWNLOAD_STATUS_PAGE_READY_TITLE.png.sha1
@@ -0,0 +1 @@
+7ad81db40f419e571d8b7c8079556118fd840505
\ No newline at end of file
diff --git a/chrome/app/theme/default_100_percent/chromium/calculator_round_24.png b/chrome/app/theme/default_100_percent/common/calculator_round_24.png
similarity index 100%
rename from chrome/app/theme/default_100_percent/chromium/calculator_round_24.png
rename to chrome/app/theme/default_100_percent/common/calculator_round_24.png
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/extension_command_close.png b/chrome/app/theme/default_100_percent/common/extension_command_close.png
deleted file mode 100644
index 1bdebff..0000000
--- a/chrome/app/theme/default_100_percent/common/extension_command_close.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/favicon_print_preview.png b/chrome/app/theme/default_100_percent/common/favicon_print_preview.png
deleted file mode 100644
index 48ebb94..0000000
--- a/chrome/app/theme/default_100_percent/common/favicon_print_preview.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/infobar_3d_blocked.png b/chrome/app/theme/default_100_percent/common/infobar_3d_blocked.png
deleted file mode 100644
index d7f4ea2f..0000000
--- a/chrome/app/theme/default_100_percent/common/infobar_3d_blocked.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/chromium/translate_round_32.png b/chrome/app/theme/default_100_percent/common/translate_round_32.png
similarity index 100%
rename from chrome/app/theme/default_100_percent/chromium/translate_round_32.png
rename to chrome/app/theme/default_100_percent/common/translate_round_32.png
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/cros/bluetooth_pairing_keyboard.png b/chrome/app/theme/default_100_percent/cros/bluetooth_pairing_keyboard.png
deleted file mode 100644
index f1daa26..0000000
--- a/chrome/app/theme/default_100_percent/cros/bluetooth_pairing_keyboard.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/cros/bluetooth_pairing_mouse.png b/chrome/app/theme/default_100_percent/cros/bluetooth_pairing_mouse.png
deleted file mode 100644
index 9b2cb0f..0000000
--- a/chrome/app/theme/default_100_percent/cros/bluetooth_pairing_mouse.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/cros/discard_wide.png b/chrome/app/theme/default_100_percent/cros/discard_wide.png
deleted file mode 100644
index e3a6903..0000000
--- a/chrome/app/theme/default_100_percent/cros/discard_wide.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/cros/hide_password.png b/chrome/app/theme/default_100_percent/cros/hide_password.png
deleted file mode 100644
index c415b5e..0000000
--- a/chrome/app/theme/default_100_percent/cros/hide_password.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/cros/kiosk_app_user_pod_icon.png b/chrome/app/theme/default_100_percent/cros/kiosk_app_user_pod_icon.png
deleted file mode 100644
index 2b62f70..0000000
--- a/chrome/app/theme/default_100_percent/cros/kiosk_app_user_pod_icon.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/cros/login_password_capslock.png b/chrome/app/theme/default_100_percent/cros/login_password_capslock.png
deleted file mode 100644
index 915f621..0000000
--- a/chrome/app/theme/default_100_percent/cros/login_password_capslock.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/cros/network_add_connection.png b/chrome/app/theme/default_100_percent/cros/network_add_connection.png
deleted file mode 100644
index 5d3dc628..0000000
--- a/chrome/app/theme/default_100_percent/cros/network_add_connection.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/cros/show_password.png b/chrome/app/theme/default_100_percent/cros/show_password.png
deleted file mode 100644
index 068ed16..0000000
--- a/chrome/app/theme/default_100_percent/cros/show_password.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/cros/snapshot_wide.png b/chrome/app/theme/default_100_percent/cros/snapshot_wide.png
deleted file mode 100644
index 48ed488d..0000000
--- a/chrome/app/theme/default_100_percent/cros/snapshot_wide.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/legacy/tab_recording_indicator.png b/chrome/app/theme/default_100_percent/cros/tab_recording_indicator.png
similarity index 100%
rename from chrome/app/theme/default_100_percent/legacy/tab_recording_indicator.png
rename to chrome/app/theme/default_100_percent/cros/tab_recording_indicator.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/chromium/calculator_round_24.png b/chrome/app/theme/default_200_percent/common/calculator_round_24.png
similarity index 100%
rename from chrome/app/theme/default_200_percent/chromium/calculator_round_24.png
rename to chrome/app/theme/default_200_percent/common/calculator_round_24.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/extension_command_close.png b/chrome/app/theme/default_200_percent/common/extension_command_close.png
deleted file mode 100644
index f99a99dd..0000000
--- a/chrome/app/theme/default_200_percent/common/extension_command_close.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/favicon_print_preview.png b/chrome/app/theme/default_200_percent/common/favicon_print_preview.png
deleted file mode 100644
index f99c7c9..0000000
--- a/chrome/app/theme/default_200_percent/common/favicon_print_preview.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/infobar_3d_blocked.png b/chrome/app/theme/default_200_percent/common/infobar_3d_blocked.png
deleted file mode 100644
index f74a6b8..0000000
--- a/chrome/app/theme/default_200_percent/common/infobar_3d_blocked.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/chromium/translate_round_32.png b/chrome/app/theme/default_200_percent/common/translate_round_32.png
similarity index 100%
rename from chrome/app/theme/default_200_percent/chromium/translate_round_32.png
rename to chrome/app/theme/default_200_percent/common/translate_round_32.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/cros/bluetooth_pairing_keyboard.png b/chrome/app/theme/default_200_percent/cros/bluetooth_pairing_keyboard.png
deleted file mode 100644
index 7c92424..0000000
--- a/chrome/app/theme/default_200_percent/cros/bluetooth_pairing_keyboard.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/cros/bluetooth_pairing_mouse.png b/chrome/app/theme/default_200_percent/cros/bluetooth_pairing_mouse.png
deleted file mode 100644
index 1b74cb4..0000000
--- a/chrome/app/theme/default_200_percent/cros/bluetooth_pairing_mouse.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/cros/discard_wide.png b/chrome/app/theme/default_200_percent/cros/discard_wide.png
deleted file mode 100644
index 379a1c9..0000000
--- a/chrome/app/theme/default_200_percent/cros/discard_wide.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/cros/hide_password.png b/chrome/app/theme/default_200_percent/cros/hide_password.png
deleted file mode 100644
index 22db4d6..0000000
--- a/chrome/app/theme/default_200_percent/cros/hide_password.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/cros/kiosk_app_user_pod_icon.png b/chrome/app/theme/default_200_percent/cros/kiosk_app_user_pod_icon.png
deleted file mode 100644
index 0879239..0000000
--- a/chrome/app/theme/default_200_percent/cros/kiosk_app_user_pod_icon.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/cros/login_password_capslock.png b/chrome/app/theme/default_200_percent/cros/login_password_capslock.png
deleted file mode 100644
index fc2f3845..0000000
--- a/chrome/app/theme/default_200_percent/cros/login_password_capslock.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/cros/network_add_connection.png b/chrome/app/theme/default_200_percent/cros/network_add_connection.png
deleted file mode 100644
index 27ef85c..0000000
--- a/chrome/app/theme/default_200_percent/cros/network_add_connection.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/cros/show_password.png b/chrome/app/theme/default_200_percent/cros/show_password.png
deleted file mode 100644
index 4422ebe..0000000
--- a/chrome/app/theme/default_200_percent/cros/show_password.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/cros/snapshot_wide.png b/chrome/app/theme/default_200_percent/cros/snapshot_wide.png
deleted file mode 100644
index 4e1898c..0000000
--- a/chrome/app/theme/default_200_percent/cros/snapshot_wide.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/legacy/tab_recording_indicator.png b/chrome/app/theme/default_200_percent/cros/tab_recording_indicator.png
similarity index 100%
rename from chrome/app/theme/default_200_percent/legacy/tab_recording_indicator.png
rename to chrome/app/theme/default_200_percent/cros/tab_recording_indicator.png
Binary files differ
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd
index 872f38af..fbbdbfe71 100644
--- a/chrome/app/theme/theme_resources.grd
+++ b/chrome/app/theme/theme_resources.grd
@@ -58,8 +58,6 @@
         <structure type="chrome_scaled_image" name="IDR_BACK_P" file="common/browser_back_pressed.png" />
       </if>
       <if expr="chromeos">
-        <structure type="chrome_scaled_image" name="IDR_BLUETOOTH_KEYBOARD" file="cros/bluetooth_pairing_keyboard.png" />
-        <structure type="chrome_scaled_image" name="IDR_BLUETOOTH_MOUSE" file="cros/bluetooth_pairing_mouse.png" />
         <structure type="chrome_scaled_image" name="IDR_BLUETOOTH_PAIRING_TICK" file="cros/bluetooth_pairing_tick.png" />
       </if>
       <structure type="chrome_scaled_image" name="IDR_BOOKMARKS_FAVICON" file="common/favicon_bookmarks.png" />
@@ -111,7 +109,6 @@
         <structure type="chrome_scaled_image" name="IDR_EXTENSIONS_RATING_STAR_HALF_RIGHT" file="common/extensions_rating_star_half_right.png" />
         <structure type="chrome_scaled_image" name="IDR_EXTENSIONS_RATING_STAR_OFF" file="common/extensions_rating_star_off.png" />
         <structure type="chrome_scaled_image" name="IDR_EXTENSIONS_RATING_STAR_ON" file="common/extensions_rating_star_on.png" />
-        <structure type="chrome_scaled_image" name="IDR_EXTENSION_COMMAND_CLOSE" file="common/extension_command_close.png" />
       </if>
       <if expr="chromeos">
         <structure type="chrome_scaled_image" name="IDR_FATAL_ERROR" file="cros/fatal_error.png" />
@@ -146,9 +143,6 @@
         <structure type="chrome_scaled_image" name="IDR_GOOGLE_ICON" file="google_chrome/google_icon.png" />
       </if>
       <structure type="chrome_scaled_image" name="IDR_HELP_MENU" file="common/help_16.png" />
-      <if expr="chromeos">
-        <structure type="chrome_scaled_image" name="IDR_HIDE_PASSWORD" file="cros/hide_password.png" />
-      </if>
       <structure type="chrome_scaled_image" name="IDR_HIDE_PASSWORD_HOVER" file="common/hide_password_hover.png" />
       <if expr="not is_android and not chromeos">
         <!-- User Manager tutorial -->
@@ -157,25 +151,17 @@
         <structure type="chrome_scaled_image" name="IDR_ICON_USER_MANAGER_TUTORIAL_FRIENDS" file="common/user_manager_tutorial/family_and_friends.png" />
         <structure type="chrome_scaled_image" name="IDR_ICON_USER_MANAGER_TUTORIAL_COMPLETE" file="common/user_manager_tutorial/complete.png" />
       </if>
-      <structure type="chrome_scaled_image" name="IDR_INFOBAR_3D_BLOCKED" file="common/infobar_3d_blocked.png" />
       <structure type="chrome_scaled_image" name="IDR_INPUT_ALERT" file="common/input_alert.png" />
       <structure type="chrome_scaled_image" name="IDR_INPUT_ALERT_MENU" file="common/input_alert_menu.png" />
       <if expr="enable_service_discovery">
         <structure type="chrome_scaled_image" name="IDR_LOCAL_DISCOVERY_CLOUDPRINT_ICON" file="common/cloudprint.png" />
       </if>
-      <if expr="chromeos">
-        <structure type="chrome_scaled_image" name="IDR_KIOSK_APP_USER_POD_ICON" file="cros/kiosk_app_user_pod_icon.png" />
-        <structure type="chrome_scaled_image" name="IDR_LOGIN_PASSWORD_CAPS_LOCK" file="cros/login_password_capslock.png" />
-      </if>
       <structure type="chrome_scaled_image" name="IDR_SUPERVISED_USER_THEME_FRAME" file="common/supervised_user_theme/theme_frame_supervised.png" />
       <structure type="chrome_scaled_image" name="IDR_SUPERVISED_USER_THEME_FRAME_INACTIVE" file="common/supervised_user_theme/theme_frame_supervised_inactive.png" />
       <structure type="chrome_scaled_image" name="IDR_SUPERVISED_USER_THEME_TAB_BACKGROUND" file="common/supervised_user_theme/theme_tab_background_supervised.png" />
       <structure type="chrome_scaled_image" name="IDR_MAXIMIZE_BUTTON_MASK" file="common/maximize_button_mask.png" />
       <structure type="chrome_scaled_image" name="IDR_MINIMIZE_BUTTON_MASK" file="common/minimize_button_mask.png" />
       <if expr="chromeos">
-        <structure type="chrome_scaled_image" name="IDR_NETWORK_ADD_CONNECTION" file="cros/network_add_connection.png" />
-      </if>
-      <if expr="chromeos">
         <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_DRIVE" file="cros/notification_drive.png" />
         <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_FINGERPRINT" file="cros/notification_fingerprint.png" />
         <structure type="chrome_scaled_image" name="IDR_ARC_PLAY_STORE_OPTIN_IN_PROGRESS_NOTIFICATION" file="cros/notification_play_store_optin_in_progress.png" />
@@ -184,8 +170,8 @@
         <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_EASYUNLOCK_ENABLED" file="cros/notification_easyunlock_enabled.png" />
       </if>
       <if expr="not is_android">
-        <structure type="chrome_scaled_image" name="IDR_OMNIBOX_CALCULATOR_ROUND" file="chromium/calculator_round_24.png" />
-        <structure type="chrome_scaled_image" name="IDR_OMNIBOX_TRANSLATION_ROUND" file="chromium/translate_round_32.png" />
+        <structure type="chrome_scaled_image" name="IDR_OMNIBOX_CALCULATOR_ROUND" file="common/calculator_round_24.png" />
+        <structure type="chrome_scaled_image" name="IDR_OMNIBOX_TRANSLATION_ROUND" file="common/translate_round_32.png" />
       </if>
       <structure type="chrome_scaled_image" name="IDR_PLUGINS_FAVICON" file="common/favicon_extensions.png" />
       <structure type="chrome_scaled_image" name="IDR_PRERENDER" file="common/prerender_succeed_icon.png" />
@@ -250,9 +236,6 @@
         <structure type="chrome_scaled_image" name="IDR_SECONDARY_USER_SETTINGS" file="cros/secondary_user_settings.png" />
       </if>
       <structure type="chrome_scaled_image" name="IDR_SETTINGS_FAVICON" file="common/favicon_settings.png" />
-      <if expr="chromeos">
-        <structure type="chrome_scaled_image" name="IDR_SHOW_PASSWORD" file="cros/show_password.png" />
-      </if>
       <structure type="chrome_scaled_image" name="IDR_SHOW_PASSWORD_HOVER" file="common/show_password_hover.png" />
       <if expr="chromeos">
         <structure type="chrome_scaled_image" name="IDR_SMB_ICON" file="cros/smb_icon.png" />
@@ -273,7 +256,7 @@
       <structure type="chrome_scaled_image" name="IDR_CLOSE_1_P" file="common/close_1_pressed.png" />
       <!-- Used by Chrome OS login page. -->
       <if expr="chromeos">
-        <structure type="chrome_scaled_image" name="IDR_TAB_RECORDING_INDICATOR" file="legacy/tab_recording_indicator.png" />
+        <structure type="chrome_scaled_image" name="IDR_TAB_RECORDING_INDICATOR" file="cros/tab_recording_indicator.png" />
 
       </if>
       <structure type="chrome_scaled_image" name="IDR_TAB_DROP_DOWN" file="tab_drop_down.png" />
@@ -315,10 +298,6 @@
       <!-- Instant Extended API toolbar background is common for all platforms. -->
       <structure type="chrome_scaled_image" name="IDR_THEME_WINDOW_CONTROL_BACKGROUND" file="notused.png" />
       <structure type="chrome_scaled_image" name="IDR_TRANSLATE_BUBBLE_ICON" file="common/translate_bubble_icon.png" />
-      <if expr="chromeos">
-        <structure type="chrome_scaled_image" name="IDR_USER_IMAGE_CAPTURE" file="cros/snapshot_wide.png" />
-        <structure type="chrome_scaled_image" name="IDR_USER_IMAGE_RECYCLE" file="cros/discard_wide.png" />
-      </if>
       <if expr="not _google_chrome">
         <structure type="chrome_scaled_image" name="IDR_WEBSTORE_ICON" file="chromium/webstore_icon.png" />
         <structure type="chrome_scaled_image" name="IDR_WEBSTORE_ICON_16" file="chromium/webstore_icon_16.png" />
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index c05350d5..34b9805 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2007,6 +2007,8 @@
       "android/android_theme_resources.h",
       "android/app_hooks.cc",
       "android/app_hooks.h",
+      "android/autofill_assistant/client_android.cc",
+      "android/autofill_assistant/client_android.h",
       "android/autofill_assistant/ui_controller_android.cc",
       "android/autofill_assistant/ui_controller_android.h",
       "android/background_sync_launcher_android.cc",
@@ -4164,8 +4166,6 @@
 
   if (enable_offline_pages) {
     sources += [
-      "offline_pages/auto_fetch_page_load_watcher.cc",
-      "offline_pages/auto_fetch_page_load_watcher.h",
       "offline_pages/background_loader_offliner.cc",
       "offline_pages/background_loader_offliner.h",
       "offline_pages/download_archive_manager.cc",
@@ -4174,12 +4174,6 @@
       "offline_pages/downloads/resource_throttle.h",
       "offline_pages/fresh_offline_content_observer.cc",
       "offline_pages/fresh_offline_content_observer.h",
-      "offline_pages/offline_page_auto_fetcher.cc",
-      "offline_pages/offline_page_auto_fetcher.h",
-      "offline_pages/offline_page_auto_fetcher_service.cc",
-      "offline_pages/offline_page_auto_fetcher_service.h",
-      "offline_pages/offline_page_auto_fetcher_service_factory.cc",
-      "offline_pages/offline_page_auto_fetcher_service_factory.h",
       "offline_pages/offline_page_bookmark_observer.cc",
       "offline_pages/offline_page_bookmark_observer.h",
       "offline_pages/offline_page_info_handler.cc",
@@ -4230,6 +4224,10 @@
     ]
     if (is_android) {
       sources += [
+        "offline_pages/android/auto_fetch_notifier.cc",
+        "offline_pages/android/auto_fetch_notifier.h",
+        "offline_pages/android/auto_fetch_page_load_watcher.cc",
+        "offline_pages/android/auto_fetch_page_load_watcher.h",
         "offline_pages/android/background_scheduler_bridge.cc",
         "offline_pages/android/background_scheduler_bridge.h",
         "offline_pages/android/cct_origin_observer.cc",
@@ -4244,6 +4242,12 @@
         "offline_pages/android/downloads/offline_page_share_helper.h",
         "offline_pages/android/load_termination_listener_impl.cc",
         "offline_pages/android/load_termination_listener_impl.h",
+        "offline_pages/android/offline_page_auto_fetcher.cc",
+        "offline_pages/android/offline_page_auto_fetcher.h",
+        "offline_pages/android/offline_page_auto_fetcher_service.cc",
+        "offline_pages/android/offline_page_auto_fetcher_service.h",
+        "offline_pages/android/offline_page_auto_fetcher_service_factory.cc",
+        "offline_pages/android/offline_page_auto_fetcher_service_factory.h",
         "offline_pages/android/offline_page_bridge.cc",
         "offline_pages/android/offline_page_bridge.h",
         "offline_pages/android/offline_page_model_factory.cc",
@@ -4711,6 +4715,7 @@
       "../android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java",
       "../android/java/src/org/chromium/chrome/browser/autofill/PhoneNumberUtil.java",
       "../android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingBridge.java",
+      "../android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantClient.java",
       "../android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java",
       "../android/java/src/org/chromium/chrome/browser/banners/AppBannerManager.java",
       "../android/java/src/org/chromium/chrome/browser/banners/AppBannerUiDelegateAndroid.java",
@@ -4841,6 +4846,7 @@
       "../android/java/src/org/chromium/chrome/browser/ntp/RecentlyClosedBridge.java",
       "../android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java",
       "../android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsLauncher.java",
+      "../android/java/src/org/chromium/chrome/browser/offlinepages/AutoFetchNotifier.java",
       "../android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerBridge.java",
       "../android/java/src/org/chromium/chrome/browser/offlinepages/CCTRequestStatus.java",
       "../android/java/src/org/chromium/chrome/browser/offlinepages/CctOfflinePageModelObserver.java",
diff --git a/chrome/browser/android/autofill_assistant/client_android.cc b/chrome/browser/android/autofill_assistant/client_android.cc
new file mode 100644
index 0000000..b183bf6
--- /dev/null
+++ b/chrome/browser/android/autofill_assistant/client_android.cc
@@ -0,0 +1,228 @@
+// 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 "chrome/browser/android/autofill_assistant/client_android.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_array.h"
+#include "base/android/jni_string.h"
+#include "base/android/locale_utils.h"
+#include "base/command_line.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/task/post_task.h"
+#include "chrome/browser/android/chrome_feature_list.h"
+#include "chrome/browser/autofill/android/personal_data_manager_android.h"
+#include "chrome/browser/autofill/personal_data_manager_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
+#include "chrome/common/channel_info.h"
+#include "components/autofill_assistant/browser/access_token_fetcher.h"
+#include "components/autofill_assistant/browser/controller.h"
+#include "components/signin/core/browser/account_info.h"
+#include "components/version_info/channel.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/web_contents.h"
+#include "google_apis/google_api_keys.h"
+#include "jni/AutofillAssistantClient_jni.h"
+#include "services/identity/public/cpp/identity_manager.h"
+#include "url/gurl.h"
+
+using base::android::AttachCurrentThread;
+using base::android::JavaParamRef;
+using base::android::JavaRef;
+
+namespace autofill_assistant {
+namespace switches {
+const char* const kAutofillAssistantServerKey = "autofill-assistant-key";
+}  // namespace switches
+
+namespace {
+
+const base::FeatureParam<std::string> kAutofillAssistantServerUrl{
+    &chrome::android::kAutofillAssistant, "url",
+    "https://automate-pa.googleapis.com"};
+
+// Time between two attempts to destroy the controller.
+static constexpr base::TimeDelta kDestroyRetryInterval =
+    base::TimeDelta::FromSeconds(2);
+
+// Fills a map from two Java arrays of strings of the same length.
+void FillParametersFromJava(JNIEnv* env,
+                            const JavaRef<jobjectArray>& names,
+                            const JavaRef<jobjectArray>& values,
+                            std::map<std::string, std::string>* parameters) {
+  std::vector<std::string> names_vector;
+  base::android::AppendJavaStringArrayToStringVector(env, names, &names_vector);
+  std::vector<std::string> values_vector;
+  base::android::AppendJavaStringArrayToStringVector(env, values,
+                                                     &values_vector);
+  DCHECK_EQ(names_vector.size(), values_vector.size());
+  for (size_t i = 0; i < names_vector.size(); ++i) {
+    parameters->insert(std::make_pair(names_vector[i], values_vector[i]));
+  }
+}
+
+}  // namespace
+
+static base::android::ScopedJavaLocalRef<jobject>
+JNI_AutofillAssistantClient_FromWebContents(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& jweb_contents) {
+  auto* web_contents = content::WebContents::FromJavaWebContents(jweb_contents);
+  ClientAndroid::CreateForWebContents(web_contents);
+  return ClientAndroid::FromWebContents(web_contents)->GetJavaObject();
+}
+
+ClientAndroid::ClientAndroid(content::WebContents* web_contents)
+    : web_contents_(web_contents),
+      // TODO: consider creating the java objects when needed.
+      java_object_(Java_AutofillAssistantClient_create(
+          AttachCurrentThread(),
+          reinterpret_cast<intptr_t>(this))),
+      weak_ptr_factory_(this) {}
+
+ClientAndroid::~ClientAndroid() {
+  Java_AutofillAssistantClient_clearNativePtr(AttachCurrentThread(),
+                                              java_object_);
+}
+
+base::android::ScopedJavaLocalRef<jobject> ClientAndroid::GetJavaObject() {
+  return base::android::ScopedJavaLocalRef<jobject>(java_object_);
+}
+
+void ClientAndroid::Autostart(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& jcaller,
+    const JavaParamRef<jstring>& jinitial_url,
+    const JavaParamRef<jobjectArray>& parameterNames,
+    const JavaParamRef<jobjectArray>& parameterValues) {
+  CreateController();
+  GURL initial_url(base::android::ConvertJavaStringToUTF8(env, jinitial_url));
+  std::map<std::string, std::string> parameters;
+  FillParametersFromJava(env, parameterNames, parameterValues, &parameters);
+  controller_->Start(initial_url, parameters);
+}
+
+base::android::ScopedJavaLocalRef<jstring> ClientAndroid::GetPrimaryAccountName(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& jcaller) {
+  AccountInfo account_info =
+      IdentityManagerFactory::GetForProfile(
+          Profile::FromBrowserContext(web_contents_->GetBrowserContext()))
+          ->GetPrimaryAccountInfo();
+  return base::android::ConvertUTF8ToJavaString(env, account_info.email);
+}
+
+void ClientAndroid::OnAccessToken(JNIEnv* env,
+                                  const JavaParamRef<jobject>& jcaller,
+                                  jboolean success,
+                                  const JavaParamRef<jstring>& access_token) {
+  if (fetch_access_token_callback_) {
+    std::move(fetch_access_token_callback_)
+        .Run(success, base::android::ConvertJavaStringToUTF8(access_token));
+  }
+}
+
+std::string ClientAndroid::GetApiKey() {
+  std::string api_key;
+  if (google_apis::IsGoogleChromeAPIKeyUsed()) {
+    api_key = chrome::GetChannel() == version_info::Channel::STABLE
+                  ? google_apis::GetAPIKey()
+                  : google_apis::GetNonStableAPIKey();
+  }
+  const auto* command_line = base::CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kAutofillAssistantServerKey)) {
+    api_key = command_line->GetSwitchValueASCII(
+        switches::kAutofillAssistantServerKey);
+  }
+  return api_key;
+}
+
+std::string ClientAndroid::GetAccountEmailAddress() {
+  JNIEnv* env = AttachCurrentThread();
+  return base::android::ConvertJavaStringToUTF8(
+      Java_AutofillAssistantClient_getAccountEmailAddress(env, java_object_));
+}
+
+AccessTokenFetcher* ClientAndroid::GetAccessTokenFetcher() {
+  return this;
+}
+
+autofill::PersonalDataManager* ClientAndroid::GetPersonalDataManager() {
+  return autofill::PersonalDataManagerFactory::GetForProfile(
+      ProfileManager::GetLastUsedProfile());
+}
+
+std::string ClientAndroid::GetServerUrl() {
+  return kAutofillAssistantServerUrl.Get();
+}
+
+UiController* ClientAndroid::GetUiController() {
+  DCHECK(controller_);
+  if (!ui_controller_android_ && controller_) {
+    ui_controller_android_ = std::make_unique<UiControllerAndroid>(
+        web_contents_, /* client= */ this, controller_.get());
+  }
+  return ui_controller_android_.get();
+}
+
+std::string ClientAndroid::GetLocale() {
+  return base::android::GetDefaultLocaleString();
+}
+
+std::string ClientAndroid::GetCountryCode() {
+  return base::android::ConvertJavaStringToUTF8(
+      Java_AutofillAssistantClient_getCountryCode(AttachCurrentThread(),
+                                                  java_object_));
+}
+
+void ClientAndroid::Stop() {
+  if (!controller_)
+    return;
+
+  if (!controller_->Terminate()) {
+    // This is a safety net and should be removed once all uses of
+    // base::Unretained in the execution and script tracking has been removed.
+    base::PostDelayedTaskWithTraits(
+        FROM_HERE, {content::BrowserThread::UI},
+        base::BindOnce(&ClientAndroid::Stop, weak_ptr_factory_.GetWeakPtr()),
+        kDestroyRetryInterval);
+    return;
+  }
+  ui_controller_android_.reset();
+  controller_.reset();
+}
+
+void ClientAndroid::FetchAccessToken(
+    base::OnceCallback<void(bool, const std::string&)> callback) {
+  DCHECK(!fetch_access_token_callback_);
+
+  fetch_access_token_callback_ = std::move(callback);
+  JNIEnv* env = AttachCurrentThread();
+  Java_AutofillAssistantClient_fetchAccessToken(env, java_object_);
+}
+
+void ClientAndroid::InvalidateAccessToken(const std::string& access_token) {
+  JNIEnv* env = AttachCurrentThread();
+  Java_AutofillAssistantClient_invalidateAccessToken(
+      env, java_object_,
+      base::android::ConvertUTF8ToJavaString(env, access_token));
+}
+
+void ClientAndroid::CreateController() {
+  if (controller_) {
+    return;
+  }
+  controller_ = std::make_unique<Controller>(
+      web_contents_,
+      /* client= */ this, WebController::CreateForWebContents(web_contents_),
+      Service::Create(web_contents_->GetBrowserContext(),
+                      /* client= */ this));
+}
+
+WEB_CONTENTS_USER_DATA_KEY_IMPL(ClientAndroid);
+
+}  // namespace autofill_assistant.
diff --git a/chrome/browser/android/autofill_assistant/client_android.h b/chrome/browser/android/autofill_assistant/client_android.h
new file mode 100644
index 0000000..b692d43
--- /dev/null
+++ b/chrome/browser/android/autofill_assistant/client_android.h
@@ -0,0 +1,94 @@
+// 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 CHROME_BROWSER_ANDROID_AUTOFILL_ASSISTANT_CLIENT_ANDROID_H_
+#define CHROME_BROWSER_ANDROID_AUTOFILL_ASSISTANT_CLIENT_ANDROID_H_
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/android/autofill_assistant/ui_controller_android.h"
+#include "components/autofill_assistant/browser/access_token_fetcher.h"
+#include "components/autofill_assistant/browser/client.h"
+#include "components/autofill_assistant/browser/controller.h"
+#include "content/public/browser/web_contents_user_data.h"
+
+namespace autofill_assistant {
+
+// Creates a Autofill Assistant client associated with a WebContents.
+//
+// To obtain an instance of this class from the C++ side, call
+// ClientAndroid::FromWebContents(web_contents). To make sure an instance
+// exists, call ClientAndroid::CreateForWebContents first.
+//
+// From the Java side, call AutofillAssistantClient.fromWebContents.
+//
+// This class is accessible from the Java side through AutofillAssistantClient.
+class ClientAndroid : public Client,
+                      public AccessTokenFetcher,
+                      public content::WebContentsUserData<ClientAndroid> {
+ public:
+  ~ClientAndroid() override;
+
+  // Returns the corresponding Java AutofillAssistantClient.
+  base::android::ScopedJavaLocalRef<jobject> GetJavaObject();
+
+  // Called from the Java side:
+  void Autostart(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& jcaller,
+      const base::android::JavaParamRef<jstring>& jinitial_url,
+      const base::android::JavaParamRef<jobjectArray>& parameterNames,
+      const base::android::JavaParamRef<jobjectArray>& parameterValues);
+  base::android::ScopedJavaLocalRef<jstring> GetPrimaryAccountName(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& jcaller);
+  void OnAccessToken(JNIEnv* env,
+                     const base::android::JavaParamRef<jobject>& jcaller,
+                     jboolean success,
+                     const base::android::JavaParamRef<jstring>& access_token);
+
+  // Overrides Client
+  std::string GetApiKey() override;
+  std::string GetAccountEmailAddress() override;
+  AccessTokenFetcher* GetAccessTokenFetcher() override;
+  autofill::PersonalDataManager* GetPersonalDataManager() override;
+  std::string GetServerUrl() override;
+  UiController* GetUiController() override;
+  std::string GetLocale() override;
+  std::string GetCountryCode() override;
+  void Stop() override;
+
+  // Overrides AccessTokenFetcher
+  void FetchAccessToken(
+      base::OnceCallback<void(bool, const std::string&)>) override;
+  void InvalidateAccessToken(const std::string& access_token) override;
+
+ private:
+  friend class content::WebContentsUserData<ClientAndroid>;
+
+  explicit ClientAndroid(content::WebContents* web_contents);
+  void CreateController();
+
+  WEB_CONTENTS_USER_DATA_KEY_DECL();
+
+  content::WebContents* web_contents_;
+
+  base::android::ScopedJavaGlobalRef<jobject> java_object_;
+  std::unique_ptr<Controller> controller_;
+  std::unique_ptr<UiControllerAndroid> ui_controller_android_;
+  base::OnceCallback<void(bool, const std::string&)>
+      fetch_access_token_callback_;
+
+  base::WeakPtrFactory<ClientAndroid> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ClientAndroid);
+};
+
+}  // namespace autofill_assistant.
+#endif  // CHROME_BROWSER_ANDROID_AUTOFILL_ASSISTANT_CLIENT_ANDROID_H_
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.cc b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
index 2e04c0b6..3bd6d23 100644
--- a/chrome/browser/android/autofill_assistant/ui_controller_android.cc
+++ b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
@@ -23,7 +23,6 @@
 #include "chrome/common/channel_info.h"
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/credit_card.h"
-#include "components/autofill_assistant/browser/access_token_fetcher.h"
 #include "components/autofill_assistant/browser/controller.h"
 #include "components/autofill_assistant/browser/rectf.h"
 #include "components/signin/core/browser/account_info.h"
@@ -40,88 +39,25 @@
 using base::android::JavaRef;
 
 namespace autofill_assistant {
-namespace switches {
-const char* const kAutofillAssistantServerKey = "autofill-assistant-key";
-}  // namespace switches
 
-namespace {
-
-const base::FeatureParam<std::string> kAutofillAssistantServerUrl{
-    &chrome::android::kAutofillAssistant, "url",
-    "https://automate-pa.googleapis.com"};
-
-// Time between two attempts to destroy the controller.
-static constexpr base::TimeDelta kDestroyRetryInterval =
-    base::TimeDelta::FromSeconds(2);
-
-// Builds a map from two Java arrays of strings with the same length.
-std::unique_ptr<std::map<std::string, std::string>> BuildParametersFromJava(
-    JNIEnv* env,
-    const JavaRef<jobjectArray>& names,
-    const JavaRef<jobjectArray>& values) {
-  std::vector<std::string> names_vector;
-  base::android::AppendJavaStringArrayToStringVector(env, names, &names_vector);
-  std::vector<std::string> values_vector;
-  base::android::AppendJavaStringArrayToStringVector(env, values,
-                                                     &values_vector);
-  DCHECK_EQ(names_vector.size(), values_vector.size());
-  auto parameters = std::make_unique<std::map<std::string, std::string>>();
-  for (size_t i = 0; i < names_vector.size(); ++i) {
-    parameters->insert(std::make_pair(names_vector[i], values_vector[i]));
-  }
-  return parameters;
-}
-
-}  // namespace
-
-UiControllerAndroid::UiControllerAndroid(
-    JNIEnv* env,
-    jobject jcaller,
-    const JavaParamRef<jobject>& webContents,
-    const JavaParamRef<jobjectArray>& parameterNames,
-    const JavaParamRef<jobjectArray>& parameterValues,
-    const JavaParamRef<jstring>& jlocale,
-    const JavaParamRef<jstring>& jcountryCode)
-    : ui_delegate_(nullptr), weak_ptr_factory_(this) {
-  java_autofill_assistant_ui_controller_.Reset(env, jcaller);
-
-  content::WebContents* web_contents =
-      content::WebContents::FromJavaWebContents(webContents);
+UiControllerAndroid::UiControllerAndroid(content::WebContents* web_contents,
+                                         Client* client,
+                                         UiDelegate* ui_delegate)
+    : client_(client), ui_delegate_(ui_delegate) {
   DCHECK(web_contents);
-  browser_context_ = web_contents->GetBrowserContext();
-
-  auto locale = base::android::ConvertJavaStringToUTF8(jlocale);
-  std::string country_code;
-  if (jcountryCode)
-    country_code = base::android::ConvertJavaStringToUTF8(jcountryCode);
-
-  Controller::CreateForWebContents(
-      web_contents, base::WrapUnique(this),
-      BuildParametersFromJava(env, parameterNames, parameterValues), locale,
-      country_code);
-  DCHECK(ui_delegate_);
+  DCHECK(client);
+  DCHECK(ui_delegate);
+  java_autofill_assistant_ui_controller_ =
+      Java_AutofillAssistantUiController_createAndStartUi(
+          AttachCurrentThread(), web_contents->GetJavaWebContents(),
+          reinterpret_cast<intptr_t>(this));
 }
 
 UiControllerAndroid::~UiControllerAndroid() {
-  Java_AutofillAssistantUiController_onNativeDestroy(
+  Java_AutofillAssistantUiController_clearNativePtr(
       AttachCurrentThread(), java_autofill_assistant_ui_controller_);
 }
 
-void UiControllerAndroid::Start(JNIEnv* env,
-                                const JavaParamRef<jobject>& jcaller,
-                                const JavaParamRef<jstring>& initialUrlString) {
-  GURL initialUrl =
-      GURL(base::android::ConvertJavaStringToUTF8(env, initialUrlString));
-  ui_delegate_->Start(initialUrl);
-}
-
-// This interface must be called before everything else in this class except the
-// constructor.
-void UiControllerAndroid::SetUiDelegate(UiDelegate* ui_delegate) {
-  ui_delegate_ = ui_delegate;
-  DCHECK(ui_delegate_);
-}
-
 void UiControllerAndroid::ShowStatusMessage(const std::string& message) {
   JNIEnv* env = AttachCurrentThread();
   Java_AutofillAssistantUiController_onShowStatusMessage(
@@ -273,7 +209,9 @@
       auto guid = payment_info->card->billing_address_id();
       if (!guid.empty()) {
         autofill::AutofillProfile* profile =
-            GetPersonalDataManager()->GetProfileByGUID(guid);
+            autofill::PersonalDataManagerFactory::GetForProfile(
+                ProfileManager::GetLastUsedProfile())
+                ->GetProfileByGUID(guid);
         if (profile != nullptr)
           payment_info->billing_address =
               std::make_unique<autofill::AutofillProfile>(*profile);
@@ -301,17 +239,6 @@
   std::move(get_payment_information_callback_).Run(std::move(payment_info));
 }
 
-void UiControllerAndroid::OnAccessToken(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& jcaller,
-    jboolean success,
-    const JavaParamRef<jstring>& access_token) {
-  if (fetch_access_token_callback_) {
-    std::move(fetch_access_token_callback_)
-        .Run(success, base::android::ConvertJavaStringToUTF8(access_token));
-  }
-}
-
 void UiControllerAndroid::OnShowDetails(JNIEnv* env,
                                         const JavaParamRef<jobject>& jcaller,
                                         jboolean jcan_continue) {
@@ -321,16 +248,6 @@
 }
 
 base::android::ScopedJavaLocalRef<jstring>
-UiControllerAndroid::GetPrimaryAccountName(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& jcaller) {
-  AccountInfo account_info = IdentityManagerFactory::GetForProfile(
-                                 Profile::FromBrowserContext(browser_context_))
-                                 ->GetPrimaryAccountInfo();
-  return base::android::ConvertUTF8ToJavaString(env, account_info.email);
-}
-
-base::android::ScopedJavaLocalRef<jstring>
 UiControllerAndroid::OnRequestDebugContext(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& jcaller) {
@@ -398,6 +315,8 @@
   JNIEnv* env = AttachCurrentThread();
   Java_AutofillAssistantUiController_onRequestPaymentInformation(
       env, java_autofill_assistant_ui_controller_,
+      base::android::ConvertUTF8ToJavaString(env,
+                                             client_->GetAccountEmailAddress()),
       payment_options->request_shipping, payment_options->request_payer_name,
       payment_options->request_payer_phone,
       payment_options->request_payer_email,
@@ -446,6 +365,12 @@
       env, java_autofill_assistant_ui_controller_);
 }
 
+void UiControllerAndroid::Stop(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& obj) {
+  client_->Stop();
+}
+
 void UiControllerAndroid::UpdateTouchableArea(bool enabled,
                                               const std::vector<RectF>& areas) {
   JNIEnv* env = AttachCurrentThread();
@@ -469,85 +394,4 @@
 std::string UiControllerAndroid::GetDebugContext() const {
   return ui_delegate_->GetDebugContext();
 }
-
-std::string UiControllerAndroid::GetApiKey() {
-  std::string api_key;
-  if (google_apis::IsGoogleChromeAPIKeyUsed()) {
-    api_key = chrome::GetChannel() == version_info::Channel::STABLE
-                  ? google_apis::GetAPIKey()
-                  : google_apis::GetNonStableAPIKey();
-  }
-  const auto* command_line = base::CommandLine::ForCurrentProcess();
-  if (command_line->HasSwitch(switches::kAutofillAssistantServerKey)) {
-    api_key = command_line->GetSwitchValueASCII(
-        switches::kAutofillAssistantServerKey);
-  }
-  return api_key;
-}
-
-AccessTokenFetcher* UiControllerAndroid::GetAccessTokenFetcher() {
-  return this;
-}
-
-autofill::PersonalDataManager* UiControllerAndroid::GetPersonalDataManager() {
-  return autofill::PersonalDataManagerFactory::GetForProfile(
-      ProfileManager::GetLastUsedProfile());
-}
-
-std::string UiControllerAndroid::GetServerUrl() {
-  return kAutofillAssistantServerUrl.Get();
-}
-
-UiController* UiControllerAndroid::GetUiController() {
-  return this;
-}
-
-void UiControllerAndroid::FetchAccessToken(
-    base::OnceCallback<void(bool, const std::string&)> callback) {
-  DCHECK(!fetch_access_token_callback_);
-
-  fetch_access_token_callback_ = std::move(callback);
-  JNIEnv* env = AttachCurrentThread();
-  Java_AutofillAssistantUiController_fetchAccessToken(
-      env, java_autofill_assistant_ui_controller_);
-}
-
-void UiControllerAndroid::InvalidateAccessToken(
-    const std::string& access_token) {
-  JNIEnv* env = AttachCurrentThread();
-  Java_AutofillAssistantUiController_invalidateAccessToken(
-      env, java_autofill_assistant_ui_controller_,
-      base::android::ConvertUTF8ToJavaString(env, access_token));
-}
-
-void UiControllerAndroid::Destroy(JNIEnv* env,
-                                  const JavaParamRef<jobject>& obj) {
-  if (!ui_delegate_->Terminate()) {
-    // This is a safety net and should be removed once all uses of
-    // base::Unretained in the execution and script tracking has been removed.
-    base::PostDelayedTaskWithTraits(
-        FROM_HERE, {content::BrowserThread::UI},
-        base::BindOnce(&UiControllerAndroid::Destroy,
-                       weak_ptr_factory_.GetWeakPtr(), base::Unretained(env),
-                       base::ConstRef(obj)),
-        kDestroyRetryInterval);
-    return;
-  }
-  ui_delegate_->OnDestroy();
-}
-
-static jlong JNI_AutofillAssistantUiController_Init(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& jcaller,
-    const JavaParamRef<jobject>& webContents,
-    const JavaParamRef<jobjectArray>& parameterNames,
-    const JavaParamRef<jobjectArray>& parameterValues,
-    const JavaParamRef<jstring>& jlocale,
-    const JavaParamRef<jstring>& jcountryCode) {
-  auto* ui_controller_android = new autofill_assistant::UiControllerAndroid(
-      env, jcaller, webContents, parameterNames, parameterValues, jlocale,
-      jcountryCode);
-  return reinterpret_cast<intptr_t>(ui_controller_android);
-}
-
 }  // namespace autofill_assistant.
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.h b/chrome/browser/android/autofill_assistant/ui_controller_android.h
index df1d850..4088b7b 100644
--- a/chrome/browser/android/autofill_assistant/ui_controller_android.h
+++ b/chrome/browser/android/autofill_assistant/ui_controller_android.h
@@ -11,32 +11,21 @@
 
 #include "base/android/scoped_java_ref.h"
 #include "base/macros.h"
-#include "components/autofill_assistant/browser/access_token_fetcher.h"
 #include "components/autofill_assistant/browser/client.h"
 #include "components/autofill_assistant/browser/ui_controller.h"
 
-namespace content {
-class BrowserContext;
-}  // namespace content
-
 namespace autofill_assistant {
 // Class implements UiController, Client and starts the Controller.
-class UiControllerAndroid : public UiController,
-                            public Client,
-                            public AccessTokenFetcher {
+class UiControllerAndroid : public UiController {
  public:
-  UiControllerAndroid(
-      JNIEnv* env,
-      jobject jcaller,
-      const base::android::JavaParamRef<jobject>& webContents,
-      const base::android::JavaParamRef<jobjectArray>& parameterNames,
-      const base::android::JavaParamRef<jobjectArray>& parameterValues,
-      const base::android::JavaParamRef<jstring>& locale,
-      const base::android::JavaParamRef<jstring>& countryCode);
+  // pointers to |web_contents|, |client| and |ui_delegate| must remain valid
+  // for the lifetime of this instance.
+  UiControllerAndroid(content::WebContents* web_contents,
+                      Client* client,
+                      UiDelegate* ui_delegate);
   ~UiControllerAndroid() override;
 
   // Overrides UiController:
-  void SetUiDelegate(UiDelegate* ui_delegate) override;
   void ShowStatusMessage(const std::string& message) override;
   std::string GetStatusMessage() override;
   void ShowOverlay() override;
@@ -68,23 +57,8 @@
   std::string GetDebugContext() const override;
   void ExpandBottomSheet() override;
 
-  // Overrides Client:
-  std::string GetApiKey() override;
-  AccessTokenFetcher* GetAccessTokenFetcher() override;
-  autofill::PersonalDataManager* GetPersonalDataManager() override;
-  std::string GetServerUrl() override;
-  UiController* GetUiController() override;
-
-  // Overrides AccessTokenFetcher
-  void FetchAccessToken(
-      base::OnceCallback<void(bool, const std::string&)>) override;
-  void InvalidateAccessToken(const std::string& access_token) override;
-
   // Called by Java.
-  void Start(JNIEnv* env,
-             const base::android::JavaParamRef<jobject>& jcaller,
-             const base::android::JavaParamRef<jstring>& initialUrlString);
-  void Destroy(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
+  void Stop(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
   void UpdateTouchableArea(JNIEnv* env,
                            const base::android::JavaParamRef<jobject>& obj);
   void OnUserInteractionInsideTouchableArea(
@@ -114,10 +88,6 @@
       const base::android::JavaParamRef<jstring>& jpayer_phone,
       const base::android::JavaParamRef<jstring>& jpayer_email,
       jboolean jis_terms_and_services_accepted);
-  void OnAccessToken(JNIEnv* env,
-                     const base::android::JavaParamRef<jobject>& jcaller,
-                     jboolean success,
-                     const base::android::JavaParamRef<jstring>& access_token);
   void OnShowDetails(JNIEnv* env,
                      const base::android::JavaParamRef<jobject>& jcaller,
                      jboolean success);
@@ -129,24 +99,18 @@
       const base::android::JavaParamRef<jobject>& jcaller);
 
  private:
+  Client* const client_;
+  UiDelegate* const ui_delegate_;
+
   // Java-side AutofillAssistantUiController object.
   base::android::ScopedJavaGlobalRef<jobject>
       java_autofill_assistant_ui_controller_;
 
-  // UI delegate can be nullptr before SetUiDelegate.
-  UiDelegate* ui_delegate_;
-  content::BrowserContext* browser_context_;
-
   base::OnceCallback<void(const std::string&)> choice_callback_;
   base::OnceCallback<void(std::unique_ptr<PaymentInformation>)>
       get_payment_information_callback_;
-  std::unique_ptr<AccessTokenFetcher> access_token_fetcher_;
-  base::OnceCallback<void(bool, const std::string&)>
-      fetch_access_token_callback_;
   base::OnceCallback<void(bool)> show_details_callback_;
 
-  base::WeakPtrFactory<UiControllerAndroid> weak_ptr_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(UiControllerAndroid);
 };
 
diff --git a/chrome/browser/android/resource_id.h b/chrome/browser/android/resource_id.h
index 21c71700..0b84d6e6 100644
--- a/chrome/browser/android/resource_id.h
+++ b/chrome/browser/android/resource_id.h
@@ -26,7 +26,6 @@
 LINK_RESOURCE_ID(0, 0)
 
 // InfoBar resources.
-LINK_RESOURCE_ID(IDR_INFOBAR_3D_BLOCKED, R.drawable.infobar_3d_blocked)
 LINK_RESOURCE_ID(IDR_INFOBAR_AUTOFILL_CC, R.drawable.infobar_autofill_cc)
 
 // Android only infobars.
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 2aa545543..5ff2ecd 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -387,7 +387,7 @@
 #include "chrome/browser/android/tab_android.h"
 #include "chrome/browser/android/webapps/single_tab_mode_tab_helper.h"
 #include "chrome/browser/chrome_browser_main_android.h"
-#include "chrome/browser/offline_pages/offline_page_auto_fetcher.h"
+#include "chrome/browser/offline_pages/android/offline_page_auto_fetcher.h"
 #include "chrome/common/descriptors_android.h"
 #include "chrome/services/media_gallery_util/public/mojom/constants.mojom.h"
 #include "components/crash/content/browser/child_exit_observer_android.h"
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 17539ab..ca046571 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -81,6 +81,8 @@
     "//chrome/services/file_util/public/cpp",
     "//chromeos",
     "//chromeos/assistant:buildflags",
+    "//chromeos/attestation",
+    "//chromeos/audio",
     "//chromeos/components/drivefs",
     "//chromeos/components/drivefs/mojom",
     "//chromeos/components/multidevice",
@@ -98,6 +100,7 @@
     "//chromeos/dbus:metrics_event_proto",
     "//chromeos/dbus:oobe_config_proto",
     "//chromeos/dbus/services:services",
+    "//chromeos/disks",
     "//chromeos/login/auth",
     "//chromeos/login/login_state",
     "//chromeos/network",
@@ -306,6 +309,10 @@
     "account_manager/account_migration_runner.h",
     "account_mapper_util.cc",
     "account_mapper_util.h",
+    "android_sms/android_sms_app_helper_delegate_impl.cc",
+    "android_sms/android_sms_app_helper_delegate_impl.h",
+    "android_sms/android_sms_pairing_state_tracker_impl.cc",
+    "android_sms/android_sms_pairing_state_tracker_impl.h",
     "app_mode/app_launch_utils.cc",
     "app_mode/app_launch_utils.h",
     "app_mode/app_session.cc",
@@ -1377,10 +1384,6 @@
     "login/wizard_controller.h",
     "mobile/mobile_activator.cc",
     "mobile/mobile_activator.h",
-    "multidevice_setup/android_sms_app_helper_delegate_impl.cc",
-    "multidevice_setup/android_sms_app_helper_delegate_impl.h",
-    "multidevice_setup/android_sms_pairing_state_tracker_impl.cc",
-    "multidevice_setup/android_sms_pairing_state_tracker_impl.h",
     "multidevice_setup/auth_token_validator_factory.cc",
     "multidevice_setup/auth_token_validator_factory.h",
     "multidevice_setup/auth_token_validator_impl.cc",
@@ -1748,8 +1751,6 @@
     "profiles/profile_helper.h",
     "profiles/profile_util.cc",
     "profiles/profile_util.h",
-    "proxy_cros_settings_parser.cc",
-    "proxy_cros_settings_parser.h",
     "reset/metrics.h",
     "resource_reporter/resource_reporter.cc",
     "resource_reporter/resource_reporter.h",
@@ -2095,6 +2096,7 @@
     "accessibility/ax_host_service_unittest.cc",
     "accessibility/switch_access_panel_unittest.cc",
     "account_manager/account_migration_runner_unittest.cc",
+    "android_sms/android_sms_app_helper_delegate_impl_unittest.cc",
     "app_mode/startup_app_launcher_unittest.cc",
     "apps/apk_web_app_installer_unittest.cc",
     "apps/intent_helper/apps_navigation_throttle_unittest.cc",
@@ -2287,7 +2289,6 @@
     "login/users/multi_profile_user_controller_unittest.cc",
     "login/users/user_manager_unittest.cc",
     "mobile/mobile_activator_unittest.cc",
-    "multidevice_setup/android_sms_app_helper_delegate_impl_unittest.cc",
     "net/client_cert_store_chromeos_unittest.cc",
     "net/network_portal_detector_impl_unittest.cc",
     "net/network_pref_state_observer_unittest.cc",
diff --git a/chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl.cc b/chrome/browser/chromeos/android_sms/android_sms_app_helper_delegate_impl.cc
similarity index 97%
rename from chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl.cc
rename to chrome/browser/chromeos/android_sms/android_sms_app_helper_delegate_impl.cc
index a72bfef9..01f1abc1 100644
--- a/chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl.cc
+++ b/chrome/browser/chromeos/android_sms/android_sms_app_helper_delegate_impl.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl.h"
+#include "chrome/browser/chromeos/android_sms/android_sms_app_helper_delegate_impl.h"
 
 #include <utility>
 
@@ -50,7 +50,7 @@
 
 namespace chromeos {
 
-namespace multidevice_setup {
+namespace android_sms {
 
 AndroidSmsAppHelperDelegateImpl::PwaFetcherDelegate::PwaFetcherDelegate() =
     default;
@@ -223,6 +223,6 @@
   pwa_fetcher_delegate_ = std::move(test_pwa_fetcher_delegate);
 }
 
-}  // namespace multidevice_setup
+}  // namespace android_sms
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl.h b/chrome/browser/chromeos/android_sms/android_sms_app_helper_delegate_impl.h
similarity index 87%
rename from chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl.h
rename to chrome/browser/chromeos/android_sms/android_sms_app_helper_delegate_impl.h
index 5868ea4..15e6dfd 100644
--- a/chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl.h
+++ b/chrome/browser/chromeos/android_sms/android_sms_app_helper_delegate_impl.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_MULTIDEVICE_SETUP_ANDROID_SMS_APP_HELPER_DELEGATE_IMPL_H_
-#define CHROME_BROWSER_CHROMEOS_MULTIDEVICE_SETUP_ANDROID_SMS_APP_HELPER_DELEGATE_IMPL_H_
+#ifndef CHROME_BROWSER_CHROMEOS_ANDROID_SMS_ANDROID_SMS_APP_HELPER_DELEGATE_IMPL_H_
+#define CHROME_BROWSER_CHROMEOS_ANDROID_SMS_ANDROID_SMS_APP_HELPER_DELEGATE_IMPL_H_
 
 #include <string>
 
@@ -24,9 +24,10 @@
 
 namespace chromeos {
 
-namespace multidevice_setup {
+namespace android_sms {
 
-class AndroidSmsAppHelperDelegateImpl : public AndroidSmsAppHelperDelegate {
+class AndroidSmsAppHelperDelegateImpl
+    : public multidevice_setup::AndroidSmsAppHelperDelegate {
  public:
   explicit AndroidSmsAppHelperDelegateImpl(Profile* profile);
   ~AndroidSmsAppHelperDelegateImpl() override;
@@ -84,8 +85,8 @@
   DISALLOW_COPY_AND_ASSIGN(AndroidSmsAppHelperDelegateImpl);
 };
 
-}  // namespace multidevice_setup
+}  // namespace android_sms
 
 }  // namespace chromeos
 
-#endif  // CHROME_BROWSER_CHROMEOS_MULTIDEVICE_SETUP_ANDROID_SMS_APP_HELPER_DELEGATE_IMPL_H_
+#endif  // CHROME_BROWSER_CHROMEOS_ANDROID_SMS_ANDROID_SMS_APP_HELPER_DELEGATE_IMPL_H_
diff --git a/chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl_unittest.cc b/chrome/browser/chromeos/android_sms/android_sms_app_helper_delegate_impl_unittest.cc
similarity index 97%
rename from chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl_unittest.cc
rename to chrome/browser/chromeos/android_sms/android_sms_app_helper_delegate_impl_unittest.cc
index 316c778f..f8b4b39 100644
--- a/chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl_unittest.cc
+++ b/chrome/browser/chromeos/android_sms/android_sms_app_helper_delegate_impl_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl.h"
+#include "chrome/browser/chromeos/android_sms/android_sms_app_helper_delegate_impl.h"
 
 #include <memory>
 #include <vector>
@@ -84,7 +84,7 @@
 
 namespace chromeos {
 
-namespace multidevice_setup {
+namespace android_sms {
 
 class AndroidSmsAppHelperDelegateImplTest : public testing::Test {
  protected:
@@ -234,7 +234,8 @@
   std::unique_ptr<FakeCookieManager> fake_cookie_manager_;
   std::unique_ptr<web_app::TestPendingAppManager> test_pending_app_manager_;
   TestPwaFetcherDelegate* test_pwa_fetcher_delegate_;
-  std::unique_ptr<AndroidSmsAppHelperDelegate> android_sms_app_helper_delegate_;
+  std::unique_ptr<multidevice_setup::AndroidSmsAppHelperDelegate>
+      android_sms_app_helper_delegate_;
 
   DISALLOW_COPY_AND_ASSIGN(AndroidSmsAppHelperDelegateImplTest);
 };
@@ -277,6 +278,6 @@
   // app here.
 }
 
-}  // namespace multidevice_setup
+}  // namespace android_sms
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/multidevice_setup/android_sms_pairing_state_tracker_impl.cc b/chrome/browser/chromeos/android_sms/android_sms_pairing_state_tracker_impl.cc
similarity index 95%
rename from chrome/browser/chromeos/multidevice_setup/android_sms_pairing_state_tracker_impl.cc
rename to chrome/browser/chromeos/android_sms/android_sms_pairing_state_tracker_impl.cc
index 6ab024e..4849f987 100644
--- a/chrome/browser/chromeos/multidevice_setup/android_sms_pairing_state_tracker_impl.cc
+++ b/chrome/browser/chromeos/android_sms/android_sms_pairing_state_tracker_impl.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/chromeos/multidevice_setup/android_sms_pairing_state_tracker_impl.h"
+#include "chrome/browser/chromeos/android_sms/android_sms_pairing_state_tracker_impl.h"
 
 #include <utility>
 
@@ -22,7 +22,7 @@
 
 namespace chromeos {
 
-namespace multidevice_setup {
+namespace android_sms {
 
 AndroidSmsPairingStateTrackerImpl::AndroidSmsPairingStateTrackerImpl(
     content::BrowserContext* browser_context)
@@ -92,6 +92,6 @@
   return partition->GetCookieManagerForBrowserProcess();
 }
 
-}  // namespace multidevice_setup
+}  // namespace android_sms
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/multidevice_setup/android_sms_pairing_state_tracker_impl.h b/chrome/browser/chromeos/android_sms/android_sms_pairing_state_tracker_impl.h
similarity index 80%
rename from chrome/browser/chromeos/multidevice_setup/android_sms_pairing_state_tracker_impl.h
rename to chrome/browser/chromeos/android_sms/android_sms_pairing_state_tracker_impl.h
index 2fa4e73..156ec13 100644
--- a/chrome/browser/chromeos/multidevice_setup/android_sms_pairing_state_tracker_impl.h
+++ b/chrome/browser/chromeos/android_sms/android_sms_pairing_state_tracker_impl.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_MULTIDEVICE_SETUP_ANDROID_SMS_PAIRING_STATE_TRACKER_IMPL_H_
-#define CHROME_BROWSER_CHROMEOS_MULTIDEVICE_SETUP_ANDROID_SMS_PAIRING_STATE_TRACKER_IMPL_H_
+#ifndef CHROME_BROWSER_CHROMEOS_ANDROID_SMS_ANDROID_SMS_PAIRING_STATE_TRACKER_IMPL_H_
+#define CHROME_BROWSER_CHROMEOS_ANDROID_SMS_ANDROID_SMS_PAIRING_STATE_TRACKER_IMPL_H_
 
 #include "base/memory/weak_ptr.h"
 #include "chromeos/services/multidevice_setup/public/cpp/android_sms_pairing_state_tracker.h"
@@ -20,11 +20,11 @@
 
 namespace chromeos {
 
-namespace multidevice_setup {
+namespace android_sms {
 
 // Concrete AndroidSmsPairingStateTracker implementation.
 class AndroidSmsPairingStateTrackerImpl
-    : public AndroidSmsPairingStateTracker,
+    : public multidevice_setup::AndroidSmsPairingStateTracker,
       public network::mojom::CookieChangeListener {
  public:
   explicit AndroidSmsPairingStateTrackerImpl(
@@ -51,8 +51,8 @@
   DISALLOW_COPY_AND_ASSIGN(AndroidSmsPairingStateTrackerImpl);
 };
 
-}  // namespace multidevice_setup
+}  // namespace android_sms
 
 }  // namespace chromeos
 
-#endif  // CHROME_BROWSER_CHROMEOS_MULTIDEVICE_SETUP_ANDROID_SMS_PAIRING_STATE_TRACKER_IMPL_H_
+#endif  // CHROME_BROWSER_CHROMEOS_ANDROID_SMS_ANDROID_SMS_PAIRING_STATE_TRACKER_IMPL_H_
diff --git a/chrome/browser/chromeos/proxy_cros_settings_parser.cc b/chrome/browser/chromeos/proxy_cros_settings_parser.cc
deleted file mode 100644
index d5ce5f1..0000000
--- a/chrome/browser/chromeos/proxy_cros_settings_parser.cc
+++ /dev/null
@@ -1,380 +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 "chrome/browser/chromeos/proxy_cros_settings_parser.h"
-
-#include <stdint.h>
-
-#include "base/stl_util.h"
-#include "base/strings/string_util.h"
-#include "base/values.h"
-#include "chromeos/network/proxy/ui_proxy_config.h"
-#include "chromeos/network/proxy/ui_proxy_config_service.h"
-
-namespace chromeos {
-
-namespace {
-
-std::unique_ptr<base::Value> CreateServerHostValue(
-    const UIProxyConfig::ManualProxy& proxy) {
-  return proxy.server.is_valid() ? std::make_unique<base::Value>(
-                                       proxy.server.host_port_pair().host())
-                                 : nullptr;
-}
-
-std::unique_ptr<base::Value> CreateServerPortValue(
-    const UIProxyConfig::ManualProxy& proxy) {
-  return proxy.server.is_valid() ? std::make_unique<base::Value>(
-                                       proxy.server.host_port_pair().port())
-                                 : nullptr;
-}
-
-net::ProxyServer CreateProxyServer(std::string host,
-                                   uint16_t port,
-                                   net::ProxyServer::Scheme scheme) {
-  if (host.empty() && port == 0)
-    return net::ProxyServer();
-  uint16_t default_port = net::ProxyServer::GetDefaultPortForScheme(scheme);
-  net::HostPortPair host_port_pair;
-  // Check if host is a valid URL or a string of valid format <server>::<port>.
-  GURL url(host);
-  if (url.is_valid())  // See if host is URL.
-    host_port_pair = net::HostPortPair::FromURL(url);
-  if (host_port_pair.host().empty())  // See if host is <server>::<port>.
-    host_port_pair = net::HostPortPair::FromString(host);
-  if (host_port_pair.host().empty())  // Host is not URL or <server>::<port>.
-    host_port_pair = net::HostPortPair(host, port);
-  if (host_port_pair.port() == 0)  // No port in host, use default.
-    host_port_pair.set_port(default_port);
-  return net::ProxyServer(scheme, host_port_pair);
-}
-
-net::ProxyServer CreateProxyServerFromHost(
-    const std::string& host,
-    const UIProxyConfig::ManualProxy& proxy,
-    net::ProxyServer::Scheme scheme) {
-  uint16_t port = 0;
-  if (proxy.server.is_valid())
-    port = proxy.server.host_port_pair().port();
-  return CreateProxyServer(host, port, scheme);
-}
-
-net::ProxyServer CreateProxyServerFromPort(
-    uint16_t port,
-    const UIProxyConfig::ManualProxy& proxy,
-    net::ProxyServer::Scheme scheme) {
-  std::string host;
-  if (proxy.server.is_valid())
-    host = proxy.server.host_port_pair().host();
-  return CreateProxyServer(host, port, scheme);
-}
-
-}  // namespace
-
-namespace proxy_cros_settings_parser {
-
-// Common prefix of all proxy prefs.
-const char kProxyPrefsPrefix[] = "cros.session.proxy";
-
-// Names of proxy preferences.
-const char kProxyPacUrl[] = "cros.session.proxy.pacurl";
-const char kProxySingleHttp[] = "cros.session.proxy.singlehttp";
-const char kProxySingleHttpPort[] = "cros.session.proxy.singlehttpport";
-const char kProxyHttpUrl[] = "cros.session.proxy.httpurl";
-const char kProxyHttpPort[] = "cros.session.proxy.httpport";
-const char kProxyHttpsUrl[] = "cros.session.proxy.httpsurl";
-const char kProxyHttpsPort[] = "cros.session.proxy.httpsport";
-const char kProxyType[] = "cros.session.proxy.type";
-const char kProxySingle[] = "cros.session.proxy.single";
-const char kProxyFtpUrl[] = "cros.session.proxy.ftpurl";
-const char kProxyFtpPort[] = "cros.session.proxy.ftpport";
-const char kProxySocks[] = "cros.session.proxy.socks";
-const char kProxySocksPort[] = "cros.session.proxy.socksport";
-const char kProxyIgnoreList[] = "cros.session.proxy.ignorelist";
-const char kProxyUsePacUrl[] = "cros.session.proxy.usepacurl";
-
-const char* const kProxySettings[] = {
-    kProxyPacUrl,    kProxySingleHttp, kProxySingleHttpPort, kProxyHttpUrl,
-    kProxyHttpPort,  kProxyHttpsUrl,   kProxyHttpsPort,      kProxyType,
-    kProxySingle,    kProxyFtpUrl,     kProxyFtpPort,        kProxySocks,
-    kProxySocksPort, kProxyIgnoreList, kProxyUsePacUrl,
-};
-
-// We have to explicitly export this because the arraysize macro doesn't like
-// extern arrays as their size is not known on compile time.
-const size_t kProxySettingsCount = base::size(kProxySettings);
-
-bool IsProxyPref(const std::string& path) {
-  return base::StartsWith(path, kProxyPrefsPrefix,
-                          base::CompareCase::SENSITIVE);
-}
-
-void SetProxyPrefValue(const std::string& network_guid,
-                       const std::string& path,
-                       const base::Value* in_value,
-                       UIProxyConfigService* config_service) {
-  if (!in_value) {
-    NOTREACHED();
-    return;
-  }
-
-  // Retrieve proxy config.
-  UIProxyConfig config;
-  config_service->GetProxyConfig(network_guid, &config);
-
-  if (path == kProxyPacUrl) {
-    std::string val;
-    if (in_value->GetAsString(&val)) {
-      GURL url(val);
-      if (url.is_valid())
-        config.SetPacUrl(url);
-      else
-        config.mode = UIProxyConfig::MODE_AUTO_DETECT;
-    }
-  } else if (path == kProxySingleHttp) {
-    std::string val;
-    if (in_value->GetAsString(&val)) {
-      config.SetSingleProxy(CreateProxyServerFromHost(
-          val, config.single_proxy, net::ProxyServer::SCHEME_HTTP));
-    }
-  } else if (path == kProxySingleHttpPort) {
-    int val;
-    if (in_value->GetAsInteger(&val)) {
-      config.SetSingleProxy(CreateProxyServerFromPort(
-          val, config.single_proxy, net::ProxyServer::SCHEME_HTTP));
-    }
-  } else if (path == kProxyHttpUrl) {
-    std::string val;
-    if (in_value->GetAsString(&val)) {
-      config.SetProxyForScheme(
-          "http", CreateProxyServerFromHost(
-              val, config.http_proxy, net::ProxyServer::SCHEME_HTTP));
-    }
-  } else if (path == kProxyHttpPort) {
-    int val;
-    if (in_value->GetAsInteger(&val)) {
-      config.SetProxyForScheme(
-          "http", CreateProxyServerFromPort(
-              val, config.http_proxy, net::ProxyServer::SCHEME_HTTP));
-    }
-  } else if (path == kProxyHttpsUrl) {
-    std::string val;
-    if (in_value->GetAsString(&val)) {
-      config.SetProxyForScheme(
-          "https", CreateProxyServerFromHost(
-              val, config.https_proxy, net::ProxyServer::SCHEME_HTTP));
-    }
-  } else if (path == kProxyHttpsPort) {
-    int val;
-    if (in_value->GetAsInteger(&val)) {
-      config.SetProxyForScheme(
-          "https", CreateProxyServerFromPort(
-              val, config.https_proxy, net::ProxyServer::SCHEME_HTTP));
-    }
-  } else if (path == kProxyType) {
-    int val;
-    if (in_value->GetAsInteger(&val)) {
-      if (val == 3) {
-        if (config.automatic_proxy.pac_url.is_valid())
-          config.SetPacUrl(config.automatic_proxy.pac_url);
-        else
-          config.mode = UIProxyConfig::MODE_AUTO_DETECT;
-      } else if (val == 2) {
-        if (config.single_proxy.server.is_valid()) {
-          config.SetSingleProxy(config.single_proxy.server);
-        } else {
-          bool set_config = false;
-          if (config.http_proxy.server.is_valid()) {
-            config.SetProxyForScheme("http", config.http_proxy.server);
-            set_config = true;
-          }
-          if (config.https_proxy.server.is_valid()) {
-            config.SetProxyForScheme("https", config.https_proxy.server);
-            set_config = true;
-          }
-          if (config.ftp_proxy.server.is_valid()) {
-            config.SetProxyForScheme("ftp", config.ftp_proxy.server);
-            set_config = true;
-          }
-          if (config.socks_proxy.server.is_valid()) {
-            config.SetProxyForScheme("socks", config.socks_proxy.server);
-            set_config = true;
-          }
-          if (!set_config)
-            config.SetProxyForScheme("http", net::ProxyServer());
-        }
-      } else {
-        config.mode = UIProxyConfig::MODE_DIRECT;
-      }
-    }
-  } else if (path == kProxySingle) {
-    bool val;
-    if (in_value->GetAsBoolean(&val)) {
-      if (val)
-        config.SetSingleProxy(config.single_proxy.server);
-      else
-        config.SetProxyForScheme("http", config.http_proxy.server);
-    }
-  } else if (path == kProxyUsePacUrl) {
-    bool use_pac_url;
-    if (in_value->GetAsBoolean(&use_pac_url)) {
-      if (use_pac_url && config.automatic_proxy.pac_url.is_valid())
-        config.SetPacUrl(config.automatic_proxy.pac_url);
-      else
-        config.mode = UIProxyConfig::MODE_AUTO_DETECT;
-    }
-  } else if (path == kProxyFtpUrl) {
-    std::string val;
-    if (in_value->GetAsString(&val)) {
-      config.SetProxyForScheme(
-          "ftp", CreateProxyServerFromHost(
-              val, config.ftp_proxy, net::ProxyServer::SCHEME_HTTP));
-    }
-  } else if (path == kProxyFtpPort) {
-    int val;
-    if (in_value->GetAsInteger(&val)) {
-      config.SetProxyForScheme(
-          "ftp", CreateProxyServerFromPort(
-              val, config.ftp_proxy, net::ProxyServer::SCHEME_HTTP));
-    }
-  } else if (path == kProxySocks) {
-    std::string val;
-    if (in_value->GetAsString(&val)) {
-      config.SetProxyForScheme(
-          "socks", CreateProxyServerFromHost(
-                       val, config.socks_proxy,
-                       base::StartsWith(val, "socks5://",
-                                        base::CompareCase::INSENSITIVE_ASCII)
-                           ? net::ProxyServer::SCHEME_SOCKS5
-                           : net::ProxyServer::SCHEME_SOCKS4));
-    }
-  } else if (path == kProxySocksPort) {
-    int val;
-    if (in_value->GetAsInteger(&val)) {
-      std::string host = config.socks_proxy.server.host_port_pair().host();
-      config.SetProxyForScheme(
-          "socks", CreateProxyServerFromPort(
-                       val, config.socks_proxy,
-                       base::StartsWith(host, "socks5://",
-                                        base::CompareCase::INSENSITIVE_ASCII)
-                           ? net::ProxyServer::SCHEME_SOCKS5
-                           : net::ProxyServer::SCHEME_SOCKS4));
-    }
-  } else if (path == kProxyIgnoreList) {
-    net::ProxyBypassRules bypass_rules;
-    if (in_value->is_list()) {
-      const base::ListValue* list_value =
-          static_cast<const base::ListValue*>(in_value);
-      for (size_t x = 0; x < list_value->GetSize(); x++) {
-        std::string val;
-        if (list_value->GetString(x, &val))
-          bypass_rules.AddRuleFromString(val);
-      }
-      config.SetBypassRules(bypass_rules);
-    }
-  } else {
-    LOG(WARNING) << "Unknown proxy settings path " << path;
-    return;
-  }
-
-  config_service->SetProxyConfig(network_guid, config);
-}
-
-bool GetProxyPrefValue(const std::string& network_guid,
-                       const std::string& path,
-                       UIProxyConfigService* config_service,
-                       std::unique_ptr<base::Value>* out_value) {
-  std::string controlled_by;
-  std::unique_ptr<base::Value> data;
-  UIProxyConfig config;
-  config_service->GetProxyConfig(network_guid, &config);
-
-  if (path == kProxyPacUrl) {
-    // Only show pacurl for pac-script mode.
-    if (config.mode == UIProxyConfig::MODE_PAC_SCRIPT &&
-        config.automatic_proxy.pac_url.is_valid()) {
-      data =
-          std::make_unique<base::Value>(config.automatic_proxy.pac_url.spec());
-    }
-  } else if (path == kProxySingleHttp) {
-    data = CreateServerHostValue(config.single_proxy);
-  } else if (path == kProxySingleHttpPort) {
-    data = CreateServerPortValue(config.single_proxy);
-  } else if (path == kProxyHttpUrl) {
-    data = CreateServerHostValue(config.http_proxy);
-  } else if (path == kProxyHttpsUrl) {
-    data = CreateServerHostValue(config.https_proxy);
-  } else if (path == kProxyType) {
-    if (config.mode == UIProxyConfig::MODE_AUTO_DETECT ||
-        config.mode == UIProxyConfig::MODE_PAC_SCRIPT) {
-      data = std::make_unique<base::Value>(3);
-    } else if (config.mode == UIProxyConfig::MODE_SINGLE_PROXY ||
-               config.mode == UIProxyConfig::MODE_PROXY_PER_SCHEME) {
-      data = std::make_unique<base::Value>(2);
-    } else {
-      data = std::make_unique<base::Value>(1);
-    }
-    switch (config.state) {
-      case ProxyPrefs::CONFIG_POLICY:
-        controlled_by = "policy";
-        break;
-      case ProxyPrefs::CONFIG_EXTENSION:
-        controlled_by = "extension";
-        break;
-      case ProxyPrefs::CONFIG_OTHER_PRECEDE:
-        controlled_by = "other";
-        break;
-      default:
-        if (!config.user_modifiable)
-          controlled_by = "shared";
-        break;
-    }
-  } else if (path == kProxySingle) {
-    data = std::make_unique<base::Value>(config.mode ==
-                                         UIProxyConfig::MODE_SINGLE_PROXY);
-  } else if (path == kProxyUsePacUrl) {
-    data = std::make_unique<base::Value>(config.mode ==
-                                         UIProxyConfig::MODE_PAC_SCRIPT);
-  } else if (path == kProxyFtpUrl) {
-    data = CreateServerHostValue(config.ftp_proxy);
-  } else if (path == kProxySocks) {
-    data = CreateServerHostValue(config.socks_proxy);
-  } else if (path == kProxyHttpPort) {
-    data = CreateServerPortValue(config.http_proxy);
-  } else if (path == kProxyHttpsPort) {
-    data = CreateServerPortValue(config.https_proxy);
-  } else if (path == kProxyFtpPort) {
-    data = CreateServerPortValue(config.ftp_proxy);
-  } else if (path == kProxySocksPort) {
-    data = CreateServerPortValue(config.socks_proxy);
-  } else if (path == kProxyIgnoreList) {
-    auto list = std::make_unique<base::ListValue>();
-    const auto& bypass_rules = config.bypass_rules.rules();
-    for (const auto& rule : bypass_rules)
-      list->AppendString(rule->ToString());
-    data = std::move(list);
-  } else {
-    out_value->reset();
-    return false;
-  }
-
-  // Decorate pref value as CoreOptionsHandler::CreateValueForPref() does.
-  auto dict = std::make_unique<base::DictionaryValue>();
-  if (!data)
-    data = std::make_unique<base::Value>(base::Value::Type::STRING);
-  dict->Set("value", std::move(data));
-  if (path == kProxyType) {
-    if (!controlled_by.empty())
-      dict->SetString("controlledBy", controlled_by);
-    dict->SetBoolean("disabled", !config.user_modifiable);
-  } else {
-    dict->SetBoolean("disabled", false);
-  }
-  *out_value = std::move(dict);
-  return true;
-}
-
-}  // namespace proxy_cros_settings_parser
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/proxy_cros_settings_parser.h b/chrome/browser/chromeos/proxy_cros_settings_parser.h
deleted file mode 100644
index 7d427fb4..0000000
--- a/chrome/browser/chromeos/proxy_cros_settings_parser.h
+++ /dev/null
@@ -1,65 +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_CHROMEOS_PROXY_CROS_SETTINGS_PARSER_H_
-#define CHROME_BROWSER_CHROMEOS_PROXY_CROS_SETTINGS_PARSER_H_
-
-#include <stddef.h>
-
-#include <memory>
-#include <string>
-
-namespace base {
-class Value;
-}
-
-namespace chromeos {
-
-class UIProxyConfigService;
-
-// This namespace defines helper functions and pref names for setting/getting a
-// Proxy configuration. These prefs are not directly read from or written to the
-// pref store, but instead are passed to/from UIProxyConfigService.
-
-namespace proxy_cros_settings_parser {
-
-extern const char kProxyPacUrl[];
-extern const char kProxySingleHttp[];
-extern const char kProxySingleHttpPort[];
-extern const char kProxyHttpUrl[];
-extern const char kProxyHttpPort[];
-extern const char kProxyHttpsUrl[];
-extern const char kProxyHttpsPort[];
-extern const char kProxyType[];
-extern const char kProxySingle[];
-extern const char kProxyFtpUrl[];
-extern const char kProxyFtpPort[];
-extern const char kProxySocks[];
-extern const char kProxySocksPort[];
-extern const char kProxyIgnoreList[];
-extern const char kProxyUsePacUrl[];
-
-extern const char* const kProxySettings[];
-extern const size_t kProxySettingsCount;
-
-// Returns true if the supplied |path| is a proxy preference name.
-bool IsProxyPref(const std::string& path);
-
-// Sets a value in the current proxy configuration on the specified profile.
-void SetProxyPrefValue(const std::string& network_guid,
-                       const std::string& path,
-                       const base::Value* in_value,
-                       UIProxyConfigService* config_service);
-
-// Gets a value from the current proxy configuration on the specified profile.
-bool GetProxyPrefValue(const std::string& network_guid,
-                       const std::string& path,
-                       UIProxyConfigService* config_service,
-                       std::unique_ptr<base::Value>* out_value);
-
-}  // namespace proxy_cros_settings_parser
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_PROXY_CROS_SETTINGS_PARSER_H_
diff --git a/chrome/browser/conflicts/enumerate_shell_extensions_win.cc b/chrome/browser/conflicts/enumerate_shell_extensions_win.cc
index ddffcf8..8bdc6344 100644
--- a/chrome/browser/conflicts/enumerate_shell_extensions_win.cc
+++ b/chrome/browser/conflicts/enumerate_shell_extensions_win.cc
@@ -212,9 +212,6 @@
 const wchar_t kApprovedShellExtensionRegistryKey[] =
     L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved";
 
-const base::Feature kExtendedShellExtensionsEnumeration{
-    "ExtendedShellExtensionsEnumeration", base::FEATURE_DISABLED_BY_DEFAULT};
-
 void EnumerateShellExtensions(
     OnShellExtensionEnumeratedCallback on_shell_extension_enumerated,
     base::OnceClosure on_enumeration_finished) {
@@ -236,13 +233,10 @@
 
   ReadApprovedShellExtensions(HKEY_LOCAL_MACHINE, callback);
   ReadApprovedShellExtensions(HKEY_CURRENT_USER, callback);
-
-  if (base::FeatureList::IsEnabled(kExtendedShellExtensionsEnumeration)) {
-    ReadColumnHandlers(callback);
-    ReadCopyHookHandlers(callback);
-    ReadDragDropHandlers(callback);
-    ReadContextMenuAndPropertySheetHandlers(callback);
-  }
+  ReadColumnHandlers(callback);
+  ReadCopyHookHandlers(callback);
+  ReadDragDropHandlers(callback);
+  ReadContextMenuAndPropertySheetHandlers(callback);
 }
 
 }  // namespace internal
diff --git a/chrome/browser/conflicts/enumerate_shell_extensions_win.h b/chrome/browser/conflicts/enumerate_shell_extensions_win.h
index 3e728b52..85de7ef 100644
--- a/chrome/browser/conflicts/enumerate_shell_extensions_win.h
+++ b/chrome/browser/conflicts/enumerate_shell_extensions_win.h
@@ -8,7 +8,6 @@
 #include <stdint.h>
 
 #include "base/callback_forward.h"
-#include "base/feature_list.h"
 
 namespace base {
 class FilePath;
@@ -17,10 +16,6 @@
 // The path to the registry key where shell extensions are registered.
 extern const wchar_t kApprovedShellExtensionRegistryKey[];
 
-// This feature controls whether additional locations are enumerated to find
-// shell extensions in the registry.
-extern const base::Feature kExtendedShellExtensionsEnumeration;
-
 // Finds shell extensions installed on the computer by enumerating the registry.
 // In addition to the file path, the SizeOfImage and TimeDateStamp of the module
 // is returned via the |on_shell_extension_enumerated| callback.
diff --git a/chrome/browser/conflicts/enumerate_shell_extensions_win_unittest.cc b/chrome/browser/conflicts/enumerate_shell_extensions_win_unittest.cc
index 1cfe07f5..083c749 100644
--- a/chrome/browser/conflicts/enumerate_shell_extensions_win_unittest.cc
+++ b/chrome/browser/conflicts/enumerate_shell_extensions_win_unittest.cc
@@ -11,7 +11,6 @@
 #include "base/path_service.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
-#include "base/test/scoped_feature_list.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/test/test_reg_util_win.h"
 #include "chrome/browser/conflicts/module_info_util_win.h"
@@ -161,9 +160,6 @@
 }
 
 TEST_F(EnumerateShellExtensionsTest, EnumerateShellExtensionPaths) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(kExtendedShellExtensionsEnumeration);
-
   struct {
     const wchar_t* guid;
     const wchar_t* path;
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index 3563234b..a12cc69c 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -955,8 +955,10 @@
     deps += [
       "//ash",
       "//ash/public/cpp",
+      "//chromeos/attestation",
       "//chromeos/components/proximity_auth",
       "//chromeos/cryptohome",
+      "//chromeos/disks",
       "//chromeos/login/login_state",
       "//chromeos/services/ime/public/mojom",
       "//chromeos/services/machine_learning/public/cpp",
diff --git a/chrome/browser/extensions/api/passwords_private/passwords_private_api.cc b/chrome/browser/extensions/api/passwords_private/passwords_private_api.cc
index 9945e3ae6..61623f50 100644
--- a/chrome/browser/extensions/api/passwords_private/passwords_private_api.cc
+++ b/chrome/browser/extensions/api/passwords_private/passwords_private_api.cc
@@ -13,8 +13,12 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/common/extensions/api/passwords_private.h"
+#include "components/browser_sync/profile_sync_service.h"
 #include "components/password_manager/core/browser/manage_passwords_referrer.h"
+#include "components/password_manager/core/browser/password_manager_util.h"
 #include "content/public/browser/web_contents.h"
 #include "extensions/browser/extension_function_registry.h"
 
@@ -31,6 +35,15 @@
   UMA_HISTOGRAM_ENUMERATION(
       "PasswordManager.ManagePasswordsReferrer",
       password_manager::ManagePasswordsReferrer::kChromeSettings);
+  if (password_manager_util::IsSyncingWithNormalEncryption(
+          ProfileSyncServiceFactory::GetForProfile(
+              Profile::FromBrowserContext(browser_context())))) {
+    // We record this second histogram to better understand the impact of the
+    // Google Password Manager experiment for signed in and syncing users.
+    UMA_HISTOGRAM_ENUMERATION(
+        "PasswordManager.ManagePasswordsReferrerSignedInAndSyncing",
+        password_manager::ManagePasswordsReferrer::kChromeSettings);
+  }
   return RespondNow(NoArguments());
 }
 
diff --git a/chrome/browser/media/widevine_hardware_caps_win.cc b/chrome/browser/media/widevine_hardware_caps_win.cc
index ff391cc..9e3fbd1 100644
--- a/chrome/browser/media/widevine_hardware_caps_win.cc
+++ b/chrome/browser/media/widevine_hardware_caps_win.cc
@@ -14,6 +14,7 @@
 #include "base/macros.h"
 #include "base/stl_util.h"
 #include "media/base/decrypt_config.h"
+#include "media/media_buildflags.h"
 
 namespace {
 
@@ -48,6 +49,59 @@
   kCbcs = 17,
 };
 
+struct CodecToD3D11DecoderProfile {
+  media::VideoCodec video_codec;
+  GUID d3d11_decoder_profile;
+};
+
+const CodecToD3D11DecoderProfile kCodecsToQuery[] = {
+#if BUILDFLAG(USE_PROPRIETARY_CODECS)
+    {media::VideoCodec::kCodecH264, D3D11_DECODER_PROFILE_H264_VLD_NOFGT},
+#endif
+    {media::VideoCodec::kCodecVP9, D3D11_DECODER_PROFILE_VP9_VLD_PROFILE0},
+};
+
+// Use |video_device| to help check whether |d3d11_decoder_profile| is supported
+// with CENC.
+bool IsD3D11DecoderProfileSupportedWithCenc(ID3D11VideoDevice* video_device,
+                                            const GUID& d3d11_decoder_profile) {
+  D3D11_VIDEO_CONTENT_PROTECTION_CAPS caps = {};
+
+  // Check whether kD3DCryptoTypeIntelWidevine is supported with |codec|.
+  auto hresult = video_device->GetContentProtectionCaps(
+      &kD3DCryptoTypeIntelWidevine, &d3d11_decoder_profile, &caps);
+  if (FAILED(hresult)) {
+    DVLOG(1) << "Failed to GetContentProtectionCaps: " << PrintHr(hresult);
+    return false;
+  }
+
+  // For kD3DCryptoTypeIntelWidevine, this is a bitmask of IntelWidevineCaps.
+  auto capability = std::bitset<64>(caps.ProtectedMemorySize);
+  DVLOG(1) << "Content protection caps: " << capability;
+
+  if (!capability.test(IntelWidevineCaps::kSupported)) {
+    DVLOG(1) << "Hardware secure decryption not supported";
+    return false;
+  }
+
+  if (!capability.test(IntelWidevineCaps::kAesCtr)) {
+    DVLOG(1) << "AES-CTR decryption not supported";
+    return false;
+  }
+
+  // Query for CENC.
+  // TODO(crbug.com/899984): There are contents encrypted with kCencVersion1 out
+  // there, so this check is not sufficient. Update this to check kCencVersion1.
+  if (!capability.test(IntelWidevineCaps::kCencVersion3)) {
+    DVLOG(1) << "CENC version 3 not supported";
+    return false;
+  }
+
+  DVLOG(1) << "Widevine hardware secure CENC-v3 decryption supported. CENC-v1 "
+              "playback may fail!";
+  return true;
+}
+
 }  // namespace
 
 void GetWidevineHardwareCaps(
@@ -70,7 +124,7 @@
   // D3D11CdmProxy requires D3D_FEATURE_LEVEL_11_1.
   const D3D_FEATURE_LEVEL feature_levels[] = {D3D_FEATURE_LEVEL_11_1};
 
-  // Create device and pupulate |device|.
+  // Create device and populate |device|.
   HRESULT hresult = D3D11CreateDevice(
       nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, feature_levels,
       base::size(feature_levels), D3D11_SDK_VERSION, device.GetAddressOf(),
@@ -87,43 +141,16 @@
     return;
   }
 
-  D3D11_VIDEO_CONTENT_PROTECTION_CAPS caps = {};
+  // TODO(xhwang): Support query for CBCS. Maybe return all encryption schemes
+  // supported by a codec.
 
-  // Check whether kD3DCryptoTypeIntelWidevine is supported with H264 codec.
-  // TODO(xhwang): Support query for VP9.
-  hresult = video_device->GetContentProtectionCaps(
-      &kD3DCryptoTypeIntelWidevine, &D3D11_DECODER_PROFILE_H264_VLD_NOFGT,
-      &caps);
-  if (FAILED(hresult)) {
-    DVLOG(1) << "Failed to GetContentProtectionCaps: " << PrintHr(hresult);
-    return;
+  for (const auto& entry : kCodecsToQuery) {
+    if (IsD3D11DecoderProfileSupportedWithCenc(video_device.Get(),
+                                               entry.d3d11_decoder_profile)) {
+      video_codecs->insert(entry.video_codec);
+    }
   }
 
-  // For kD3DCryptoTypeIntelWidevine, this is a bitmask of IntelWidevineCaps.
-  auto capability = std::bitset<64>(caps.ProtectedMemorySize);
-  DVLOG(1) << "Content protection caps: " << capability;
-
-  if (!capability.test(IntelWidevineCaps::kSupported)) {
-    DVLOG(1) << "Hardware secure decryption not supported";
-    return;
-  }
-
-  // TODO(xhwang): Support query for CBCS.
-  if (!capability.test(IntelWidevineCaps::kAesCtr)) {
-    DVLOG(1) << "AES-CTR decryption not supported";
-    return;
-  }
-
-  // Query for CENC.
-  // TODO(crbug.com/899984): There are contents encrypted with kCencVersion1 out
-  // there, so this check is not sufficient. Update this to check kCencVersion1.
-  if (!capability.test(IntelWidevineCaps::kCencVersion3)) {
-    DVLOG(1) << "CENC version 3 not supported";
-    return;
-  }
-
-  DVLOG(1) << "Widevine hardware secure H264 CENC-v3 decryption supported. "
-              "CENC-v1 playback may fail!";
-  video_codecs->insert(media::VideoCodec::kCodecH264);
-  encryption_schemes->insert(media::EncryptionMode::kCenc);
+  if (!video_codecs->empty())
+    encryption_schemes->insert(media::EncryptionMode::kCenc);
 }
diff --git a/chrome/browser/media/widevine_hardware_caps_win_unittest.cc b/chrome/browser/media/widevine_hardware_caps_win_unittest.cc
index 4149e9a..7475e04 100644
--- a/chrome/browser/media/widevine_hardware_caps_win_unittest.cc
+++ b/chrome/browser/media/widevine_hardware_caps_win_unittest.cc
@@ -6,6 +6,9 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 
+// TODO(xhwang): Add tests using D3D11 mocks. Currently this cannot be done
+// because we cannot depend on media/gpu/windows/d3d11_mocks.*.
+
 TEST(WidevineHardwareCapsTest, GetWidevineHardwareCaps) {
   base::flat_set<media::CdmProxy::Protocol> cdm_proxy_protocols = {
       media::CdmProxy::Protocol::kIntel};
diff --git a/chrome/browser/metrics/ukm_browsertest.cc b/chrome/browser/metrics/ukm_browsertest.cc
index 1648a6dee..a128b08 100644
--- a/chrome/browser/metrics/ukm_browsertest.cc
+++ b/chrome/browser/metrics/ukm_browsertest.cc
@@ -20,7 +20,7 @@
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
-#include "chrome/browser/sync/test/integration/secondary_account_helper.h"
+#include "chrome/browser/sync/test/integration/secondary_account_sync_test.h"
 #include "chrome/browser/sync/test/integration/single_client_status_change_checker.h"
 #include "chrome/browser/sync/test/integration/sync_test.h"
 #include "chrome/browser/ui/browser.h"
@@ -144,10 +144,10 @@
 };
 
 // Test fixture that provides access to some UKM internals.
-class UkmBrowserTestBase : public SyncTest {
+class UkmBrowserTestBase : public SecondaryAccountSyncTest {
  public:
   explicit UkmBrowserTestBase(bool is_unified_consent_enabled)
-      : SyncTest(SINGLE_CLIENT),
+      :
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
         scoped_dice_(is_unified_consent_enabled
                          ? std::make_unique<ScopedAccountConsistencyDice>()
@@ -336,18 +336,9 @@
                                {});
   }
 
-  void SetUpInProcessBrowserTestFixture() override {
-    // This is required to support (fake) secondary-account-signin (based on
-    // cookies) in tests. Without this, the real GaiaCookieManagerService would
-    // try talking to Google servers which of course wouldn't work in tests.
-    fake_gaia_cookie_manager_factory_ =
-        secondary_account_helper::SetUpFakeGaiaCookieManagerService();
-    UkmBrowserTest::SetUpInProcessBrowserTestFixture();
-  }
-
   void SetUpOnMainThread() override {
 #if defined(OS_CHROMEOS)
-    secondary_account_helper::InitNetwork();
+    InitNetwork();
 #endif  // defined(OS_CHROMEOS)
     UkmBrowserTest::SetUpOnMainThread();
   }
@@ -355,9 +346,6 @@
  private:
   base::test::ScopedFeatureList features_;
 
-  secondary_account_helper::ScopedFakeGaiaCookieManagerServiceFactory
-      fake_gaia_cookie_manager_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(UkmBrowserTestWithSyncTransport);
 };
 
@@ -1174,8 +1162,7 @@
   browser_sync::ProfileSyncService* sync_service =
       ProfileSyncServiceFactory::GetForProfile(profile);
 
-  secondary_account_helper::SignInSecondaryAccount(profile,
-                                                   "secondary_user@email.com");
+  SignInSecondaryAccount(profile, "secondary_user@email.com");
   ASSERT_NE(syncer::SyncService::TransportState::DISABLED,
             sync_service->GetTransportState());
   ASSERT_TRUE(harness->AwaitSyncSetupCompletion(
diff --git a/chrome/browser/offline_pages/android/auto_fetch_notifier.cc b/chrome/browser/offline_pages/android/auto_fetch_notifier.cc
new file mode 100644
index 0000000..9edf1dc
--- /dev/null
+++ b/chrome/browser/offline_pages/android/auto_fetch_notifier.cc
@@ -0,0 +1,31 @@
+// Copyright 2019 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/offline_pages/android/auto_fetch_notifier.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/offline_pages/android/offline_page_auto_fetcher_service.h"
+#include "chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_android.h"
+#include "jni/AutoFetchNotifier_jni.h"
+
+namespace offline_pages {
+
+void ShowAutoFetchCompleteNotification(const base::string16& pageTitle,
+                                       const std::string& url,
+                                       int android_tab_id,
+                                       int64_t offline_id) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  Java_AutoFetchNotifier_showCompleteNotification(
+      env,
+      base::android::ConvertUTF8ToJavaString(env, base::UTF16ToUTF8(pageTitle)),
+      base::android::ConvertUTF8ToJavaString(env, url), android_tab_id,
+      offline_id);
+}
+
+}  // namespace offline_pages
diff --git a/chrome/browser/offline_pages/android/auto_fetch_notifier.h b/chrome/browser/offline_pages/android/auto_fetch_notifier.h
new file mode 100644
index 0000000..8789fe5
--- /dev/null
+++ b/chrome/browser/offline_pages/android/auto_fetch_notifier.h
@@ -0,0 +1,23 @@
+// Copyright 2019 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_OFFLINE_PAGES_ANDROID_AUTO_FETCH_NOTIFIER_H_
+#define CHROME_BROWSER_OFFLINE_PAGES_ANDROID_AUTO_FETCH_NOTIFIER_H_
+
+#include <string>
+
+#include "base/strings/string16.h"
+
+namespace offline_pages {
+
+// Functions for calling into AutoFetchNotifier.java.
+
+void ShowAutoFetchCompleteNotification(const base::string16& pageTitle,
+                                       const std::string& originalUrl,
+                                       int android_tab_id,
+                                       int64_t offline_id);
+
+}  // namespace offline_pages
+
+#endif  // CHROME_BROWSER_OFFLINE_PAGES_ANDROID_AUTO_FETCH_NOTIFIER_H_
diff --git a/chrome/browser/offline_pages/auto_fetch_page_load_watcher.cc b/chrome/browser/offline_pages/android/auto_fetch_page_load_watcher.cc
similarity index 93%
rename from chrome/browser/offline_pages/auto_fetch_page_load_watcher.cc
rename to chrome/browser/offline_pages/android/auto_fetch_page_load_watcher.cc
index f530ca53..1ea1a52 100644
--- a/chrome/browser/offline_pages/auto_fetch_page_load_watcher.cc
+++ b/chrome/browser/offline_pages/android/auto_fetch_page_load_watcher.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/offline_pages/auto_fetch_page_load_watcher.h"
+#include "chrome/browser/offline_pages/android/auto_fetch_page_load_watcher.h"
 
 #include <memory>
 
 #include "base/macros.h"
-#include "chrome/browser/offline_pages/offline_page_auto_fetcher.h"
-#include "chrome/browser/offline_pages/offline_page_auto_fetcher_service.h"
-#include "chrome/browser/offline_pages/offline_page_auto_fetcher_service_factory.h"
+#include "chrome/browser/offline_pages/android/offline_page_auto_fetcher.h"
+#include "chrome/browser/offline_pages/android/offline_page_auto_fetcher_service.h"
+#include "chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_factory.h"
 #include "chrome/browser/offline_pages/request_coordinator_factory.h"
 #include "components/offline_pages/core/background/request_coordinator.h"
 #include "components/offline_pages/core/client_namespace_constants.h"
diff --git a/chrome/browser/offline_pages/auto_fetch_page_load_watcher.h b/chrome/browser/offline_pages/android/auto_fetch_page_load_watcher.h
similarity index 91%
rename from chrome/browser/offline_pages/auto_fetch_page_load_watcher.h
rename to chrome/browser/offline_pages/android/auto_fetch_page_load_watcher.h
index fa70625..9f19eb2 100644
--- a/chrome/browser/offline_pages/auto_fetch_page_load_watcher.h
+++ b/chrome/browser/offline_pages/android/auto_fetch_page_load_watcher.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_OFFLINE_PAGES_AUTO_FETCH_PAGE_LOAD_WATCHER_H_
-#define CHROME_BROWSER_OFFLINE_PAGES_AUTO_FETCH_PAGE_LOAD_WATCHER_H_
+#ifndef CHROME_BROWSER_OFFLINE_PAGES_ANDROID_AUTO_FETCH_PAGE_LOAD_WATCHER_H_
+#define CHROME_BROWSER_OFFLINE_PAGES_ANDROID_AUTO_FETCH_PAGE_LOAD_WATCHER_H_
 
 #include <map>
 #include <memory>
@@ -73,4 +73,4 @@
 
 }  // namespace offline_pages
 
-#endif  // CHROME_BROWSER_OFFLINE_PAGES_AUTO_FETCH_PAGE_LOAD_WATCHER_H_
+#endif  // CHROME_BROWSER_OFFLINE_PAGES_ANDROID_AUTO_FETCH_PAGE_LOAD_WATCHER_H_
diff --git a/chrome/browser/offline_pages/auto_fetch_page_load_watcher_unittest.cc b/chrome/browser/offline_pages/android/auto_fetch_page_load_watcher_unittest.cc
similarity index 98%
rename from chrome/browser/offline_pages/auto_fetch_page_load_watcher_unittest.cc
rename to chrome/browser/offline_pages/android/auto_fetch_page_load_watcher_unittest.cc
index 685f905..231fc047 100644
--- a/chrome/browser/offline_pages/auto_fetch_page_load_watcher_unittest.cc
+++ b/chrome/browser/offline_pages/android/auto_fetch_page_load_watcher_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/offline_pages/auto_fetch_page_load_watcher.h"
+#include "chrome/browser/offline_pages/android/auto_fetch_page_load_watcher.h"
 
 #include <memory>
 #include <string>
diff --git a/chrome/browser/offline_pages/android/background_scheduler_bridge.cc b/chrome/browser/offline_pages/android/background_scheduler_bridge.cc
index 9aebb16..801c3b6 100644
--- a/chrome/browser/offline_pages/android/background_scheduler_bridge.cc
+++ b/chrome/browser/offline_pages/android/background_scheduler_bridge.cc
@@ -6,6 +6,7 @@
 
 #include "base/android/callback_android.h"
 #include "base/android/scoped_java_ref.h"
+#include "chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_factory.h"
 #include "chrome/browser/offline_pages/offline_page_model_factory.h"
 #include "chrome/browser/offline_pages/request_coordinator_factory.h"
 #include "chrome/browser/profiles/profile.h"
@@ -32,9 +33,16 @@
   ScopedJavaGlobalRef<jobject> j_callback_ref;
   j_callback_ref.Reset(env, j_callback_obj);
 
+  Profile* profile = ProfileManager::GetLastUsedProfile();
+  if (!profile)
+    return false;
+
+  // Make sure the auto-fetch service is running, so it can respond to completed
+  // pages.
+  OfflinePageAutoFetcherServiceFactory::GetForBrowserContext(profile);
+
   // Lookup/create RequestCoordinator KeyedService and call
   // StartScheduledProcessing on it with bound j_callback_obj.
-  Profile* profile = ProfileManager::GetLastUsedProfile();
   RequestCoordinator* coordinator =
       RequestCoordinatorFactory::GetInstance()->
       GetForBrowserContext(profile);
@@ -52,6 +60,8 @@
 // JNI call to stop request processing in scheduled mode.
 static void JNI_BackgroundSchedulerBridge_StopScheduledProcessing(JNIEnv* env) {
   Profile* profile = ProfileManager::GetLastUsedProfile();
+  if (!profile)
+    return;
   RequestCoordinator* coordinator =
       RequestCoordinatorFactory::GetInstance()->GetForBrowserContext(profile);
   DVLOG(2) << "resource_coordinator: " << coordinator;
diff --git a/chrome/browser/offline_pages/offline_page_auto_fetcher.cc b/chrome/browser/offline_pages/android/offline_page_auto_fetcher.cc
similarity index 90%
rename from chrome/browser/offline_pages/offline_page_auto_fetcher.cc
rename to chrome/browser/offline_pages/android/offline_page_auto_fetcher.cc
index 521cdf8..7242d52 100644
--- a/chrome/browser/offline_pages/offline_page_auto_fetcher.cc
+++ b/chrome/browser/offline_pages/android/offline_page_auto_fetcher.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/offline_pages/offline_page_auto_fetcher.h"
+#include "chrome/browser/offline_pages/android/offline_page_auto_fetcher.h"
 
 #include <utility>
 
 #include "chrome/browser/android/tab_android.h"
-#include "chrome/browser/offline_pages/offline_page_auto_fetcher_service.h"
-#include "chrome/browser/offline_pages/offline_page_auto_fetcher_service_factory.h"
+#include "chrome/browser/offline_pages/android/offline_page_auto_fetcher_service.h"
+#include "chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_factory.h"
 #include "chrome/browser/ui/android/tab_model/tab_model.h"
 #include "chrome/browser/ui/android/tab_model/tab_model_list.h"
 #include "content/public/browser/render_frame_host.h"
diff --git a/chrome/browser/offline_pages/offline_page_auto_fetcher.h b/chrome/browser/offline_pages/android/offline_page_auto_fetcher.h
similarity index 80%
rename from chrome/browser/offline_pages/offline_page_auto_fetcher.h
rename to chrome/browser/offline_pages/android/offline_page_auto_fetcher.h
index 0f05c5f..e39387a 100644
--- a/chrome/browser/offline_pages/offline_page_auto_fetcher.h
+++ b/chrome/browser/offline_pages/android/offline_page_auto_fetcher.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_OFFLINE_PAGES_OFFLINE_PAGE_AUTO_FETCHER_H_
-#define CHROME_BROWSER_OFFLINE_PAGES_OFFLINE_PAGE_AUTO_FETCHER_H_
+#ifndef CHROME_BROWSER_OFFLINE_PAGES_ANDROID_OFFLINE_PAGE_AUTO_FETCHER_H_
+#define CHROME_BROWSER_OFFLINE_PAGES_ANDROID_OFFLINE_PAGE_AUTO_FETCHER_H_
 
 #include <memory>
 #include <queue>
@@ -26,8 +26,7 @@
  public:
   explicit OfflinePageAutoFetcher(content::RenderFrameHost* render_frame_host);
   ~OfflinePageAutoFetcher() override;
-  void TrySchedule(bool user_requested,
-                   TryScheduleCallback callback) override;
+  void TrySchedule(bool user_requested, TryScheduleCallback callback) override;
   void CancelSchedule() override;
 
   static void Create(chrome::mojom::OfflinePageAutoFetcherRequest request,
@@ -44,4 +43,4 @@
 
 }  // namespace offline_pages
 
-#endif  // CHROME_BROWSER_OFFLINE_PAGES_OFFLINE_PAGE_AUTO_FETCHER_H_
+#endif  // CHROME_BROWSER_OFFLINE_PAGES_ANDROID_OFFLINE_PAGE_AUTO_FETCHER_H_
diff --git a/chrome/browser/offline_pages/offline_page_auto_fetcher_service.cc b/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service.cc
similarity index 82%
rename from chrome/browser/offline_pages/offline_page_auto_fetcher_service.cc
rename to chrome/browser/offline_pages/android/offline_page_auto_fetcher_service.cc
index 87d607e9..423219f4 100644
--- a/chrome/browser/offline_pages/offline_page_auto_fetcher_service.cc
+++ b/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service.cc
@@ -2,14 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/offline_pages/offline_page_auto_fetcher_service.h"
+#include "chrome/browser/offline_pages/android/offline_page_auto_fetcher_service.h"
 
 #include <string>
 #include <utility>
 
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
 #include "base/optional.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "chrome/browser/offline_pages/request_coordinator_factory.h"
 #include "components/offline_pages/core/auto_fetch.h"
@@ -45,6 +48,7 @@
   }
   return nullptr;
 }
+
 }  // namespace
 
 // This is an attempt to verify that a task callback eventually calls
@@ -70,10 +74,21 @@
 };
 
 OfflinePageAutoFetcherService::OfflinePageAutoFetcherService(
-    RequestCoordinator* request_coordinator)
+    RequestCoordinator* request_coordinator,
+    OfflinePageModel* offline_page_model,
+    Delegate* delegate)
     : page_load_watcher_(request_coordinator),
-      request_coordinator_(request_coordinator) {}
-OfflinePageAutoFetcherService::~OfflinePageAutoFetcherService() {}
+      request_coordinator_(request_coordinator),
+      offline_page_model_(offline_page_model),
+      delegate_(delegate) {
+  request_coordinator_->AddObserver(this);
+}
+
+OfflinePageAutoFetcherService::~OfflinePageAutoFetcherService() = default;
+
+void OfflinePageAutoFetcherService::Shutdown() {
+  request_coordinator_->RemoveObserver(this);
+}
 
 void OfflinePageAutoFetcherService::TrySchedule(bool user_requested,
                                                 const GURL& url,
@@ -144,7 +159,6 @@
       return;
     }
   }
-
   // Finally, schedule a new request, and proceed to step 3.
   RequestCoordinator::SavePageLaterParams params;
   params.url = url;
@@ -222,4 +236,34 @@
   return task_queue_.empty();
 }
 
+void OfflinePageAutoFetcherService::OnCompleted(
+    const SavePageRequest& request,
+    RequestNotifier::BackgroundSavePageResult status) {
+  if (request.client_id().name_space != kAutoAsyncNamespace ||
+      status != RequestNotifier::BackgroundSavePageResult::SUCCESS)
+    return;
+
+  offline_page_model_->GetPageByOfflineId(
+      request.request_id(),
+      base::BindOnce(&OfflinePageAutoFetcherService::AutoFetchComplete,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+void OfflinePageAutoFetcherService::AutoFetchComplete(
+    const OfflinePageItem* page) {
+  if (!page)
+    return;
+  base::Optional<auto_fetch::ClientIdMetadata> metadata =
+      auto_fetch::ExtractMetadata(page->client_id);
+  if (!metadata)
+    return;
+
+  const GURL& url =
+      page->original_url.is_empty() ? page->url : page->original_url;
+
+  delegate_->ShowAutoFetchCompleteNotification(page->title, url.spec(),
+                                               metadata.value().android_tab_id,
+                                               page->offline_id);
+}
+
 }  // namespace offline_pages
diff --git a/chrome/browser/offline_pages/offline_page_auto_fetcher_service.h b/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service.h
similarity index 71%
rename from chrome/browser/offline_pages/offline_page_auto_fetcher_service.h
rename to chrome/browser/offline_pages/android/offline_page_auto_fetcher_service.h
index 2904452..162cf76 100644
--- a/chrome/browser/offline_pages/offline_page_auto_fetcher_service.h
+++ b/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_OFFLINE_PAGES_OFFLINE_PAGE_AUTO_FETCHER_SERVICE_H_
-#define CHROME_BROWSER_OFFLINE_PAGES_OFFLINE_PAGE_AUTO_FETCHER_SERVICE_H_
+#ifndef CHROME_BROWSER_OFFLINE_PAGES_ANDROID_OFFLINE_PAGE_AUTO_FETCHER_SERVICE_H_
+#define CHROME_BROWSER_OFFLINE_PAGES_ANDROID_OFFLINE_PAGE_AUTO_FETCHER_SERVICE_H_
 
 #include <memory>
 #include <utility>
@@ -11,10 +11,12 @@
 
 #include "base/callback_forward.h"
 #include "base/memory/weak_ptr.h"
-#include "chrome/browser/offline_pages/auto_fetch_page_load_watcher.h"
+#include "chrome/browser/offline_pages/android/auto_fetch_page_load_watcher.h"
 #include "chrome/common/offline_page_auto_fetcher.mojom.h"
 #include "components/keyed_service/core/keyed_service.h"
+#include "components/offline_pages/core/background/request_coordinator.h"
 #include "components/offline_pages/core/background/request_queue_results.h"
+#include "components/offline_pages/core/offline_page_model.h"
 #include "url/gurl.h"
 
 namespace offline_pages {
@@ -44,17 +46,33 @@
 // Additionally, save page requests are removed upon successful navigation
 // commit. See |AutoFetchPageLoadWatcher|.
 
-// A KeyedService that provides an interface to schedule and cancel auto-fetch
-// requests.
-class OfflinePageAutoFetcherService : public KeyedService {
+// A KeyedService for the auto-fetch feature.
+// * Provides an interface to schedule and cancel auto-fetch requests.
+// * Listens for complete fetches with RequestCoordinator::Observer, and
+//   triggers the system notification.
+class OfflinePageAutoFetcherService : public KeyedService,
+                                      public RequestCoordinator::Observer {
  public:
   using OfflinePageAutoFetcherScheduleResult =
       chrome::mojom::OfflinePageAutoFetcherScheduleResult;
   using TryScheduleCallback = base::OnceCallback<void(
       chrome::mojom::OfflinePageAutoFetcherScheduleResult)>;
 
+  // Injected interface for testing.
+  class Delegate {
+   public:
+    // Calls |offline_pages::ShowAutoFetchCompleteNotification()|.
+    virtual void ShowAutoFetchCompleteNotification(
+        const base::string16& pageTitle,
+        const std::string& url,
+        int android_tab_id,
+        int64_t offline_id) = 0;
+  };
+
   explicit OfflinePageAutoFetcherService(
-      RequestCoordinator* request_coordinator);
+      RequestCoordinator* request_coordinator,
+      OfflinePageModel* offline_page_model,
+      Delegate* delegate);
   ~OfflinePageAutoFetcherService() override;
 
   AutoFetchPageLoadWatcher* page_load_watcher() { return &page_load_watcher_; }
@@ -69,11 +87,19 @@
 
   // KeyedService implementation.
 
-  void Shutdown() override {}
+  void Shutdown() override;
 
   // Testing methods.
   bool IsTaskQueueEmptyForTesting();
 
+  // RequestCoordinator::Observer implementation.
+  void OnAdded(const SavePageRequest& request) override {}
+  void OnCompleted(const SavePageRequest& request,
+                   RequestNotifier::BackgroundSavePageResult status) override;
+  void OnChanged(const SavePageRequest& request) override {}
+  void OnNetworkProgress(const SavePageRequest& request,
+                         int64_t received_bytes) override {}
+
  private:
   class TaskToken;
   using TaskCallback = base::OnceCallback<void(TaskToken)>;
@@ -118,8 +144,12 @@
       std::vector<std::unique_ptr<SavePageRequest>> requests);
   void CancelScheduleStep3(TaskToken token, const MultipleItemStatuses&);
 
+  void AutoFetchComplete(const OfflinePageItem* page);
+
   AutoFetchPageLoadWatcher page_load_watcher_;
   RequestCoordinator* request_coordinator_;
+  OfflinePageModel* offline_page_model_;
+  Delegate* delegate_;
   // TODO(harringtond): Pull out task management into another class, or use
   // offline_pages::TaskQueue.
   std::queue<TaskCallback> task_queue_;
@@ -127,4 +157,5 @@
 };
 
 }  // namespace offline_pages
-#endif  // CHROME_BROWSER_OFFLINE_PAGES_OFFLINE_PAGE_AUTO_FETCHER_SERVICE_H_
+
+#endif  // CHROME_BROWSER_OFFLINE_PAGES_ANDROID_OFFLINE_PAGE_AUTO_FETCHER_SERVICE_H_
diff --git a/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_factory.cc b/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_factory.cc
new file mode 100644
index 0000000..0d5c3ef
--- /dev/null
+++ b/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_factory.cc
@@ -0,0 +1,67 @@
+// 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 "chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_factory.h"
+
+#include "base/memory/singleton.h"
+#include "chrome/browser/offline_pages/android/auto_fetch_notifier.h"
+#include "chrome/browser/offline_pages/android/offline_page_auto_fetcher_service.h"
+#include "chrome/browser/offline_pages/offline_page_model_factory.h"
+#include "chrome/browser/offline_pages/request_coordinator_factory.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+
+namespace offline_pages {
+
+class OfflinePageAutoFetcherServiceFactory::ServiceDelegate final
+    : public OfflinePageAutoFetcherService::Delegate {
+  void ShowAutoFetchCompleteNotification(const base::string16& pageTitle,
+                                         const std::string& url,
+                                         int android_tab_id,
+                                         int64_t offline_id) override {
+    offline_pages::ShowAutoFetchCompleteNotification(
+        pageTitle, url, android_tab_id, offline_id);
+  }
+};
+
+// static
+OfflinePageAutoFetcherServiceFactory*
+OfflinePageAutoFetcherServiceFactory::GetInstance() {
+  return base::Singleton<OfflinePageAutoFetcherServiceFactory>::get();
+}
+
+// static
+OfflinePageAutoFetcherService*
+OfflinePageAutoFetcherServiceFactory::GetForBrowserContext(
+    content::BrowserContext* context) {
+  KeyedService* service =
+      GetInstance()->GetServiceForBrowserContext(context, true);
+  if (!service)
+    return nullptr;
+  return static_cast<OfflinePageAutoFetcherService*>(service);
+}
+
+OfflinePageAutoFetcherServiceFactory::OfflinePageAutoFetcherServiceFactory()
+    : BrowserContextKeyedServiceFactory(
+          "OfflinePageAutoFetcherService",
+          BrowserContextDependencyManager::GetInstance()),
+      service_delegate_(
+          std::make_unique<
+              OfflinePageAutoFetcherServiceFactory::ServiceDelegate>()) {
+  DependsOn(RequestCoordinatorFactory::GetInstance());
+  DependsOn(OfflinePageModelFactory::GetInstance());
+}
+
+OfflinePageAutoFetcherServiceFactory::~OfflinePageAutoFetcherServiceFactory() {}
+
+KeyedService* OfflinePageAutoFetcherServiceFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  RequestCoordinator* coordinator =
+      RequestCoordinatorFactory::GetForBrowserContext(context);
+  OfflinePageModel* model =
+      OfflinePageModelFactory::GetForBrowserContext(context);
+  return new OfflinePageAutoFetcherService(coordinator, model,
+                                           service_delegate_.get());
+}
+
+}  // namespace offline_pages
diff --git a/chrome/browser/offline_pages/offline_page_auto_fetcher_service_factory.h b/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_factory.h
similarity index 76%
rename from chrome/browser/offline_pages/offline_page_auto_fetcher_service_factory.h
rename to chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_factory.h
index b02ecbd9d..14a7bbf4 100644
--- a/chrome/browser/offline_pages/offline_page_auto_fetcher_service_factory.h
+++ b/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_factory.h
@@ -2,9 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_OFFLINE_PAGES_OFFLINE_PAGE_AUTO_FETCHER_SERVICE_FACTORY_H_
-#define CHROME_BROWSER_OFFLINE_PAGES_OFFLINE_PAGE_AUTO_FETCHER_SERVICE_FACTORY_H_
+#ifndef CHROME_BROWSER_OFFLINE_PAGES_ANDROID_OFFLINE_PAGE_AUTO_FETCHER_SERVICE_FACTORY_H_
+#define CHROME_BROWSER_OFFLINE_PAGES_ANDROID_OFFLINE_PAGE_AUTO_FETCHER_SERVICE_FACTORY_H_
 
+#include <memory>
 #include "base/macros.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 #include "content/public/browser/browser_context.h"
@@ -26,6 +27,7 @@
       content::BrowserContext* context);
 
  private:
+  class ServiceDelegate;
   friend struct base::DefaultSingletonTraits<
       OfflinePageAutoFetcherServiceFactory>;
 
@@ -35,9 +37,10 @@
   KeyedService* BuildServiceInstanceFor(
       content::BrowserContext* context) const override;
 
+  std::unique_ptr<ServiceDelegate> service_delegate_;
   DISALLOW_COPY_AND_ASSIGN(OfflinePageAutoFetcherServiceFactory);
 };
 
 }  // namespace offline_pages
 
-#endif  // CHROME_BROWSER_OFFLINE_PAGES_OFFLINE_PAGE_AUTO_FETCHER_SERVICE_FACTORY_H_
+#endif  // CHROME_BROWSER_OFFLINE_PAGES_ANDROID_OFFLINE_PAGE_AUTO_FETCHER_SERVICE_FACTORY_H_
diff --git a/chrome/browser/offline_pages/offline_page_auto_fetcher_service_unittest.cc b/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_unittest.cc
similarity index 67%
rename from chrome/browser/offline_pages/offline_page_auto_fetcher_service_unittest.cc
rename to chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_unittest.cc
index 203457e4..739d8ec 100644
--- a/chrome/browser/offline_pages/offline_page_auto_fetcher_service_unittest.cc
+++ b/chrome/browser/offline_pages/android/offline_page_auto_fetcher_service_unittest.cc
@@ -2,18 +2,22 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/offline_pages/offline_page_auto_fetcher_service.h"
+#include "chrome/browser/offline_pages/android/offline_page_auto_fetcher_service.h"
 
 #include "base/bind.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/test/bind_test_util.h"
 #include "base/test/mock_callback.h"
+#include "chrome/browser/offline_pages/offline_page_model_factory.h"
 #include "chrome/browser/offline_pages/request_coordinator_factory.h"
 #include "chrome/browser/offline_pages/test_request_coordinator_builder.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
+#include "components/offline_pages/core/auto_fetch.h"
 #include "components/offline_pages/core/background/request_coordinator.h"
 #include "components/offline_pages/core/background/test_request_queue_store.h"
 #include "components/offline_pages/core/client_namespace_constants.h"
+#include "components/offline_pages/core/stub_offline_page_model.h"
 #include "content/public/test/navigation_simulator.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -21,19 +25,50 @@
 
 namespace offline_pages {
 namespace {
-const int kTabId = 1;
+using testing::_;
 using OfflinePageAutoFetcherScheduleResult =
     chrome::mojom::OfflinePageAutoFetcherScheduleResult;
 
+const int kTabId = 1;
+ClientId TestClientId() {
+  return auto_fetch::MakeClientId(auto_fetch::ClientIdMetadata(kTabId));
+}
+SavePageRequest TestRequest(ClientId client_id = TestClientId()) {
+  return SavePageRequest(123, GURL("http://www.url.com"), client_id,
+                         base::Time(), true);
+}
+
+class MockDelegate : public OfflinePageAutoFetcherService::Delegate {
+ public:
+  MOCK_METHOD4(ShowAutoFetchCompleteNotification,
+               void(const base::string16& pageTitle,
+                    const std::string& url,
+                    int android_tab_id,
+                    int64_t offline_id));
+};
+
+class TestOfflinePageModel : public StubOfflinePageModel {
+ public:
+  // Change signature for the mocked method to make it easier to use.
+  MOCK_METHOD1(GetPageByOfflineId_, OfflinePageItem*(int64_t offline_id));
+  void GetPageByOfflineId(int64_t offline_id,
+                          SingleOfflinePageItemCallback callback) override {
+    std::move(callback).Run(GetPageByOfflineId_(offline_id));
+  }
+};
+
 class OfflinePageAutoFetcherServiceTest : public testing::Test {
  public:
   void SetUp() override {
     RequestCoordinator* coordinator = static_cast<RequestCoordinator*>(
         RequestCoordinatorFactory::GetInstance()->SetTestingFactoryAndUse(
             &profile_, base::BindRepeating(&BuildTestRequestCoordinator)));
+
     queue_store_ = static_cast<TestRequestQueueStore*>(
         coordinator->queue_for_testing()->GetStoreForTesting());
-    service_ = std::make_unique<OfflinePageAutoFetcherService>(coordinator);
+
+    service_ = std::make_unique<OfflinePageAutoFetcherService>(
+        coordinator, &offline_page_model_, &delegate_);
   }
 
   void TearDown() override {
@@ -59,6 +94,8 @@
 
  protected:
   content::TestBrowserThreadBundle browser_thread_bundle_;
+  MockDelegate delegate_;
+  TestOfflinePageModel offline_page_model_;
   TestingProfile profile_;
 
   // Owned by the request queue.
@@ -186,5 +223,49 @@
   browser_thread_bundle_.RunUntilIdle();
 }
 
+// Simulate a completed auto fetch request, and verify that
+// ShowAutoFetchCompleteNotification() is called on the delegate.
+TEST_F(OfflinePageAutoFetcherServiceTest, NotifyOnAutoFetchCompleted) {
+  const SavePageRequest kTestRequest = TestRequest();
+  const int64_t kOfflineId = 1234;
+  OfflinePageItem returned_item(kTestRequest.url(), kOfflineId,
+                                kTestRequest.client_id(), base::FilePath(),
+                                2000);
+  returned_item.title = base::ASCIIToUTF16("Cows");
+  EXPECT_CALL(offline_page_model_,
+              GetPageByOfflineId_(kTestRequest.request_id()))
+      .WillOnce(testing::Return(&returned_item));
+  EXPECT_CALL(delegate_, ShowAutoFetchCompleteNotification(
+                             returned_item.title, kTestRequest.url().spec(),
+                             kTabId, kOfflineId));
+  service_->OnCompleted(kTestRequest,
+                        RequestNotifier::BackgroundSavePageResult::SUCCESS);
+
+  browser_thread_bundle_.RunUntilIdle();
+}
+
+// Simulate a failed auto-fetch request, and verify that
+// it is ignored.
+TEST_F(OfflinePageAutoFetcherServiceTest, DontNotifyOnAutoFetchFail) {
+  const SavePageRequest kTestRequest = TestRequest();
+  EXPECT_CALL(offline_page_model_, GetPageByOfflineId_(_)).Times(0);
+  service_->OnCompleted(
+      kTestRequest, RequestNotifier::BackgroundSavePageResult::LOADING_FAILURE);
+
+  browser_thread_bundle_.RunUntilIdle();
+}
+
+// Simulate a completed non-auto-fetch request, and verify that
+// it is ignored.
+TEST_F(OfflinePageAutoFetcherServiceTest, DontNotifyOnOtherRequestCompleted) {
+  const ClientId kClientId("other-namespace", "id");
+  const SavePageRequest kTestRequest = TestRequest(kClientId);
+  EXPECT_CALL(offline_page_model_, GetPageByOfflineId_(_)).Times(0);
+  service_->OnCompleted(kTestRequest,
+                        RequestNotifier::BackgroundSavePageResult::SUCCESS);
+
+  browser_thread_bundle_.RunUntilIdle();
+}
+
 }  // namespace
 }  // namespace offline_pages
diff --git a/chrome/browser/offline_pages/offline_page_auto_fetcher_service_factory.cc b/chrome/browser/offline_pages/offline_page_auto_fetcher_service_factory.cc
deleted file mode 100644
index 5ad9b57d..0000000
--- a/chrome/browser/offline_pages/offline_page_auto_fetcher_service_factory.cc
+++ /dev/null
@@ -1,47 +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 "chrome/browser/offline_pages/offline_page_auto_fetcher_service_factory.h"
-
-#include "base/memory/singleton.h"
-#include "chrome/browser/offline_pages/offline_page_auto_fetcher_service.h"
-#include "chrome/browser/offline_pages/request_coordinator_factory.h"
-#include "components/keyed_service/content/browser_context_dependency_manager.h"
-
-namespace offline_pages {
-
-// static
-OfflinePageAutoFetcherServiceFactory*
-OfflinePageAutoFetcherServiceFactory::GetInstance() {
-  return base::Singleton<OfflinePageAutoFetcherServiceFactory>::get();
-}
-
-// static
-OfflinePageAutoFetcherService*
-OfflinePageAutoFetcherServiceFactory::GetForBrowserContext(
-    content::BrowserContext* context) {
-  KeyedService* service =
-      GetInstance()->GetServiceForBrowserContext(context, true);
-  if (!service)
-    return nullptr;
-  return static_cast<OfflinePageAutoFetcherService*>(service);
-}
-
-OfflinePageAutoFetcherServiceFactory::OfflinePageAutoFetcherServiceFactory()
-    : BrowserContextKeyedServiceFactory(
-          "OfflinePageAutoFetcherService",
-          BrowserContextDependencyManager::GetInstance()) {
-  DependsOn(RequestCoordinatorFactory::GetInstance());
-}
-
-OfflinePageAutoFetcherServiceFactory::~OfflinePageAutoFetcherServiceFactory() {}
-
-KeyedService* OfflinePageAutoFetcherServiceFactory::BuildServiceInstanceFor(
-    content::BrowserContext* context) const {
-  RequestCoordinator* coordinator =
-      RequestCoordinatorFactory::GetForBrowserContext(context);
-  return new OfflinePageAutoFetcherService(coordinator);
-}
-
-}  // namespace offline_pages
diff --git a/chrome/browser/predictors/loading_predictor.cc b/chrome/browser/predictors/loading_predictor.cc
index 18c6c5c..f2ae6c5 100644
--- a/chrome/browser/predictors/loading_predictor.cc
+++ b/chrome/browser/predictors/loading_predictor.cc
@@ -94,6 +94,7 @@
   if (!has_preconnect_prediction)
     return;
 
+  ++total_hints_activated_;
   active_hints_.emplace(url, base::TimeTicks::Now());
   if (IsPreconnectAllowed(profile_))
     MaybeAddPreconnect(url, std::move(prediction.requests), origin);
@@ -250,6 +251,7 @@
     return;
 
   DCHECK(stats);
+  active_hints_.erase(stats->url);
   stats_collector_->RecordPreconnectStats(std::move(stats));
 }
 
diff --git a/chrome/browser/predictors/loading_predictor.h b/chrome/browser/predictors/loading_predictor.h
index 9f65ca2..8a64bed 100644
--- a/chrome/browser/predictors/loading_predictor.h
+++ b/chrome/browser/predictors/loading_predictor.h
@@ -80,6 +80,7 @@
   void PreconnectFinished(std::unique_ptr<PreconnectStats> stats) override;
 
   size_t GetActiveHintsSizeForTesting() { return active_hints_.size(); }
+  size_t GetTotalHintsActivatedForTesting() { return total_hints_activated_; }
   size_t GetActiveNavigationsSizeForTesting() {
     return active_navigations_.size();
   }
@@ -131,6 +132,7 @@
   std::map<GURL, base::TimeTicks> active_hints_;
   std::set<NavigationID> active_navigations_;
   bool shutdown_ = false;
+  size_t total_hints_activated_ = 0;
 
   GURL last_omnibox_origin_;
   base::TimeTicks last_omnibox_preconnect_time_;
@@ -148,6 +150,10 @@
   FRIEND_TEST_ALL_PREFIXES(LoadingPredictorTest,
                            TestMainFrameRequestDoesntCancelExternalHint);
   FRIEND_TEST_ALL_PREFIXES(LoadingPredictorTest,
+                           TestDuplicateHintAfterPreconnectCompleteCalled);
+  FRIEND_TEST_ALL_PREFIXES(LoadingPredictorTest,
+                           TestDuplicateHintAfterPreconnectCompleteNotCalled);
+  FRIEND_TEST_ALL_PREFIXES(LoadingPredictorTest,
                            TestDontTrackNonPrefetchableUrls);
   FRIEND_TEST_ALL_PREFIXES(LoadingPredictorTest, TestDontPredictOmniboxHints);
 
diff --git a/chrome/browser/predictors/loading_predictor_browsertest.cc b/chrome/browser/predictors/loading_predictor_browsertest.cc
index 3ff8f2f0..9cbd307 100644
--- a/chrome/browser/predictors/loading_predictor_browsertest.cc
+++ b/chrome/browser/predictors/loading_predictor_browsertest.cc
@@ -467,10 +467,14 @@
   auto observer = NavigateToURLAsync(url);
   EXPECT_TRUE(observer->WaitForRequestStart());
   EXPECT_EQ(1u, loading_predictor()->GetActiveNavigationsSizeForTesting());
-  EXPECT_EQ(1u, loading_predictor()->GetActiveHintsSizeForTesting());
+  // Checking GetActiveHintsSizeForTesting() is racy since the active hint
+  // is removed after the preconnect finishes. Instead check for total
+  // hints activated.
+  EXPECT_EQ(1u, loading_predictor()->GetTotalHintsActivatedForTesting());
   observer->WaitForNavigationFinished();
   EXPECT_EQ(0u, loading_predictor()->GetActiveNavigationsSizeForTesting());
   EXPECT_EQ(0u, loading_predictor()->GetActiveHintsSizeForTesting());
+  EXPECT_EQ(1u, loading_predictor()->GetTotalHintsActivatedForTesting());
 }
 
 // Tests that two concurrenct navigations are recorded correctly by the
@@ -483,11 +487,15 @@
   EXPECT_TRUE(observer1->WaitForRequestStart());
   EXPECT_TRUE(observer2->WaitForRequestStart());
   EXPECT_EQ(2u, loading_predictor()->GetActiveNavigationsSizeForTesting());
-  EXPECT_EQ(2u, loading_predictor()->GetActiveHintsSizeForTesting());
+  // Checking GetActiveHintsSizeForTesting() is racy since the active hint
+  // is removed after the preconnect finishes. Instead check for total
+  // hints activated.
+  EXPECT_EQ(2u, loading_predictor()->GetTotalHintsActivatedForTesting());
   observer1->WaitForNavigationFinished();
   observer2->WaitForNavigationFinished();
   EXPECT_EQ(0u, loading_predictor()->GetActiveNavigationsSizeForTesting());
   EXPECT_EQ(0u, loading_predictor()->GetActiveHintsSizeForTesting());
+  EXPECT_EQ(2u, loading_predictor()->GetTotalHintsActivatedForTesting());
 }
 
 // Tests that two navigations to the same URL are deduplicated.
@@ -499,11 +507,19 @@
   EXPECT_TRUE(observer1->WaitForRequestStart());
   EXPECT_TRUE(observer2->WaitForRequestStart());
   EXPECT_EQ(2u, loading_predictor()->GetActiveNavigationsSizeForTesting());
-  EXPECT_EQ(1u, loading_predictor()->GetActiveHintsSizeForTesting());
+  // Checking GetActiveHintsSizeForTesting() is racy since the active hint
+  // is removed after the preconnect finishes. Instead check for total
+  // hints activated. The total hints activated may be only 1 if the second
+  // navigation arrives before the first preconnect finishes. However, if the
+  // second navigation arrives later, then two hints may get activated.
+  EXPECT_LE(1u, loading_predictor()->GetTotalHintsActivatedForTesting());
+  EXPECT_GE(2u, loading_predictor()->GetTotalHintsActivatedForTesting());
   observer1->WaitForNavigationFinished();
   observer2->WaitForNavigationFinished();
   EXPECT_EQ(0u, loading_predictor()->GetActiveNavigationsSizeForTesting());
   EXPECT_EQ(0u, loading_predictor()->GetActiveHintsSizeForTesting());
+  EXPECT_LE(1u, loading_predictor()->GetTotalHintsActivatedForTesting());
+  EXPECT_GE(2u, loading_predictor()->GetTotalHintsActivatedForTesting());
 }
 
 // Tests that the LoadingPredictor doesn't record non-http(s) navigations.
diff --git a/chrome/browser/predictors/loading_predictor_unittest.cc b/chrome/browser/predictors/loading_predictor_unittest.cc
index 022bf606..c168cd5 100644
--- a/chrome/browser/predictors/loading_predictor_unittest.cc
+++ b/chrome/browser/predictors/loading_predictor_unittest.cc
@@ -229,6 +229,64 @@
   EXPECT_EQ(start_time, it->second);
 }
 
+TEST_F(LoadingPredictorTest, TestDuplicateHintAfterPreconnectCompleteCalled) {
+  const GURL url = GURL(kUrl);
+  const auto& active_navigations = predictor_->active_navigations_;
+  auto& active_hints = predictor_->active_hints_;
+
+  predictor_->PrepareForPageLoad(url, HintOrigin::EXTERNAL);
+  auto it = active_hints.find(url);
+  EXPECT_NE(it, active_hints.end());
+  EXPECT_TRUE(active_navigations.empty());
+
+  // To check that the hint is replaced, set the start time in the past,
+  // and check later that it changed.
+  base::TimeTicks start_time = it->second - base::TimeDelta::FromSeconds(10);
+  it->second = start_time;
+
+  std::unique_ptr<PreconnectStats> preconnect_stats =
+      std::make_unique<PreconnectStats>(url);
+  predictor_->PreconnectFinished(std::move(preconnect_stats));
+
+  predictor_->PrepareForPageLoad(url, HintOrigin::NAVIGATION_PREDICTOR);
+  it = active_hints.find(url);
+  EXPECT_NE(it, active_hints.end());
+  EXPECT_TRUE(active_navigations.empty());
+
+  // Calling PreconnectFinished() must have cleared the hint, and duplicate
+  // PrepareForPageLoad() call should be honored.
+  EXPECT_LT(start_time, it->second);
+}
+
+TEST_F(LoadingPredictorTest,
+       TestDuplicateHintAfterPreconnectCompleteNotCalled) {
+  const GURL url = GURL(kUrl);
+  const auto& active_navigations = predictor_->active_navigations_;
+  auto& active_hints = predictor_->active_hints_;
+
+  predictor_->PrepareForPageLoad(url, HintOrigin::EXTERNAL);
+  auto it = active_hints.find(url);
+  EXPECT_NE(it, active_hints.end());
+  EXPECT_TRUE(active_navigations.empty());
+
+  content::RunAllTasksUntilIdle();
+  it = active_hints.find(url);
+  EXPECT_NE(it, active_hints.end());
+
+  // To check that the hint is not replaced, set the start time in the recent
+  // past, and check later that it didn't change.
+  base::TimeTicks start_time = it->second - base::TimeDelta::FromSeconds(10);
+  it->second = start_time;
+
+  predictor_->PrepareForPageLoad(url, HintOrigin::NAVIGATION_PREDICTOR);
+  it = active_hints.find(url);
+  EXPECT_NE(it, active_hints.end());
+  EXPECT_TRUE(active_navigations.empty());
+
+  // Duplicate PrepareForPageLoad() call should not be honored.
+  EXPECT_EQ(start_time, it->second);
+}
+
 TEST_F(LoadingPredictorTest, TestDontTrackNonPrefetchableUrls) {
   const GURL url3 = GURL(kUrl3);
   predictor_->PrepareForPageLoad(url3, HintOrigin::NAVIGATION);
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index 52f89f0..b31b220 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -143,14 +143,14 @@
 #include "ui/base/l10n/l10n_util.h"
 
 #if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/android_sms/android_sms_app_helper_delegate_impl.h"
+#include "chrome/browser/chromeos/android_sms/android_sms_pairing_state_tracker_impl.h"
 #include "chrome/browser/chromeos/arc/arc_service_launcher.h"
 #include "chrome/browser/chromeos/authpolicy/auth_policy_credentials_manager.h"
 #include "chrome/browser/chromeos/cryptauth/gcm_device_info_provider_impl.h"
 #include "chrome/browser/chromeos/device_sync/device_sync_client_factory.h"
 #include "chrome/browser/chromeos/locale_change_guard.h"
 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
-#include "chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl.h"
-#include "chrome/browser/chromeos/multidevice_setup/android_sms_pairing_state_tracker_impl.h"
 #include "chrome/browser/chromeos/multidevice_setup/auth_token_validator_factory.h"
 #include "chrome/browser/chromeos/multidevice_setup/auth_token_validator_impl.h"
 #include "chrome/browser/chromeos/multidevice_setup/oobe_completion_tracker_factory.h"
@@ -1196,10 +1196,9 @@
         chromeos::multidevice_setup::OobeCompletionTrackerFactory::
             GetForProfile(this),
         std::make_unique<
-            chromeos::multidevice_setup::AndroidSmsAppHelperDelegateImpl>(this),
+            chromeos::android_sms::AndroidSmsAppHelperDelegateImpl>(this),
         std::make_unique<
-            chromeos::multidevice_setup::AndroidSmsPairingStateTrackerImpl>(
-            this),
+            chromeos::android_sms::AndroidSmsPairingStateTrackerImpl>(this),
         chromeos::GcmDeviceInfoProviderImpl::GetInstance());
   }
 
diff --git a/chrome/browser/resources/settings/about_page/BUILD.gn b/chrome/browser/resources/settings/about_page/BUILD.gn
index 54af5d44..333dc4020 100644
--- a/chrome/browser/resources/settings/about_page/BUILD.gn
+++ b/chrome/browser/resources/settings/about_page/BUILD.gn
@@ -10,12 +10,15 @@
     ":about_page_browser_proxy",
     ":channel_switcher_dialog",
     ":detailed_build_info",
+    ":management_browser_proxy",
+    ":management_page",
   ]
 }
 
 js_library("about_page") {
   deps = [
     ":about_page_browser_proxy",
+    ":management_browser_proxy",
     "..:lifetime_browser_proxy",
     "..:route",
     "../settings_page:main_page_behavior",
@@ -51,3 +54,18 @@
     "//ui/webui/resources/js:load_time_data",
   ]
 }
+
+js_library("management_browser_proxy") {
+  deps = [
+    "//ui/webui/resources/js:cr",
+    "//ui/webui/resources/js:load_time_data",
+    "//ui/webui/resources/js:promise_resolver",
+    "//ui/webui/resources/js:util",
+  ]
+}
+
+js_library("management_page") {
+  deps = [
+    ":management_browser_proxy",
+  ]
+}
diff --git a/chrome/browser/resources/settings/about_page/about_page.html b/chrome/browser/resources/settings/about_page/about_page.html
index 5184ab7..c64cae2 100644
--- a/chrome/browser/resources/settings/about_page/about_page.html
+++ b/chrome/browser/resources/settings/about_page/about_page.html
@@ -22,6 +22,8 @@
 <if expr="chromeos">
 <link rel="import" href="detailed_build_info.html">
 <link rel="import" href="update_warning_dialog.html">
+<link rel="import" href="management_browser_proxy.html">
+<link rel="import" href="management_page.html">
 <link rel="import" href="../settings_page/settings_subpage.html">
 <link rel="import" href="../reset_page/powerwash_dialog.html">
 </if>
@@ -231,6 +233,11 @@
                 id="detailed-build-info-trigger"
                 on-click="onDetailedBuildInfoTap_"
                 label="$i18n{aboutDetailedBuildInfo}"></cr-link-row>
+            <cr-link-row class="hr" icon-class="subpage-arrow"
+                start-icon="settings:business"
+                id="management-info"
+                on-click="onManagementInfoTap_"
+                label="[[managementTitle_]]"></cr-link-row>
 </if>
           </div>
 <if expr="chromeos">
@@ -239,6 +246,11 @@
               <settings-detailed-build-info></settings-detailed-build-info>
             </settings-subpage>
           </template>
+          <template is="dom-if" route-path="/help/management">
+            <settings-subpage page-title="[[managementTitle_]]">
+              <settings-management-page></settings-management-page>
+            </settings-subpage>
+          </template>
 </if>
         </settings-animated-pages>
       </settings-section>
diff --git a/chrome/browser/resources/settings/about_page/about_page.js b/chrome/browser/resources/settings/about_page/about_page.js
index 6a95aac8..b51b9fd 100644
--- a/chrome/browser/resources/settings/about_page/about_page.js
+++ b/chrome/browser/resources/settings/about_page/about_page.js
@@ -125,6 +125,14 @@
     },
 
     /** @private */
+    managementTitle_: {
+      type: String,
+      // TODO(raleksandrov): Better to use string from management_strings as
+      // default value here, but this should be never shown.
+      value: 'Management overview',
+    },
+
+    /** @private */
     showUpdateWarningDialog_: {
       type: Boolean,
       value: false,
@@ -161,6 +169,8 @@
     // </if>
   ],
 
+  /** @private {?settings.ManagementBrowserProxy} */
+  browserProxy_: null,
 
   /** @private {?settings.AboutPageBrowserProxy} */
   aboutBrowserProxy_: null,
@@ -194,6 +204,11 @@
     this.aboutBrowserProxy_.getHasEndOfLife().then(result => {
       this.hasEndOfLife_ = result;
     });
+
+    this.browserProxy_ = settings.ManagementBrowserProxyImpl.getInstance();
+    this.browserProxy_.getManagementTitle().then(title => {
+      this.managementTitle_ = title;
+    });
     // </if>
     // <if expr="not chromeos">
     this.startListening_();
@@ -517,6 +532,11 @@
   },
 
   /** @private */
+  onManagementInfoTap_: function() {
+    settings.navigateTo(settings.routes.MANAGEMENT_INFO);
+  },
+
+  /** @private */
   onRelaunchAndPowerwashTap_: function() {
     if (this.currentUpdateStatusEvent_.rollback) {
       // Wipe already initiated, simply relaunch.
diff --git a/chrome/browser/resources/settings/about_page/management_browser_proxy.html b/chrome/browser/resources/settings/about_page/management_browser_proxy.html
new file mode 100644
index 0000000..abaff42
--- /dev/null
+++ b/chrome/browser/resources/settings/about_page/management_browser_proxy.html
@@ -0,0 +1,2 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+<script src="management_browser_proxy.js"></script>
diff --git a/chrome/browser/resources/settings/about_page/management_browser_proxy.js b/chrome/browser/resources/settings/about_page/management_browser_proxy.js
new file mode 100644
index 0000000..17be3bf
--- /dev/null
+++ b/chrome/browser/resources/settings/about_page/management_browser_proxy.js
@@ -0,0 +1,113 @@
+// 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.
+
+cr.exportPath('settings');
+/**
+ * @typedef {{
+ *    name: string,
+ *    permissions: !Array<string>
+ * }}
+ */
+settings.Extension;
+
+cr.define('settings', function() {
+  /** @interface */
+  class ManagementBrowserProxy {
+    /**
+     * @return {!Promise<string>} Return title of the management page
+     */
+    getManagementTitle() {}
+
+    /**
+     * @return {!Promise<string>} Message stating if device is enterprise
+     * managed and by whom.
+     */
+    getDeviceManagementStatus() {}
+
+    /**
+     * @return {!Promise<!Array<string>>} Types of device reporting.
+     */
+    getReportingDevice() {}
+
+    /**
+     * @return {!Promise<!Array<string>>} Types of device reporting.
+     */
+    getReportingSecurity() {}
+
+    /**
+     * @return {!Promise<!Array<string>>} Types of device reporting.
+     */
+    getReportingUserActivity() {}
+
+    /**
+     * @return {!Promise<!Array<string>>} Types of device reporting.
+     */
+    getReportingWeb() {}
+
+    /**
+     * Each extension has a name and a list of permission messages.
+     * @return {!Promise<!Array<!settings.Extension>>} List of extensions.
+     */
+    getExtensions() {}
+
+    /**
+     * @return {!Promise<boolean>} Boolean describing trust root configured
+     * or not.
+     */
+    getLocalTrustRootsInfo() {}
+  }
+
+  /**
+   * @implements {settings.ManagementBrowserProxy}
+   */
+  class ManagementBrowserProxyImpl {
+    /** @override */
+    getManagementTitle() {
+      return cr.sendWithPromise('getManagementTitle');
+    }
+
+    /** @override */
+    getDeviceManagementStatus() {
+      return cr.sendWithPromise('getDeviceManagementStatus');
+    }
+
+    /** @override */
+    getReportingDevice() {
+      return cr.sendWithPromise('getReportingDevice');
+    }
+
+    /** @override */
+    getReportingSecurity() {
+      return cr.sendWithPromise('getReportingSecurity');
+    }
+
+    /** @override */
+    getReportingUserActivity() {
+      return cr.sendWithPromise('getReportingUserActivity');
+    }
+
+    /** @override */
+    getReportingWeb() {
+      return cr.sendWithPromise('getReportingWeb');
+    }
+
+    /** @override */
+    getExtensions() {
+      return cr.sendWithPromise('getExtensions');
+    }
+
+    /** @override */
+    getLocalTrustRootsInfo() {
+      return cr.sendWithPromise('getLocalTrustRootsInfo');
+    }
+  }
+
+  // Make Page a singleton.
+  cr.addSingletonGetter(ManagementBrowserProxyImpl);
+
+  return {
+    ManagementBrowserProxy: ManagementBrowserProxy,
+    ManagementBrowserProxyImpl: ManagementBrowserProxyImpl
+  };
+});
diff --git a/chrome/browser/resources/settings/about_page/management_page.html b/chrome/browser/resources/settings/about_page/management_page.html
new file mode 100644
index 0000000..8fcc356
--- /dev/null
+++ b/chrome/browser/resources/settings/about_page/management_page.html
@@ -0,0 +1,68 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="management_browser_proxy.html">
+<link rel="import" href="../settings_shared_css.html">
+<link rel="import" href="../icons.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
+
+<dom-module id="settings-management-page">
+  <template>
+    <style include="settings-shared">
+      cr-policy-indicator {
+        margin-inline-start: var(--cr-controlled-by-spacing);
+      }
+
+      ul {
+        list-style-type : none;
+      }
+    </style>
+      <!--  This is where page content gets dynamically added. -->
+
+      <div class="settings-box two-line single-column"
+           id="managementStatus" hidden></div>
+
+      <div class="settings-box block single-column" id="policies" hidden>
+        <h2>$i18n{managementDeviceReporting}</h2>
+        <div id="deviceConfiguration">
+          $i18n{managementDeviceConfiguration}
+        </div>
+        <ul id="reportingInfoList">
+          <li id="reportingDevice" hidden>
+            <iron-icon icon="settings:computer"></iron-icon>
+            <span id="reportingDeviceText"> </span>
+          </li>
+          <li id="reportingSecurity" hidden>
+            <iron-icon icon="settings:security"></iron-icon>
+            <span id="reportingSecurityText"> </span>
+          </li>
+          <li id="reportingUserActivity" hidden>
+            <iron-icon icon="settings:person"></iron-icon>
+            <span id="reportingUserActivityText"> </span>
+          </li>
+          <li id="reportingWeb" hidden>
+            <iron-icon icon="settings:public"></iron-icon>
+            <span id="reportingWebText"> </span>
+          </li>
+        </ul>
+      </div>
+
+      <div class="settings-box two-line single-column" id="extensions" hidden>
+        <h2>$i18n{managementExtensionReporting}</h2>
+        <div id="extensionsInstalled">
+          $i18n{managementExtensionsInstalled}
+        </div>
+        <table id="extensionsTable">
+          <tr>
+            <th>$i18n{managementExtensionName}</th>
+            <th>$i18n{managementExtensionPermissions}</th>
+          </tr>
+        </table>
+      </div>
+
+      <div class="settings-box two-line single-column" id="trustRoots" hidden>
+          <h2 class="section-title">$i18n{managementLocalTrustRoots}</h2>
+          <div id="trustRootsConfiguration"></div>
+      </div>
+  </template>
+  <script src="management_page.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/settings/about_page/management_page.js b/chrome/browser/resources/settings/about_page/management_page.js
new file mode 100644
index 0000000..1b9084c
--- /dev/null
+++ b/chrome/browser/resources/settings/about_page/management_page.js
@@ -0,0 +1,179 @@
+// 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.
+
+/**
+ * @fileoverview 'settings-management-page' contains scary information
+ * about ChromeOS privacy.
+ */
+Polymer({
+  is: 'settings-management-page',
+
+  /** @private {?settings.ManagementBrowserProxy} */
+  browserProxy_: null,
+
+  /** @private */
+  getDeviceManagementStatus_: function() {
+    this.browserProxy_.getDeviceManagementStatus()
+        .then(managedString => {
+          this.$.managementStatus.textContent = managedString;
+          this.$.managementStatus.hidden = false;
+        })
+        .catch(
+            // On Chrome desktop, the behavior is to show nothing (device
+            // management is outside of Chrome's control), so
+            // RejectJavascriptCallback is used, which throws an error. The
+            // intended handling in this case is to do nothing.
+            () => {});
+  },
+
+  /** @private */
+  getReportingDevice_: function() {
+    this.browserProxy_.getReportingDevice().then(reportingSources => {
+      if (reportingSources.length == 0) {
+        return;
+      }
+      let reportingInfoAdded = false;
+
+      for (const id of reportingSources) {
+        reportingInfoAdded = true;
+        this.$.reportingDeviceText.textContent +=
+            loadTimeData.getString(id) + ' ';
+      }
+
+      if (reportingInfoAdded) {
+        this.$.policies.hidden = false;
+        this.$.reportingDevice.hidden = false;
+      }
+    });
+  },
+
+  /** @private */
+  getReportingSecurity_: function() {
+    this.browserProxy_.getReportingSecurity().then(reportingSources => {
+      if (reportingSources.length == 0) {
+        return;
+      }
+      let reportingInfoAdded = false;
+
+      for (const id of reportingSources) {
+        reportingInfoAdded = true;
+        this.$.reportingSecurityText.textContent +=
+            loadTimeData.getString(id) + ' ';
+      }
+
+      if (reportingInfoAdded) {
+        this.$.policies.hidden = false;
+        this.$.reportingSecurity.hidden = false;
+      }
+    });
+  },
+
+  /** @private */
+  getReportingUserActivity_: function() {
+    this.browserProxy_.getReportingUserActivity().then(reportingSources => {
+      if (reportingSources.length == 0) {
+        return;
+      }
+      let reportingInfoAdded = false;
+
+      for (const id of reportingSources) {
+        reportingInfoAdded = true;
+        this.$.reportingUserActivityText.textContent +=
+            loadTimeData.getString(id) + ' ';
+      }
+
+      if (reportingInfoAdded) {
+        this.$.policies.hidden = false;
+        this.$.reportingUserActivity.hidden = false;
+      }
+    });
+  },
+
+  /** @private */
+  getReportingWeb_: function() {
+    this.browserProxy_.getReportingWeb().then(reportingSources => {
+      if (reportingSources.length == 0) {
+        return;
+      }
+      let reportingInfoAdded = false;
+
+      for (const id of reportingSources) {
+        reportingInfoAdded = true;
+        this.$.reportingWebText.textContent += loadTimeData.getString(id) + ' ';
+      }
+
+      if (reportingInfoAdded) {
+        this.$.policies.hidden = false;
+        this.$.reportingWeb.hidden = false;
+      }
+    });
+  },
+
+  /** @private */
+  getExtensions_: function() {
+    // Show names and permissions of |extensions| in a table.
+    this.browserProxy_.getExtensions().then(extensions => {
+      if (extensions.length == 0) {
+        return;
+      }
+
+      const table = this.$.extensionsTable;
+
+      for (const /** settings.Extension */ extension of extensions) {
+        assert(
+            extension.hasOwnProperty('permissions'),
+            'Each extension must have the permissions field');
+        assert(
+            extension.hasOwnProperty('name'),
+            'Each extension must have the name field');
+
+        const permissionsList = document.createElement('ul');
+        for (const perm of extension.permissions) {
+          const permissionElement = document.createElement('li');
+          permissionElement.textContent = perm;
+          permissionsList.appendChild(permissionElement);
+        }
+
+        const row = table.insertRow();
+        const nameCell = row.insertCell();
+        // insertCell(-1) inserts at the last position.
+        const permissionsCell = row.insertCell(-1);
+        nameCell.textContent = extension.name;
+        permissionsCell.appendChild(permissionsList);
+      }
+
+      this.$.extensions.hidden = false;
+    });
+  },
+
+  /** @private */
+  getLocalTrustRootsInfo_: function() {
+    this.browserProxy_.getLocalTrustRootsInfo().then(trustRootsConfigured => {
+      if (trustRootsConfigured) {
+        this.$.trustRootsConfiguration.textContent =
+            loadTimeData.getString('managementTrustRootsConfigured');
+        this.$.trustRoots.hidden = false;
+      }
+    });
+  },
+
+  /** @override */
+  attached: function() {
+    this.browserProxy_ = settings.ManagementBrowserProxyImpl.getInstance();
+
+    this.getDeviceManagementStatus_();
+
+    this.getReportingDevice_();
+
+    this.getReportingSecurity_();
+
+    this.getReportingUserActivity_();
+
+    this.getReportingWeb_();
+
+    this.getExtensions_();
+
+    this.getLocalTrustRootsInfo_();
+  },
+});
diff --git a/chrome/browser/resources/settings/icons.html b/chrome/browser/resources/settings/icons.html
index 6cec5302..ad4836e 100644
--- a/chrome/browser/resources/settings/icons.html
+++ b/chrome/browser/resources/settings/icons.html
@@ -77,6 +77,7 @@
 <if expr="not chromeos">
       <g id="build"><path d="M22.7 19l-9.1-9.1c.9-2.3.4-5-1.5-6.9-2-2-5-2.4-7.4-1.3L9 6 6 9 1.6 4.7C.4 7.1.9 10.1 2.9 12.1c1.9 1.9 4.6 2.4 6.9 1.5l9.1 9.1c.4.4 1 .4 1.4 0l2.3-2.3c.5-.4.5-1.1.1-1.4z"></path></g>
 </if>
+      <g id="business"><path d="M12 7V3H2v18h20V7H12zM6 19H4v-2h2v2zm0-4H4v-2h2v2zm0-4H4V9h2v2zm0-4H4V5h2v2zm4 12H8v-2h2v2zm0-4H8v-2h2v2zm0-4H8V9h2v2zm0-4H8V5h2v2zm10 12h-8v-2h2v-2h-2v-2h2v-2h-2V9h8v10zm-2-8h-2v2h2v-2zm0 4h-2v2h2v-2z"></path></g>
       <g id="check-circle"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"></path></g>
 <if expr="chromeos">
       <g id="chevron-left"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"</path></g>
@@ -120,14 +121,17 @@
       <g id="pdf"><path d="M7 11.5h1v-1H7v1zM19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-9.5 8.5c0 .83-.67 1.5-1.5 1.5H7v2H5.5V9H8c.83 0 1.5.67 1.5 1.5v1zm10-1H17v1h1.5V13H17v2h-1.5V9h4v1.5zm-5 3c0 .83-.67 1.5-1.5 1.5h-2.5V9H13c.83 0 1.5.67 1.5 1.5v3zm-2.5 0h1v-3h-1v3z"></path><path fill="none" d="M0 0h24v24H0z"></path></g>
       <g id="palette"><path d="M12 3c-4.97 0-9 4.03-9 9s4.03 9 9 9c.83 0 1.5-.67 1.5-1.5 0-.39-.15-.74-.39-1.01-.23-.26-.38-.61-.38-.99 0-.83.67-1.5 1.5-1.5H16c2.76 0 5-2.24 5-5 0-4.42-4.03-8-9-8zm-5.5 9c-.83 0-1.5-.67-1.5-1.5S5.67 9 6.5 9 8 9.67 8 10.5 7.33 12 6.5 12zm3-4C8.67 8 8 7.33 8 6.5S8.67 5 9.5 5s1.5.67 1.5 1.5S10.33 8 9.5 8zm5 0c-.83 0-1.5-.67-1.5-1.5S13.67 5 14.5 5s1.5.67 1.5 1.5S15.33 8 14.5 8zm3 4c-.83 0-1.5-.67-1.5-1.5S16.67 9 17.5 9s1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"></path></g>
       <g id="payment-handler"><path d="M20 4H4c-1.11 0-1.99.89-1.99 2L2 18c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V6c0-1.11-.89-2-2-2zm0 14H4v-6h16v6zm0-10H4V6h16v2z"></path></g>
+      <g id="person"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"></path></g>
       <g id="photo"><path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z"></path></g>
       <g id="power-settings-new"><path d="M13 3h-2v10h2V3zm4.83 2.17l-1.42 1.42C17.99 7.86 19 9.81 19 12c0 3.87-3.13 7-7 7s-7-3.13-7-7c0-2.19 1.01-4.14 2.58-5.42L6.17 5.17C4.23 6.82 3 9.26 3 12c0 4.97 4.03 9 9 9s9-4.03 9-9c0-2.74-1.23-5.18-3.17-6.83z"></path></g>
       <g id="protocol-handler"><path d="M21.72 11.33l-6.644-7.035a.97.97 0 0 0-1.38-.01l-1.67 1.72-1.617-1.712a.97.97 0 0 0-1.38-.01l-6.737 6.935c-.187.191-.29.447-.292.719-.002.272.099.529.28.722l6.644 7.034a.949.949 0 0 0 1.38.011l1.671-1.718 1.615 1.71a.949.949 0 0 0 1.381.01l6.74-6.935a1.054 1.054 0 0 0 .01-1.44zM6.947 12.464l3.657 3.785-.974.98-5.273-5.456 5.349-5.378.929.962-3.677 3.7a.998.998 0 0 0-.292.702 1 1 0 0 0 .28.705zm7.35 4.768l-.931-.963 3.68-3.7a1.012 1.012 0 0 0 .007-1.407l-3.656-3.784.974-.98 5.273 5.456-5.348 5.378z"></path></g>
+      <g id="public"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"></path></g>
       <g id="restore"><path d="M13 3c-4.97 0-9 4.03-9 9H1l3.89 3.89.07.14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42C8.27 19.99 10.51 21 13 21c4.97 0 9-4.03 9-9s-4.03-9-9-9zm-1 5v5l4.28 2.54.72-1.21-3.5-2.08V8H12z"></path></g>
       <g id="rotate-right"><path d="M15.55 5.55L11 1v3.07C7.06 4.56 4 7.92 4 12s3.05 7.44 7 7.93v-2.02c-2.84-.48-5-2.94-5-5.91s2.16-5.43 5-5.91V10l4.55-4.45zM19.93 11c-.17-1.39-.72-2.73-1.62-3.89l-1.42 1.42c.54.75.88 1.6 1.02 2.47h2.02zM13 17.9v2.02c1.39-.17 2.74-.71 3.9-1.61l-1.44-1.44c-.75.54-1.59.89-2.46 1.03zm3.89-2.42l1.42 1.41c.9-1.16 1.45-2.5 1.62-3.89h-2.02c-.14.87-.48 1.72-1.02 2.48z"></path></g>
       <g id="sensors"><path d="M10 8.5c-0.8 0-1.5 0.7-1.5 1.5s0.7 1.5 1.5 1.5s1.5-0.7 1.5-1.5S10.8 8.5 10 8.5z M7.6 5.8 C6.2 6.7 5.2 8.2 5.2 10c0 1.8 1 3.4 2.4 4.2l0.8-1.4c-1-0.6-1.6-1.6-1.6-2.8c0-1.2 0.6-2.2 1.6-2.8L7.6 5.8z M14.8 10 c0-1.8-1-3.4-2.4-4.2l-0.8 1.4c0.9 0.6 1.6 1.6 1.6 2.8c0 1.2-0.6 2.2-1.6 2.8l0.8 1.4C13.8 13.4 14.8 11.8 14.8 10z M6 3 c-2.4 1.4-4 4-4 7c0 3 1.6 5.6 4 7l0.8-1.4c-1.9-1.1-3.2-3.2-3.2-5.6c0-2.4 1.3-4.5 3.2-5.6L6 3z M13.2 4.4 c1.9 1.1 3.2 3.2 3.2 5.6c0 2.4-1.3 4.5-3.2 5.6L14 17c2.4-1.4 4-4 4-7c0-3-1.6-5.6-4-7L13.2 4.4z"></path></g>
 <if expr="chromeos">
       <g id="alert-device-out-of-range" fill="none" fill-rule="evenodd"><path d="M-1-1h20v20H-1z"></path><path fill="#C53929" fill-rule="nonzero" d="M8.167 11.5h1.666v1.667H8.167V11.5zm0-6.667h1.666v5H8.167v-5zM8.992.667C4.392.667.667 4.4.667 9s3.725 8.333 8.325 8.333c4.608 0 8.341-3.733 8.341-8.333S13.6.667 8.992.667zm.008 15A6.665 6.665 0 0 1 2.333 9 6.665 6.665 0 0 1 9 2.333 6.665 6.665 0 0 1 15.667 9 6.665 6.665 0 0 1 9 15.667z"></path></g>
+      <g id="security"><path d="M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4zm0 10.99h7c-.53 4.12-3.28 7.79-7 8.94V12H5V6.3l7-3.11v8.8z"></path></g>
       <g id="signal-cellular-0-bar"><path fill-opacity=".3" d="M2 22h20V2z"></path></g>
       <g id="signal-cellular-1-bar"><path fill-opacity=".3" d="M2 22h20V2z"></path><path d="M12 12L2 22h10z"></path></g>
       <g id="signal-cellular-2-bar"><path fill-opacity=".3" d="M2 22h20V2z"></path><path d="M14 10L2 22h12z"></path></g>
diff --git a/chrome/browser/resources/settings/route.js b/chrome/browser/resources/settings/route.js
index 61d7c61c..d1e832b 100644
--- a/chrome/browser/resources/settings/route.js
+++ b/chrome/browser/resources/settings/route.js
@@ -52,6 +52,7 @@
  *   MANAGE_ACCESSIBILITY: (undefined|!settings.Route),
  *   MANAGE_PROFILE: (undefined|!settings.Route),
  *   MANAGE_TTS_SETTINGS: (undefined|!settings.Route),
+ *   MANAGEMENT_INFO : (undefined|!settings.Route),
  *   MULTIDEVICE: (undefined|!settings.Route),
  *   MULTIDEVICE_FEATURES: (undefined|!settings.Route),
  *   NETWORK_DETAIL: (undefined|!settings.Route),
@@ -434,6 +435,7 @@
     // route in order to show the subpage on Chrome OS.
     r.ABOUT_ABOUT = r.ABOUT.createSection('/help/about', 'about');
     r.DETAILED_BUILD_INFO = r.ABOUT_ABOUT.createChild('/help/details');
+    r.MANAGEMENT_INFO = r.ABOUT_ABOUT.createChild('/help/management');
     // </if>
 
     return r;
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd
index 163e8fe..dc9b10e 100644
--- a/chrome/browser/resources/settings/settings_resources.grd
+++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -74,6 +74,18 @@
         <structure name="IDR_SETTINGS_UPDATE_WARNING_DIALOG_JS"
                    file="about_page/update_warning_dialog.js"
                    type="chrome_html" />
+        <structure name="IDR_SETTINGS_MANAGEMENT_PAGE_HTML"
+                    file="about_page/management_page.html"
+                    type="chrome_html"/>
+        <structure name="IDR_SETTINGS_MANAGEMENT_PAGE_JS"
+                    file="about_page/management_page.js"
+                    type="chrome_html"/>
+        <structure name="IDR_SETTINGS_MANAGEMENT_BROWSER_PROXY_HTML"
+                    file="about_page/management_browser_proxy.html"
+                    type="chrome_html"/>
+        <structure name="IDR_SETTINGS_MANAGEMENT_PROXY_JS"
+                    file="about_page/management_browser_proxy.js"
+                    type="chrome_html"/>
       </if>
       <structure name="IDR_SETTINGS_ADD_SITE_DIALOG_HTML"
                  file="site_settings/add_site_dialog.html"
diff --git a/chrome/browser/service_process/service_process_control_mac.mm b/chrome/browser/service_process/service_process_control_mac.mm
index b0fe049b..01127a53 100644
--- a/chrome/browser/service_process/service_process_control_mac.mm
+++ b/chrome/browser/service_process/service_process_control_mac.mm
@@ -12,7 +12,6 @@
 #include "chrome/common/service_process_util_posix.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
-#include "third_party/google_toolbox_for_mac/src/Foundation/GTMServiceManagement.h"
 
 using content::BrowserThread;
 
diff --git a/chrome/browser/sync/test/integration/secondary_account_helper.h b/chrome/browser/sync/test/integration/secondary_account_helper.h
deleted file mode 100644
index b0bdc98..0000000
--- a/chrome/browser/sync/test/integration/secondary_account_helper.h
+++ /dev/null
@@ -1,53 +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 CHROME_BROWSER_SYNC_TEST_INTEGRATION_SECONDARY_ACCOUNT_HELPER_H_
-#define CHROME_BROWSER_SYNC_TEST_INTEGRATION_SECONDARY_ACCOUNT_HELPER_H_
-
-#include <memory>
-#include <string>
-
-#include "base/callback_list.h"
-#include "build/build_config.h"
-
-class Profile;
-
-namespace content {
-class BrowserContext;
-}  // namespace content
-
-namespace secondary_account_helper {
-
-using ScopedFakeGaiaCookieManagerServiceFactory = std::unique_ptr<
-    base::CallbackList<void(content::BrowserContext*)>::Subscription>;
-
-// Sets up a factory to create a FakeGaiaCookieManagerService. Meant to be
-// called from SetUpInProcessBrowserTestFixture. The caller should hold on to
-// the returned object for the duration of the test, e.g. store it in a member
-// of the test fixture class.
-ScopedFakeGaiaCookieManagerServiceFactory SetUpFakeGaiaCookieManagerService();
-
-#if defined(OS_CHROMEOS)
-// Sets up necessary fakes for fake network responses to work. Meant to be
-// called from SetUpOnMainThread.
-// TODO(crbug.com/882770): On ChromeOS, we need to set up a fake
-// NetworkPortalDetector, otherwise chromeos::DelayNetworkCall will think it's
-// behind a captive portal and delay all network requests forever, which means
-// the ListAccounts requests (i.e. getting cookie accounts) will never make it
-// far enough to even request our fake response.
-void InitNetwork();
-#endif  // defined(OS_CHROMEOS)
-
-// Makes a non-primary account available with both a refresh token and cookie.
-void SignInSecondaryAccount(Profile* profile, const std::string& email);
-
-#if !defined(OS_CHROMEOS)
-// Makes the given account Chrome's primary one. The account must already be
-// signed in (per SignInSecondaryAccount).
-void MakeAccountPrimary(Profile* profile, const std::string& email);
-#endif  // !defined(OS_CHROMEOS)
-
-}  // namespace secondary_account_helper
-
-#endif  // CHROME_BROWSER_SYNC_TEST_INTEGRATION_SECONDARY_ACCOUNT_HELPER_H_
diff --git a/chrome/browser/sync/test/integration/secondary_account_helper.cc b/chrome/browser/sync/test/integration/secondary_account_sync_test.cc
similarity index 60%
rename from chrome/browser/sync/test/integration/secondary_account_helper.cc
rename to chrome/browser/sync/test/integration/secondary_account_sync_test.cc
index dc50be6..9c9ebbf4 100644
--- a/chrome/browser/sync/test/integration/secondary_account_helper.cc
+++ b/chrome/browser/sync/test/integration/secondary_account_sync_test.cc
@@ -1,17 +1,13 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2019 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/sync/test/integration/secondary_account_helper.h"
+#include "chrome/browser/sync/test/integration/secondary_account_sync_test.h"
 
 #include "base/bind.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/signin/fake_gaia_cookie_manager_service_builder.h"
-#include "chrome/browser/signin/gaia_cookie_manager_service_factory.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
-#include "components/keyed_service/content/browser_context_dependency_manager.h"
-#include "components/signin/core/browser/fake_gaia_cookie_manager_service.h"
 #include "components/signin/core/browser/signin_manager.h"
 #include "services/identity/public/cpp/identity_test_utils.h"
 
@@ -23,28 +19,8 @@
 #include "chromeos/network/portal_detector/network_portal_detector.h"
 #endif  // defined(OS_CHROMEOS)
 
-namespace secondary_account_helper {
-
-namespace {
-
-void OnWillCreateBrowserContextServices(content::BrowserContext* context) {
-  GaiaCookieManagerServiceFactory::GetInstance()->SetTestingFactory(
-      context,
-      base::BindRepeating(
-          &BuildFakeGaiaCookieManagerServiceWithOptions,
-          /*create_fake_url_loader_factory_for_cookie_requests=*/true));
-}
-
-}  // namespace
-
-ScopedFakeGaiaCookieManagerServiceFactory SetUpFakeGaiaCookieManagerService() {
-  return BrowserContextDependencyManager::GetInstance()
-      ->RegisterWillCreateBrowserContextServicesCallbackForTesting(
-          base::BindRepeating(&OnWillCreateBrowserContextServices));
-}
-
 #if defined(OS_CHROMEOS)
-void InitNetwork() {
+void SecondaryAccountSyncTest::InitNetwork() {
   auto* portal_detector = new chromeos::NetworkPortalDetectorTestImpl();
 
   const chromeos::NetworkState* default_network =
@@ -66,20 +42,20 @@
 }
 #endif  // defined(OS_CHROMEOS)
 
-void SignInSecondaryAccount(Profile* profile, const std::string& email) {
+void SecondaryAccountSyncTest::SignInSecondaryAccount(
+    Profile* profile,
+    const std::string& email) {
   identity::IdentityManager* identity_manager =
       IdentityManagerFactory::GetForProfile(profile);
   AccountInfo account_info =
       identity::MakeAccountAvailable(identity_manager, email);
-  FakeGaiaCookieManagerService* fake_cookie_service =
-      static_cast<FakeGaiaCookieManagerService*>(
-          GaiaCookieManagerServiceFactory::GetForProfile(profile));
-  identity::SetCookieAccounts(fake_cookie_service, identity_manager,
+  identity::SetCookieAccounts(identity_manager, &test_url_loader_factory_,
                               {{account_info.email, account_info.gaia}});
 }
 
 #if !defined(OS_CHROMEOS)
-void MakeAccountPrimary(Profile* profile, const std::string& email) {
+void SecondaryAccountSyncTest::MakeAccountPrimary(Profile* profile,
+                                                  const std::string& email) {
   // This is implemented in the same way as in
   // DiceTurnSyncOnHelper::SigninAndShowSyncConfirmationUI.
   // TODO(blundell): IdentityManager should support this use case, so we don't
@@ -88,5 +64,3 @@
       email);
 }
 #endif  // !defined(OS_CHROMEOS)
-
-}  // namespace secondary_account_helper
diff --git a/chrome/browser/sync/test/integration/secondary_account_sync_test.h b/chrome/browser/sync/test/integration/secondary_account_sync_test.h
new file mode 100644
index 0000000..54be3a8b
--- /dev/null
+++ b/chrome/browser/sync/test/integration/secondary_account_sync_test.h
@@ -0,0 +1,40 @@
+// Copyright 2019 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_SYNC_TEST_INTEGRATION_SECONDARY_ACCOUNT_SYNC_TEST_H_
+#define CHROME_BROWSER_SYNC_TEST_INTEGRATION_SECONDARY_ACCOUNT_SYNC_TEST_H_
+
+#include <string>
+
+#include "build/build_config.h"
+#include "chrome/browser/sync/test/integration/sync_test.h"
+
+class Profile;
+
+class SecondaryAccountSyncTest : public SyncTest {
+ public:
+  SecondaryAccountSyncTest() : SyncTest(SINGLE_CLIENT) {}
+
+#if defined(OS_CHROMEOS)
+  // Sets up necessary fakes for fake network responses to work. Meant to be
+  // called from SetUpOnMainThread.
+  // TODO(crbug.com/882770): On ChromeOS, we need to set up a fake
+  // NetworkPortalDetector, otherwise chromeos::DelayNetworkCall will think it's
+  // behind a captive portal and delay all network requests forever, which means
+  // the ListAccounts requests (i.e. getting cookie accounts) will never make it
+  // far enough to even request our fake response.
+  void InitNetwork();
+#endif  // defined(OS_CHROMEOS)
+
+  // Makes a non-primary account available with both a refresh token and cookie.
+  void SignInSecondaryAccount(Profile* profile, const std::string& email);
+
+#if !defined(OS_CHROMEOS)
+  // Makes the given account Chrome's primary one. The account must already be
+  // signed in (per SignInSecondaryAccount).
+  void MakeAccountPrimary(Profile* profile, const std::string& email);
+#endif  // !defined(OS_CHROMEOS)
+};
+
+#endif  // CHROME_BROWSER_SYNC_TEST_INTEGRATION_SECONDARY_ACCOUNT_SYNC_TEST_H_
diff --git a/chrome/browser/sync/test/integration/single_client_secondary_account_sync_test.cc b/chrome/browser/sync/test/integration/single_client_secondary_account_sync_test.cc
index 76e36d8..644d0d2 100644
--- a/chrome/browser/sync/test/integration/single_client_secondary_account_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_secondary_account_sync_test.cc
@@ -9,7 +9,7 @@
 #include "chrome/browser/defaults.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
-#include "chrome/browser/sync/test/integration/secondary_account_helper.h"
+#include "chrome/browser/sync/test/integration/secondary_account_sync_test.h"
 #include "chrome/browser/sync/test/integration/single_client_status_change_checker.h"
 #include "chrome/browser/sync/test/integration/sync_test.h"
 #include "components/browser_sync/profile_sync_service.h"
@@ -27,9 +27,9 @@
   return allowed_types;
 }
 
-class SingleClientSecondaryAccountSyncTest : public SyncTest {
+class SingleClientSecondaryAccountSyncTest : public SecondaryAccountSyncTest {
  public:
-  SingleClientSecondaryAccountSyncTest() : SyncTest(SINGLE_CLIENT) {
+  SingleClientSecondaryAccountSyncTest() {
     features_.InitWithFeatures(
         /*enabled_features=*/{switches::kSyncStandaloneTransport,
                               switches::kSyncSupportSecondaryAccount},
@@ -37,14 +37,9 @@
   }
   ~SingleClientSecondaryAccountSyncTest() override {}
 
-  void SetUpInProcessBrowserTestFixture() override {
-    fake_gaia_cookie_manager_factory_ =
-        secondary_account_helper::SetUpFakeGaiaCookieManagerService();
-  }
-
   void SetUpOnMainThread() override {
 #if defined(OS_CHROMEOS)
-    secondary_account_helper::InitNetwork();
+    InitNetwork();
 #endif  // defined(OS_CHROMEOS)
   }
 
@@ -53,9 +48,6 @@
  private:
   base::test::ScopedFeatureList features_;
 
-  secondary_account_helper::ScopedFakeGaiaCookieManagerServiceFactory
-      fake_gaia_cookie_manager_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(SingleClientSecondaryAccountSyncTest);
 };
 
@@ -69,7 +61,7 @@
 
   // Since standalone transport is disabled, just signing in (without making the
   // account Chrome's primary one) should *not* start the Sync machinery.
-  secondary_account_helper::SignInSecondaryAccount(profile(), "user@email.com");
+  SignInSecondaryAccount(profile(), "user@email.com");
   EXPECT_EQ(syncer::SyncService::TransportState::DISABLED,
             GetSyncService(0)->GetTransportState());
 }
@@ -85,7 +77,7 @@
   // Since secondary account support is disabled, just signing in (without
   // making the account Chrome's primary one) should *not* start the Sync
   // machinery.
-  secondary_account_helper::SignInSecondaryAccount(profile(), "user@email.com");
+  SignInSecondaryAccount(profile(), "user@email.com");
   EXPECT_EQ(syncer::SyncService::TransportState::DISABLED,
             GetSyncService(0)->GetTransportState());
 }
@@ -97,7 +89,7 @@
   // Signing in (without making the account Chrome's primary one or explicitly
   // setting up Sync) should trigger starting the Sync machinery in standalone
   // transport mode.
-  secondary_account_helper::SignInSecondaryAccount(profile(), "user@email.com");
+  SignInSecondaryAccount(profile(), "user@email.com");
   if (browser_defaults::kSyncAutoStarts) {
     EXPECT_EQ(syncer::SyncService::TransportState::INITIALIZING,
               GetSyncService(0)->GetTransportState());
@@ -135,7 +127,7 @@
   ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
 
   // Set up Sync in transport mode for a non-primary account.
-  secondary_account_helper::SignInSecondaryAccount(profile(), "user@email.com");
+  SignInSecondaryAccount(profile(), "user@email.com");
   ASSERT_TRUE(GetClient(0)->AwaitSyncSetupCompletion(
       /*skip_passphrase_verification=*/false));
   ASSERT_EQ(syncer::SyncService::TransportState::ACTIVE,
@@ -145,7 +137,7 @@
 
   // Simulate the user opting in to full Sync: Make the account primary, and
   // set first-time setup to complete.
-  secondary_account_helper::MakeAccountPrimary(profile(), "user@email.com");
+  MakeAccountPrimary(profile(), "user@email.com");
   GetSyncService(0)->GetUserSettings()->SetFirstSetupComplete();
 
   EXPECT_TRUE(GetClient(0)->AwaitSyncSetupCompletion(
diff --git a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
index 4557714..0204467 100644
--- a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
@@ -10,7 +10,7 @@
 #include "build/build_config.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
-#include "chrome/browser/sync/test/integration/secondary_account_helper.h"
+#include "chrome/browser/sync/test/integration/secondary_account_sync_test.h"
 #include "chrome/browser/sync/test/integration/single_client_status_change_checker.h"
 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
 #include "chrome/browser/sync/test/integration/sync_test.h"
@@ -185,9 +185,9 @@
 }  // namespace
 
 class SingleClientWalletSyncTest : public UssWalletSwitchToggler,
-                                   public SyncTest {
+                                   public SecondaryAccountSyncTest {
  public:
-  SingleClientWalletSyncTest() : SyncTest(SINGLE_CLIENT) {}
+  SingleClientWalletSyncTest() {}
   ~SingleClientWalletSyncTest() override {}
 
  protected:
@@ -1065,14 +1065,9 @@
   }
   ~SingleClientWalletSecondaryAccountSyncTest() override {}
 
-  void SetUpInProcessBrowserTestFixture() override {
-    fake_gaia_cookie_manager_factory_ =
-        secondary_account_helper::SetUpFakeGaiaCookieManagerService();
-  }
-
   void SetUpOnMainThread() override {
 #if defined(OS_CHROMEOS)
-    secondary_account_helper::InitNetwork();
+    InitNetwork();
 #endif  // defined(OS_CHROMEOS)
   }
 
@@ -1081,9 +1076,6 @@
  private:
   base::test::ScopedFeatureList features_;
 
-  secondary_account_helper::ScopedFakeGaiaCookieManagerServiceFactory
-      fake_gaia_cookie_manager_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(SingleClientWalletSecondaryAccountSyncTest);
 };
 
@@ -1108,7 +1100,7 @@
       {CreateDefaultSyncWalletCard(), CreateDefaultSyncPaymentsCustomerData()});
 
   // Set up Sync in transport mode for a non-primary account.
-  secondary_account_helper::SignInSecondaryAccount(profile(), "user@email.com");
+  SignInSecondaryAccount(profile(), "user@email.com");
   ASSERT_TRUE(GetClient(0)->AwaitSyncSetupCompletion(
       /*skip_passphrase_verification=*/false));
   ASSERT_EQ(syncer::SyncService::TransportState::ACTIVE,
@@ -1137,7 +1129,7 @@
 
   // Simulate the user opting in to full Sync: Make the account primary, and
   // set first-time setup to complete.
-  secondary_account_helper::MakeAccountPrimary(profile(), "user@email.com");
+  MakeAccountPrimary(profile(), "user@email.com");
   GetSyncService(0)->GetUserSettings()->SetFirstSetupComplete();
 
   // Wait for Sync to get reconfigured into feature mode.
@@ -1180,7 +1172,7 @@
   GetFakeServer()->SetWalletData({CreateDefaultSyncWalletCard()});
 
   // Set up Sync in transport mode for a non-primary account.
-  secondary_account_helper::SignInSecondaryAccount(profile(), "user@email.com");
+  SignInSecondaryAccount(profile(), "user@email.com");
   ASSERT_TRUE(GetClient(0)->AwaitSyncSetupCompletion(
       /*skip_passphrase_verification=*/false));
   ASSERT_EQ(syncer::SyncService::TransportState::ACTIVE,
@@ -1206,7 +1198,7 @@
   EXPECT_EQ(0U, GetServerCards(profile_data).size());
 
   // Simulate the user opting in to full Sync: First, make the account primary.
-  secondary_account_helper::MakeAccountPrimary(profile(), "user@email.com");
+  MakeAccountPrimary(profile(), "user@email.com");
 
   // Now start actually configuring Sync.
   auto setup_handle = GetSyncService(0)->GetSetupInProgressHandle();
diff --git a/chrome/browser/sync/test/integration/sync_test.h b/chrome/browser/sync/test/integration/sync_test.h
index eb4aa17..266371fe 100644
--- a/chrome/browser/sync/test/integration/sync_test.h
+++ b/chrome/browser/sync/test/integration/sync_test.h
@@ -43,7 +43,7 @@
 // To disable a test from running on Chromium waterfalls, you would still use
 // the default DISABLED_test_name macro. To disable it from running as an E2E
 // test outside Chromium waterfalls you would need to remove the E2E* macro.
-#define MACRO_CONCAT(prefix, test_name) prefix ## _ ## test_name
+#define MACRO_CONCAT(prefix, test_name) prefix##_##test_name
 #define E2E_ONLY(test_name) MACRO_CONCAT(DISABLED_E2ETest, test_name)
 #define E2E_ENABLED(test_name) MACRO_CONCAT(test_name, E2ETest)
 
@@ -328,6 +328,9 @@
   // The FakeServer used in tests with server type IN_PROCESS_FAKE_SERVER.
   std::unique_ptr<fake_server::FakeServer> fake_server_;
 
+  // The factory used to mock out GAIA signin.
+  network::TestURLLoaderFactory test_url_loader_factory_;
+
  protected:
   virtual void BeforeSetupClient(int index);
 
@@ -501,9 +504,6 @@
   // Used to start and stop the local test server.
   base::Process test_server_;
 
-  // The factory used to mock out GAIA signin.
-  network::TestURLLoaderFactory test_url_loader_factory_;
-
   // The shared URLLoaderFactory backed by |test_url_loader_factory_|.
   scoped_refptr<network::WeakWrapperSharedURLLoaderFactory>
       test_shared_url_loader_factory_;
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 155302e..f8cf465c 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1744,6 +1744,7 @@
       "//ash/public/cpp/vector_icons",
       "//chrome/browser/chromeos",
       "//chrome/browser/chromeos/android_sms:android_sms_urls",
+      "//chromeos/audio",
       "//chromeos/components/multidevice",
       "//chromeos/components/multidevice/debug_webui",
       "//chromeos/components/multidevice/logging",
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 7b392d0..27290da 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -714,9 +714,28 @@
 ///////////////////////////////////////////////////////////////////////////////
 // Browser, OnBeforeUnload handling:
 
+Browser::WarnBeforeClosingResult Browser::MaybeWarnBeforeClosing(
+    Browser::WarnBeforeClosingCallback warn_callback) {
+  // If the browser can close right away (there are no pending downloads we need
+  // to prompt about) then there's no need to warn. In the future, we might need
+  // to check other conditions as well.
+  if (CanCloseWithInProgressDownloads())
+    return WarnBeforeClosingResult::kOkToClose;
+
+  DCHECK(!warn_before_closing_callback_)
+      << "Tried to close window during close warning; dialog should be modal.";
+  warn_before_closing_callback_ = std::move(warn_callback);
+  return WarnBeforeClosingResult::kDoNotClose;
+}
+
 bool Browser::ShouldCloseWindow() {
-  if (!CanCloseWithInProgressDownloads())
+  // If the user needs to see one or more warnings, hold off closing the
+  // browser.
+  const WarnBeforeClosingResult result = MaybeWarnBeforeClosing(base::BindOnce(
+      &Browser::FinishWarnBeforeClosing, weak_factory_.GetWeakPtr()));
+  if (result == WarnBeforeClosingResult::kDoNotClose)
     return false;
+
   if (IsFastTabUnloadEnabled())
     return fast_unload_controller_->ShouldCloseWindow();
   return unload_controller_->ShouldCloseWindow();
@@ -813,29 +832,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 // In-progress download termination handling:
 
-void Browser::InProgressDownloadResponse(bool cancel_downloads) {
-  if (cancel_downloads) {
-    cancel_download_confirmation_state_ = RESPONSE_RECEIVED;
-    chrome::CloseWindow(this);
-    return;
-  }
-
-  // Sets the confirmation state to NOT_PROMPTED so that if the user tries to
-  // close again we'll show the warning again.
-  cancel_download_confirmation_state_ = NOT_PROMPTED;
-
-  // Show the download page so the user can figure-out what downloads are still
-  // in-progress.
-  chrome::ShowDownloads(this);
-
-  // Reset UnloadController::is_attempting_to_close_browser_ so that we don't
-  // prompt every time any tab is closed. http://crbug.com/305516
-  if (IsFastTabUnloadEnabled())
-    fast_unload_controller_->CancelWindowClose();
-  else
-    unload_controller_->CancelWindowClose();
-}
-
 Browser::DownloadClosePreventionType Browser::OkToCloseWithInProgressDownloads(
     int* num_downloads_blocking) const {
   DCHECK(num_downloads_blocking);
@@ -2485,6 +2481,42 @@
   return false;
 }
 
+void Browser::InProgressDownloadResponse(bool cancel_downloads) {
+  if (cancel_downloads) {
+    cancel_download_confirmation_state_ = RESPONSE_RECEIVED;
+    std::move(warn_before_closing_callback_)
+        .Run(WarnBeforeClosingResult::kOkToClose);
+    return;
+  }
+
+  // Sets the confirmation state to NOT_PROMPTED so that if the user tries to
+  // close again we'll show the warning again.
+  cancel_download_confirmation_state_ = NOT_PROMPTED;
+
+  // Show the download page so the user can figure-out what downloads are still
+  // in-progress.
+  chrome::ShowDownloads(this);
+
+  std::move(warn_before_closing_callback_)
+      .Run(WarnBeforeClosingResult::kDoNotClose);
+}
+
+void Browser::FinishWarnBeforeClosing(WarnBeforeClosingResult result) {
+  switch (result) {
+    case WarnBeforeClosingResult::kOkToClose:
+      chrome::CloseWindow(this);
+      break;
+    case WarnBeforeClosingResult::kDoNotClose:
+      // Reset UnloadController::is_attempting_to_close_browser_ so that we
+      // don't prompt every time any tab is closed. http://crbug.com/305516
+      if (IsFastTabUnloadEnabled())
+        fast_unload_controller_->CancelWindowClose();
+      else
+        unload_controller_->CancelWindowClose();
+      break;
+  }
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Browser, Assorted utility functions (private):
 
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h
index af984a0..29e83e11 100644
--- a/chrome/browser/ui/browser.h
+++ b/chrome/browser/ui/browser.h
@@ -12,6 +12,7 @@
 #include <string>
 #include <vector>
 
+#include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
@@ -156,6 +157,16 @@
     DOWNLOAD_CLOSE_LAST_WINDOW_IN_INCOGNITO_PROFILE,
   };
 
+  // Represents the result of the user being warned before closing the browser.
+  // See WarnBeforeClosingCallback and WarnBeforeClosing() below.
+  enum class WarnBeforeClosingResult { kOkToClose, kDoNotClose };
+
+  // Callback that receives the result of a user being warned about closing a
+  // browser window (for example, if closing the window would interrupt a
+  // download). The parameter is whether the close should proceed.
+  using WarnBeforeClosingCallback =
+      base::OnceCallback<void(WarnBeforeClosingResult)>;
+
   struct CreateParams {
     explicit CreateParams(Profile* profile, bool user_gesture);
     CreateParams(Type type, Profile* profile, bool user_gesture);
@@ -338,9 +349,29 @@
 
   // OnBeforeUnload handling //////////////////////////////////////////////////
 
+  // Displays any necessary warnings to the user on taking an action that might
+  // close the browser (for example, warning if there are downloads in progress
+  // that would be interrupted).
+  //
+  // Distinct from ShouldCloseWindow() (which calls this method) because this
+  // method does not consider beforeunload handler, only things the user should
+  // be prompted about.
+  //
+  // If no warnings are needed, the method returns kOkToClose, indicating that
+  // the close can proceed immediately, and the callback is not called. If the
+  // method returns kDoNotClose, closing should be handled by |warn_callback|
+  // (and then only if the callback receives the kOkToClose value).
+  WarnBeforeClosingResult MaybeWarnBeforeClosing(
+      WarnBeforeClosingCallback warn_callback);
+
   // Gives beforeunload handlers the chance to cancel the close. Returns whether
   // to proceed with the close. If called while the process begun by
   // TryToCloseWindow is in progress, returns false without taking action.
+  //
+  // If you don't care about beforeunload handlers and just want to prompt the
+  // user that they might lose an in-progress operation, call
+  // MaybeWarnBeforeClosing() instead (ShouldCloseWindow() also calls this
+  // method).
   bool ShouldCloseWindow();
 
   // Begins the process of confirming whether the associated browser can be
@@ -380,12 +411,6 @@
 
   // In-progress download termination handling /////////////////////////////////
 
-  // Called when the user has decided whether to proceed or not with the browser
-  // closure.  |cancel_downloads| is true if the downloads should be canceled
-  // and the browser closed, false if the browser should stay open and the
-  // downloads running.
-  void InProgressDownloadResponse(bool cancel_downloads);
-
   // Indicates whether or not this browser window can be closed, or
   // would be blocked by in-progress downloads.
   // If executing downloads would be cancelled by this window close,
@@ -840,6 +865,17 @@
   // Returns true if the window can close, false otherwise.
   bool CanCloseWithInProgressDownloads();
 
+  // Called when the user has decided whether to proceed or not with the browser
+  // closure.  |cancel_downloads| is true if the downloads should be canceled
+  // and the browser closed, false if the browser should stay open and the
+  // downloads running.
+  void InProgressDownloadResponse(bool cancel_downloads);
+
+  // Called when all warnings have completed when attempting to close the
+  // browser directly (e.g. via hotkey, close button, terminate signal, etc.)
+  // Used as a WarnBeforeClosingCallback by ShouldCloseWindow().
+  void FinishWarnBeforeClosing(WarnBeforeClosingResult result);
+
   // Assorted utility functions ///////////////////////////////////////////////
 
   // Sets the specified browser as the delegate of the WebContents and all the
@@ -1040,6 +1076,8 @@
 
   std::unique_ptr<ScopedKeepAlive> keep_alive_;
 
+  WarnBeforeClosingCallback warn_before_closing_callback_;
+
   // The following factory is used for chrome update coalescing.
   base::WeakPtrFactory<Browser> chrome_updater_factory_;
 
diff --git a/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller.mm b/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller.mm
index e78f12a4..23fb7a69 100644
--- a/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller.mm
+++ b/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller.mm
@@ -388,7 +388,7 @@
   [shareButton_ setFrameOrigin:origin];
   [shareButton_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
   [shareButton_ setTarget:self];
-  [shareButton_ setKeyEquivalent:kKeyEquivalentReturn];
+  [shareButton_ setKeyEquivalent:kKeyEquivalentEscape];
   [shareButton_ setAction:@selector(sharePressed:)];
   [content addSubview:shareButton_];
 
@@ -401,7 +401,7 @@
   [cancelButton_ setFrameOrigin:origin];
   [cancelButton_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
   [cancelButton_ setTarget:self];
-  [cancelButton_ setKeyEquivalent:kKeyEquivalentEscape];
+  [cancelButton_ setKeyEquivalent:kKeyEquivalentReturn];
   [cancelButton_ setAction:@selector(cancelPressed:)];
   [content addSubview:cancelButton_];
 }
diff --git a/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller_unittest.mm b/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller_unittest.mm
index 60d84b8..2002eea4 100644
--- a/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller_unittest.mm
@@ -171,6 +171,12 @@
   EXPECT_TRUE([[items objectAtIndex:1] imageRepresentation] != nil);
 }
 
+TEST_F(DesktopMediaPickerControllerTest, CancelIsDefault) {
+  [controller_ showWindow:nil];
+  EXPECT_EQ([[controller_ window] defaultButtonCell],
+            [[controller_ cancelButton] cell]);
+}
+
 TEST_F(DesktopMediaPickerControllerTest, ClickShareScreen) {
   [controller_ showWindow:nil];
   ChangeType(DesktopMediaID::TYPE_SCREEN);
diff --git a/chrome/browser/ui/passwords/manage_passwords_view_utils.cc b/chrome/browser/ui/passwords/manage_passwords_view_utils.cc
index 685039e..b47f60b 100644
--- a/chrome/browser/ui/passwords/manage_passwords_view_utils.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_view_utils.cc
@@ -53,6 +53,16 @@
       net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
 }
 
+bool IsSignedInAndSyncingPasswordsNormally(Profile* profile) {
+  return password_manager_util::IsSyncingWithNormalEncryption(
+      ProfileSyncServiceFactory::GetForProfile(profile));
+}
+
+bool IsGooglePasswordManagerEnabled() {
+  return base::FeatureList::IsEnabled(
+      password_manager::features::kGooglePasswordManager);
+}
+
 }  // namespace
 
 gfx::ImageSkia ScaleImageForAccountAvatar(gfx::ImageSkia skia_image) {
@@ -200,11 +210,11 @@
 }
 
 bool ShouldManagePasswordsinGooglePasswordManager(Profile* profile) {
-  return base::FeatureList::IsEnabled(
-             password_manager::features::kGooglePasswordManager) &&
-         password_manager_util::GetPasswordSyncState(
-             ProfileSyncServiceFactory::GetForProfile(profile)) ==
-             password_manager::SYNCING_NORMAL_ENCRYPTION;
+  // To make sure that the experiment groups contain the same proportions of
+  // signed in and syncing users, we need to check the sync state before
+  // checking the feature flag.
+  return IsSignedInAndSyncingPasswordsNormally(profile) &&
+         IsGooglePasswordManagerEnabled();
 }
 
 // Navigation is handled differently on Android.
@@ -221,10 +231,15 @@
                                    ManagePasswordsReferrer referrer) {
   UMA_HISTOGRAM_ENUMERATION("PasswordManager.ManagePasswordsReferrer",
                             referrer);
-  if (ShouldManagePasswordsinGooglePasswordManager(browser->profile())) {
-    NavigateToGooglePasswordManager(browser->profile(), referrer);
-  } else {
-    chrome::ShowPasswordManager(browser);
+  if (IsSignedInAndSyncingPasswordsNormally(browser->profile())) {
+    UMA_HISTOGRAM_ENUMERATION(
+        "PasswordManager.ManagePasswordsReferrerSignedInAndSyncing", referrer);
+    if (IsGooglePasswordManagerEnabled()) {
+      NavigateToGooglePasswordManager(browser->profile(), referrer);
+      return;
+    }
   }
+
+  chrome::ShowPasswordManager(browser);
 }
 #endif  // !defined(OS_ANDROID)
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc
index d4bae96..0749f22 100644
--- a/chrome/browser/ui/tab_helpers.cc
+++ b/chrome/browser/ui/tab_helpers.cc
@@ -123,7 +123,7 @@
 #endif
 
 #if BUILDFLAG(ENABLE_OFFLINE_PAGES)
-#include "chrome/browser/offline_pages/auto_fetch_page_load_watcher.h"
+#include "chrome/browser/offline_pages/android/auto_fetch_page_load_watcher.h"
 #include "chrome/browser/offline_pages/offline_page_tab_helper.h"
 #include "chrome/browser/offline_pages/recent_tab_helper.h"
 #endif
diff --git a/chrome/browser/ui/unload_controller.cc b/chrome/browser/ui/unload_controller.cc
index f47d0f8..c09b659 100644
--- a/chrome/browser/ui/unload_controller.cc
+++ b/chrome/browser/ui/unload_controller.cc
@@ -205,8 +205,10 @@
 }
 
 void UnloadController::CancelWindowClose() {
-  // Closing of window can be canceled from a beforeunload handler.
-  DCHECK(is_attempting_to_close_browser_);
+  // Note that this method may be called if closing was canceled in a number of
+  // different ways, so is_attempting_to_close_browser_ may be false. In that
+  // case some of this code might not have an effect, but it's still useful to,
+  // for example, call the notification(s).
   tabs_needing_before_unload_fired_.clear();
   for (auto it = tabs_needing_unload_fired_.begin();
        it != tabs_needing_unload_fired_.end(); ++it) {
diff --git a/chrome/browser/ui/views/passwords/password_pending_view.cc b/chrome/browser/ui/views/passwords/password_pending_view.cc
index 21c4b5c..1bfc5ec 100644
--- a/chrome/browser/ui/views/passwords/password_pending_view.cc
+++ b/chrome/browser/ui/views/passwords/password_pending_view.cc
@@ -190,9 +190,9 @@
 std::unique_ptr<views::ToggleImageButton> CreatePasswordViewButton(
     views::ButtonListener* listener,
     bool are_passwords_revealed) {
-  std::unique_ptr<views::ToggleImageButton> button(
-      new views::ToggleImageButton(listener));
+  auto button = std::make_unique<views::ToggleImageButton>(listener);
   button->SetFocusForPlatform();
+  button->SetInstallFocusRingOnFocus(true);
   button->set_request_focus_on_press(true);
   button->SetTooltipText(
       l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_SHOW_PASSWORD));
diff --git a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
index 4996420a..e268ea4 100644
--- a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
+++ b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
@@ -276,6 +276,27 @@
   model_->AddSelectionFromAnchorTo(model_index);
 }
 
+bool BrowserTabStripController::BeforeCloseTab(int model_index,
+                                               CloseTabSource source) {
+  // Only consider pausing the close operation if this is the last remaining
+  // tab (since otherwise closing it won't close the browser window).
+  if (GetCount() > 1)
+    return true;
+
+  // Closing this tab will close the current window. See if the browser wants to
+  // prompt the user before the browser is allowed to close.
+  const Browser::WarnBeforeClosingResult result =
+      browser_view_->browser()->MaybeWarnBeforeClosing(base::BindOnce(
+          [](TabStrip* tab_strip, int model_index, CloseTabSource source,
+             Browser::WarnBeforeClosingResult result) {
+            if (result == Browser::WarnBeforeClosingResult::kOkToClose)
+              tab_strip->CloseTab(tab_strip->tab_at(model_index), source);
+          },
+          base::Unretained(tabstrip_), model_index, source));
+
+  return result == Browser::WarnBeforeClosingResult::kOkToClose;
+}
+
 void BrowserTabStripController::CloseTab(int model_index,
                                          CloseTabSource source) {
   // Cancel any pending tab transition.
diff --git a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.h b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.h
index a9d9e31a..d72fb97 100644
--- a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.h
+++ b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.h
@@ -59,6 +59,7 @@
   void ExtendSelectionTo(int model_index) override;
   void ToggleSelected(int model_index) override;
   void AddSelectionFromAnchorTo(int model_index) override;
+  bool BeforeCloseTab(int model_index, CloseTabSource source) override;
   void CloseTab(int model_index, CloseTabSource source) override;
   void ShowContextMenuForTab(Tab* tab,
                              const gfx::Point& p,
diff --git a/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc b/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc
index fbfe981..79f0571 100644
--- a/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc
+++ b/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc
@@ -91,6 +91,11 @@
 void FakeBaseTabStripController::AddSelectionFromAnchorTo(int index) {
 }
 
+bool FakeBaseTabStripController::BeforeCloseTab(int index,
+                                                CloseTabSource source) {
+  return true;
+}
+
 void FakeBaseTabStripController::CloseTab(int index, CloseTabSource source) {
   RemoveTab(index);
 }
diff --git a/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h b/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h
index 1c87628f..2bd65f805 100644
--- a/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h
+++ b/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h
@@ -35,6 +35,7 @@
   void ExtendSelectionTo(int index) override;
   void ToggleSelected(int index) override;
   void AddSelectionFromAnchorTo(int index) override;
+  bool BeforeCloseTab(int index, CloseTabSource source) override;
   void CloseTab(int index, CloseTabSource source) override;
   void ShowContextMenuForTab(Tab* tab,
                              const gfx::Point& p,
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index 6a60ade8..4840d6c2 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -978,6 +978,11 @@
   if (!IsValidModelIndex(model_index))
     return;
 
+  // If we're not allowed to close this tab for whatever reason, we should not
+  // proceed.
+  if (!controller_->BeforeCloseTab(model_index, source))
+    return;
+
   if (!in_tab_close_ && IsAnimating()) {
     // Cancel any current animations. We do this as remove uses the current
     // ideal bounds and we need to know ideal bounds is in a good state.
diff --git a/chrome/browser/ui/views/tabs/tab_strip_controller.h b/chrome/browser/ui/views/tabs/tab_strip_controller.h
index 100d554..f819c706 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_controller.h
+++ b/chrome/browser/ui/views/tabs/tab_strip_controller.h
@@ -63,6 +63,12 @@
   // Adds the selection the anchor to |index|.
   virtual void AddSelectionFromAnchorTo(int index) = 0;
 
+  // Prepares to close a tab. If closing the tab might require (for example) a
+  // user prompt, triggers that prompt and returns false, indicating that the
+  // current close operation should not proceed. If this method returns true,
+  // closing can proceed.
+  virtual bool BeforeCloseTab(int index, CloseTabSource source) = 0;
+
   // Closes the tab at the specified index in the model.
   virtual void CloseTab(int index, CloseTabSource source) = 0;
 
diff --git a/chrome/browser/ui/webui/management_ui_handler.cc b/chrome/browser/ui/webui/management_ui_handler.cc
index e3f9cbf..269ca8b 100644
--- a/chrome/browser/ui/webui/management_ui_handler.cc
+++ b/chrome/browser/ui/webui/management_ui_handler.cc
@@ -54,10 +54,30 @@
 namespace {
 
 #if defined(OS_CHROMEOS)
+
+base::string16 GetTitleWithEnterpriseDomain(
+    policy::BrowserPolicyConnectorChromeOS* connector) {
+  if (!connector->IsEnterpriseManaged()) {
+    return l10n_util::GetStringUTF16(IDS_MANAGEMENT_TITLE);
+  }
+  std::string display_domain = connector->GetEnterpriseDisplayDomain();
+
+  if (display_domain.empty()) {
+    if (!connector->IsActiveDirectoryManaged())
+      return l10n_util::GetStringUTF16(IDS_MANAGEMENT_TITLE);
+
+    display_domain = connector->GetRealm();
+  }
+
+  return l10n_util::GetStringFUTF16(IDS_MANAGEMENT_TITLE_BY,
+                                    base::UTF8ToUTF16(display_domain));
+}
+
 base::string16 GetEnterpriseDisplayDomain(
     policy::BrowserPolicyConnectorChromeOS* connector) {
-  if (!connector->IsEnterpriseManaged())
+  if (!connector->IsEnterpriseManaged()) {
     return l10n_util::GetStringUTF16(IDS_MANAGEMENT_DEVICE_NOT_MANAGED);
+  }
 
   std::string display_domain = connector->GetEnterpriseDisplayDomain();
 
@@ -72,6 +92,85 @@
                                     base::UTF8ToUTF16(display_domain));
 }
 
+void AddChromeOSReportingDevice(base::Value* report_sources) {
+  policy::BrowserPolicyConnectorChromeOS* connector =
+      g_browser_process->platform_part()->browser_policy_connector_chromeos();
+
+  // Only check for report status in managed environment.
+  if (!connector->IsEnterpriseManaged())
+    return;
+
+  policy::DeviceCloudPolicyManagerChromeOS* manager =
+      connector->GetDeviceCloudPolicyManager();
+
+  if (!manager)
+    return;
+
+  if (manager->GetSystemLogUploader()->upload_enabled()) {
+    report_sources->GetList().push_back(
+        base::Value(kManagementLogUploadEnabled));
+  }
+
+  const policy::DeviceStatusCollector* collector =
+      manager->GetStatusUploader()->device_status_collector();
+
+  if (collector->report_hardware_status()) {
+    report_sources->GetList().push_back(
+        base::Value(kManagementReportHardwareStatus));
+  }
+}
+
+void AddChromeOSReportingSecurity(base::Value* report_sources) {}
+
+void AddChromeOSReportingUserActivity(base::Value* report_sources) {
+  policy::BrowserPolicyConnectorChromeOS* connector =
+      g_browser_process->platform_part()->browser_policy_connector_chromeos();
+
+  // Only check for report status in managed environment.
+  if (!connector->IsEnterpriseManaged())
+    return;
+
+  policy::DeviceCloudPolicyManagerChromeOS* manager =
+      connector->GetDeviceCloudPolicyManager();
+
+  if (!manager)
+    return;
+
+  const policy::DeviceStatusCollector* collector =
+      manager->GetStatusUploader()->device_status_collector();
+
+  if (collector->report_activity_times()) {
+    report_sources->GetList().push_back(
+        base::Value(kManagementReportActivityTimes));
+  }
+  if (collector->report_users()) {
+    report_sources->GetList().push_back(base::Value(kManagementReportUsers));
+  }
+}
+
+void AddChromeOSReportingWeb(base::Value* report_sources) {
+  policy::BrowserPolicyConnectorChromeOS* connector =
+      g_browser_process->platform_part()->browser_policy_connector_chromeos();
+
+  // Only check for report status in managed environment.
+  if (!connector->IsEnterpriseManaged())
+    return;
+
+  policy::DeviceCloudPolicyManagerChromeOS* manager =
+      connector->GetDeviceCloudPolicyManager();
+
+  if (!manager)
+    return;
+
+  const policy::DeviceStatusCollector* collector =
+      manager->GetStatusUploader()->device_status_collector();
+
+  if (collector->report_network_interfaces()) {
+    report_sources->GetList().push_back(
+        base::Value(kManagementReportNetworkInterfaces));
+  }
+}
+
 void AddChromeOSReportingInfo(base::Value* report_sources) {
   policy::BrowserPolicyConnectorChromeOS* connector =
       g_browser_process->platform_part()->browser_policy_connector_chromeos();
@@ -167,10 +266,30 @@
 
 void ManagementUIHandler::RegisterMessages() {
   web_ui()->RegisterMessageCallback(
+      "getManagementTitle",
+      base::BindRepeating(&ManagementUIHandler::HandleGetManagementTitle,
+                          base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
       "getDeviceManagementStatus",
       base::BindRepeating(&ManagementUIHandler::HandleGetDeviceManagementStatus,
                           base::Unretained(this)));
   web_ui()->RegisterMessageCallback(
+      "getReportingDevice",
+      base::BindRepeating(&ManagementUIHandler::HandleGetReportingDevice,
+                          base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "getReportingSecurity",
+      base::BindRepeating(&ManagementUIHandler::HandleGetReportingSecurity,
+                          base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "getReportingUserActivity",
+      base::BindRepeating(&ManagementUIHandler::HandleGetReportingUserActivity,
+                          base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "getReportingWeb",
+      base::BindRepeating(&ManagementUIHandler::HandleGetReportingWeb,
+                          base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
       "getReportingInfo",
       base::BindRepeating(&ManagementUIHandler::HandleGetReportingInfo,
                           base::Unretained(this)));
@@ -184,9 +303,23 @@
                           base::Unretained(this)));
 }
 
-void ManagementUIHandler::HandleGetDeviceManagementStatus(
+void ManagementUIHandler::HandleGetManagementTitle(
     const base::ListValue* args) {
   AllowJavascript();
+#if defined(OS_CHROMEOS)
+  policy::BrowserPolicyConnectorChromeOS* connector =
+      g_browser_process->platform_part()->browser_policy_connector_chromeos();
+
+  base::Value title(GetTitleWithEnterpriseDomain(connector));
+  ResolveJavascriptCallback(args->GetList()[0] /* callback_id */, title);
+#else
+  RejectJavascriptCallback(args->GetList()[0] /* callback_id */,
+                           base::Value("Management overview"));
+#endif  // defined(OS_CHROMEOS)
+}
+
+void ManagementUIHandler::HandleGetDeviceManagementStatus(
+    const base::ListValue* args) {
   base::RecordAction(base::UserMetricsAction("ManagementPageViewed"));
 
 #if defined(OS_CHROMEOS)
@@ -203,6 +336,57 @@
 #endif  // defined(OS_CHROMEOS)
 }
 
+void ManagementUIHandler::HandleGetReportingDevice(
+    const base::ListValue* args) {
+  base::Value report_sources(base::Value::Type::LIST);
+
+// Only Chrome OS devices report status.
+#if defined(OS_CHROMEOS)
+  AddChromeOSReportingDevice(&report_sources);
+#endif  // defined(OS_CHROMEOS)
+
+  ResolveJavascriptCallback(args->GetList()[0] /* callback_id */,
+                            report_sources);
+}
+
+void ManagementUIHandler::HandleGetReportingSecurity(
+    const base::ListValue* args) {
+  base::Value report_sources(base::Value::Type::LIST);
+
+// Only Chrome OS devices report status.
+#if defined(OS_CHROMEOS)
+  AddChromeOSReportingSecurity(&report_sources);
+#endif  // defined(OS_CHROMEOS)
+
+  ResolveJavascriptCallback(args->GetList()[0] /* callback_id */,
+                            report_sources);
+}
+
+void ManagementUIHandler::HandleGetReportingUserActivity(
+    const base::ListValue* args) {
+  base::Value report_sources(base::Value::Type::LIST);
+
+// Only Chrome OS devices report status.
+#if defined(OS_CHROMEOS)
+  AddChromeOSReportingUserActivity(&report_sources);
+#endif  // defined(OS_CHROMEOS)
+
+  ResolveJavascriptCallback(args->GetList()[0] /* callback_id */,
+                            report_sources);
+}
+
+void ManagementUIHandler::HandleGetReportingWeb(const base::ListValue* args) {
+  base::Value report_sources(base::Value::Type::LIST);
+
+// Only Chrome OS devices report status.
+#if defined(OS_CHROMEOS)
+  AddChromeOSReportingWeb(&report_sources);
+#endif  // defined(OS_CHROMEOS)
+
+  ResolveJavascriptCallback(args->GetList()[0] /* callback_id */,
+                            report_sources);
+}
+
 void ManagementUIHandler::HandleGetReportingInfo(const base::ListValue* args) {
   base::Value report_sources(base::Value::Type::LIST);
 
diff --git a/chrome/browser/ui/webui/management_ui_handler.h b/chrome/browser/ui/webui/management_ui_handler.h
index 290a3575..ae85569 100644
--- a/chrome/browser/ui/webui/management_ui_handler.h
+++ b/chrome/browser/ui/webui/management_ui_handler.h
@@ -33,8 +33,18 @@
   void RegisterMessages() override;
 
  private:
+  void HandleGetManagementTitle(const base::ListValue* args);
+
   void HandleGetDeviceManagementStatus(const base::ListValue* args);
 
+  void HandleGetReportingDevice(const base::ListValue* args);
+
+  void HandleGetReportingSecurity(const base::ListValue* args);
+
+  void HandleGetReportingUserActivity(const base::ListValue* args);
+
+  void HandleGetReportingWeb(const base::ListValue* args);
+
   void HandleGetReportingInfo(const base::ListValue* args);
 
   void HandleGetExtensions(const base::ListValue* args);
diff --git a/chrome/browser/ui/webui/settings/chromeos/multidevice_handler.cc b/chrome/browser/ui/webui/settings/chromeos/multidevice_handler.cc
index a477f8f..e143e3fc 100644
--- a/chrome/browser/ui/webui/settings/chromeos/multidevice_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/multidevice_handler.cc
@@ -8,10 +8,10 @@
 #include "base/bind_helpers.h"
 #include "base/logging.h"
 #include "base/values.h"
+#include "chrome/browser/chromeos/android_sms/android_sms_app_helper_delegate_impl.h"
 #include "chrome/browser/chromeos/android_sms/android_sms_urls.h"
 #include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_factory.h"
 #include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_storage.h"
-#include "chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/chromeos/multidevice_setup/multidevice_setup_dialog.h"
 #include "chromeos/components/multidevice/logging/logging.h"
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index 31aae81f..e94c5b5 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -66,6 +66,7 @@
 #include "chrome/browser/ui/webui/chromeos/bluetooth_dialog_localized_strings_provider.h"
 #include "chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.h"
 #include "chrome/browser/ui/webui/chromeos/smb_shares/smb_shares_localized_strings_provider.h"
+#include "chrome/browser/ui/webui/management_ui_handler.h"
 #include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/services/multidevice_setup/public/cpp/url_provider.h"
@@ -417,6 +418,27 @@
     {"aboutUpdateWarningTitle", IDS_SETTINGS_ABOUT_PAGE_UPDATE_WARNING_TITLE},
     {"aboutUpdateWarningContinue",
      IDS_SETTINGS_ABOUT_PAGE_UPDATE_WARNING_CONTINUE_BUTTON},
+
+    // About page, Management subpage
+    {"managementTitle", IDS_MANAGEMENT_TITLE},
+    {"managementDeviceReporting", IDS_MANAGEMENT_DEVICE_REPORTING},
+    {"managementDeviceConfiguration", IDS_MANAGEMENT_DEVICE_CONFIGURATION},
+    {"managementExtensionReporting", IDS_MANAGEMENT_EXTENSION_REPORTING},
+    {"managementExtensionsInstalled", IDS_MANAGEMENT_EXTENSIONS_INSTALLED},
+    {"managementExtensionName", IDS_MANAGEMENT_EXTENSIONS_NAME},
+    {"managementExtensionPermissions", IDS_MANAGEMENT_EXTENSIONS_PERMISSIONS},
+    {kManagementLogUploadEnabled, IDS_MANAGEMENT_LOG_UPLOAD_ENABLED},
+    {kManagementReportActivityTimes,
+     IDS_MANAGEMENT_REPORT_DEVICE_ACTIVITY_TIMES},
+    {kManagementReportHardwareStatus,
+     IDS_MANAGEMENT_REPORT_DEVICE_HARDWARE_STATUS},
+    {kManagementReportNetworkInterfaces,
+     IDS_MANAGEMENT_REPORT_DEVICE_NETWORK_INTERFACES},
+    {kManagementReportUsers, IDS_MANAGEMENT_REPORT_DEVICE_USERS},
+    {"managementLocalTrustRoots", IDS_MANAGEMENT_LOCAL_TRUST_ROOTS},
+    {"managementTrustRootsNotConfigured",
+     IDS_MANAGEMENT_TRUST_ROOTS_NOT_CONFIGURED},
+    {"managementTrustRootsConfigured", IDS_MANAGEMENT_TRUST_ROOTS_CONFIGURED}
 #endif  // defined(OS_CHROMEOS)
   };
   AddLocalizedStringsBulk(html_source, kLocalizedStrings,
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui.cc b/chrome/browser/ui/webui/settings/md_settings_ui.cc
index 3188dde..9711557 100644
--- a/chrome/browser/ui/webui/settings/md_settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_ui.cc
@@ -75,14 +75,15 @@
 #include "ash/public/cpp/resources/grit/ash_public_unscaled_resources.h"
 #include "ash/public/cpp/stylus_utils.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/android_sms/android_sms_app_helper_delegate_impl.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/chromeos/crostini/crostini_util.h"
 #include "chrome/browser/chromeos/login/demo_mode/demo_session.h"
 #include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.h"
-#include "chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl.h"
 #include "chrome/browser/chromeos/multidevice_setup/multidevice_setup_client_factory.h"
 #include "chrome/browser/signin/account_tracker_service_factory.h"
 #include "chrome/browser/ui/webui/chromeos/smb_shares/smb_handler.h"
+#include "chrome/browser/ui/webui/management_ui_handler.h"
 #include "chrome/browser/ui/webui/settings/chromeos/accessibility_handler.h"
 #include "chrome/browser/ui/webui/settings/chromeos/account_manager_handler.h"
 #include "chrome/browser/ui/webui/settings/chromeos/android_apps_handler.h"
@@ -186,6 +187,7 @@
   AddSettingsPageUIHandler(std::make_unique<StartupPagesHandler>(web_ui));
 
 #if defined(OS_CHROMEOS)
+  AddSettingsPageUIHandler(std::make_unique<ManagementUIHandler>());
   AddSettingsPageUIHandler(
       std::make_unique<chromeos::settings::AccessibilityHandler>(web_ui));
   AddSettingsPageUIHandler(
@@ -285,7 +287,7 @@
             chromeos::multidevice_setup::MultiDeviceSetupClientFactory::
                 GetForProfile(profile),
             std::make_unique<
-                chromeos::multidevice_setup::AndroidSmsAppHelperDelegateImpl>(
+                chromeos::android_sms::AndroidSmsAppHelperDelegateImpl>(
                 profile)));
   }
   html_source->AddBoolean(
diff --git a/chrome/browser/web_applications/bookmark_apps/external_web_apps_unittest.cc b/chrome/browser/web_applications/bookmark_apps/external_web_apps_unittest.cc
index dc5d097..4ba47cfe 100644
--- a/chrome/browser/web_applications/bookmark_apps/external_web_apps_unittest.cc
+++ b/chrome/browser/web_applications/bookmark_apps/external_web_apps_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 #include <memory>
+#include <set>
 #include <vector>
 
 #include "base/bind.h"
@@ -39,8 +40,11 @@
 constexpr char kUserTypesTestDir[] = "user_types";
 
 #if defined(OS_CHROMEOS)
+constexpr char kAppAllUrl[] = "https://www.google.com/all";
 constexpr char kAppChildUrl[] = "https://www.google.com/child";
+constexpr char kAppGuestUrl[] = "https://www.google.com/guest";
 constexpr char kAppManagedUrl[] = "https://www.google.com/managed";
+constexpr char kAppSupervisedUrl[] = "https://www.google.com/supervised";
 constexpr char kAppUnmanagedUrl[] = "https://www.google.com/unmanaged";
 #endif
 
@@ -112,6 +116,13 @@
     return profile_builder.Build();
   }
 
+  // Helper that creates simple test guest profile.
+  std::unique_ptr<TestingProfile> CreateGuestProfile() {
+    TestingProfile::Builder profile_builder;
+    profile_builder.SetGuestSession();
+    return profile_builder.Build();
+  }
+
 #if defined(OS_CHROMEOS)
   // Helper that creates simple test profile and logs it into user manager.
   // This makes profile appears as a primary profile in ChromeOS.
@@ -123,6 +134,22 @@
     user_manager()->LoginUser(account_id);
     return profile;
   }
+
+  // Helper that creates simple test guest profile and logs it into user
+  // manager. This makes profile appears as a primary profile in ChromeOS.
+  std::unique_ptr<TestingProfile> CreateGuestProfileAndLogin() {
+    std::unique_ptr<TestingProfile> profile = CreateGuestProfile();
+    user_manager()->AddGuestUser();
+    user_manager()->LoginUser(user_manager()->GetGuestAccountId());
+    return profile;
+  }
+
+  void VerifySetOfApps(Profile* profile, const std::set<GURL>& expectations) {
+    const auto app_infos = ScanApps(profile, test_dir(kUserTypesTestDir));
+    ASSERT_EQ(expectations.size(), app_infos.size());
+    for (const auto& app_info : app_infos)
+      ASSERT_EQ(1u, expectations.count(app_info.url));
+  }
 #endif
 
  private:
@@ -293,55 +320,34 @@
   EXPECT_EQ(0u, app_infos.size());
 }
 
-TEST_F(ScanDirForExternalWebAppsTest, RecursiveSearch) {
-  const auto app_infos =
-      web_app::ScanDirForExternalWebAppsForTesting(test_dir(kUserTypesTestDir));
-
-  // Search is recursive and includes sub-directories. |kUserTypesTestDir|
-  // contains sub-directories for child and managed users. All apps from these
-  // folders has to be included.
-  EXPECT_EQ(3u, app_infos.size());
-}
-
 #if defined(OS_CHROMEOS)
-TEST_F(ScanDirForExternalWebAppsWithProfileTest, UnmanagedUser) {
-  const auto app_infos =
-      ScanApps(CreateProfileAndLogin().get(), test_dir(kUserTypesTestDir));
-  // This contains all apps, including for child and managed users.
-  const std::set<GURL> expectations(
-      {GURL(kAppChildUrl), GURL(kAppManagedUrl), GURL(kAppUnmanagedUrl)});
-  EXPECT_EQ(expectations.size(), app_infos.size());
-  for (const auto& app_info : app_infos)
-    EXPECT_EQ(1u, expectations.count(app_info.url));
+TEST_F(ScanDirForExternalWebAppsWithProfileTest, ChildUser) {
+  const auto profile = CreateProfileAndLogin();
+  profile->SetSupervisedUserId(supervised_users::kChildAccountSUID);
+  VerifySetOfApps(profile.get(), {GURL(kAppAllUrl), GURL(kAppChildUrl)});
 }
 
-TEST_F(ScanDirForExternalWebAppsWithProfileTest, SupervisedUser) {
-  const auto profile = CreateProfileAndLogin();
-  profile->SetSupervisedUserId("asdf");
-  const auto app_infos = ScanApps(profile.get(), test_dir(kUserTypesTestDir));
-  // This contains all apps, including for child and managed users once
-  // supervised user in general is not managed or child and there is no current
-  // separation for this type of user.
-  ASSERT_EQ(3u, app_infos.size());
+TEST_F(ScanDirForExternalWebAppsWithProfileTest, GuestUser) {
+  VerifySetOfApps(CreateGuestProfileAndLogin().get(),
+                  {GURL(kAppAllUrl), GURL(kAppGuestUrl)});
 }
 
 TEST_F(ScanDirForExternalWebAppsWithProfileTest, ManagedUser) {
   const auto profile = CreateProfileAndLogin();
   policy::ProfilePolicyConnectorFactory::GetForBrowserContext(profile.get())
       ->OverrideIsManagedForTesting(true);
-  const auto app_infos = ScanApps(profile.get(), test_dir(kUserTypesTestDir));
-  // This includes apps for managed users only.
-  ASSERT_EQ(1u, app_infos.size());
-  EXPECT_EQ(GURL(kAppManagedUrl), app_infos[0].url);
+  VerifySetOfApps(profile.get(), {GURL(kAppAllUrl), GURL(kAppManagedUrl)});
 }
 
-TEST_F(ScanDirForExternalWebAppsWithProfileTest, ChildUser) {
+TEST_F(ScanDirForExternalWebAppsWithProfileTest, SupervisedUser) {
   const auto profile = CreateProfileAndLogin();
-  profile->SetSupervisedUserId(supervised_users::kChildAccountSUID);
-  const auto app_infos = ScanApps(profile.get(), test_dir(kUserTypesTestDir));
-  // This includes apps for child users only.
-  ASSERT_EQ(1u, app_infos.size());
-  EXPECT_EQ(GURL(kAppChildUrl), app_infos[0].url);
+  profile->SetSupervisedUserId("asdf");
+  VerifySetOfApps(profile.get(), {GURL(kAppAllUrl), GURL(kAppSupervisedUrl)});
+}
+
+TEST_F(ScanDirForExternalWebAppsWithProfileTest, UnmanagedUser) {
+  VerifySetOfApps(CreateProfileAndLogin().get(),
+                  {GURL(kAppAllUrl), GURL(kAppUnmanagedUrl)});
 }
 
 TEST_F(ScanDirForExternalWebAppsWithProfileTest, NonPrimaryProfile) {
diff --git a/chrome/browser/web_applications/external_web_apps.cc b/chrome/browser/web_applications/external_web_apps.cc
index 0b95b33..6b2ba746 100644
--- a/chrome/browser/web_applications/external_web_apps.cc
+++ b/chrome/browser/web_applications/external_web_apps.cc
@@ -21,6 +21,7 @@
 #include "build/build_config.h"
 #include "chrome/browser/policy/profile_policy_connector.h"
 #include "chrome/browser/policy/profile_policy_connector_factory.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/common/chrome_paths.h"
 #include "content/public/browser/browser_thread.h"
@@ -54,15 +55,17 @@
 constexpr char kLaunchContainerTab[] = "tab";
 constexpr char kLaunchContainerWindow[] = "window";
 
+// kUserType is required key that specifies enumeration of user types for which
+// web app is visible. See kUserType* constants
+constexpr char kUserType[] = "user_type";
+
+constexpr char kUserTypeChild[] = "child";
+constexpr char kUserTypeGuest[] = "guest";
+constexpr char kUserTypeManaged[] = "managed";
+constexpr char kUserTypeSupervised[] = "supervised";
+constexpr char kUserTypeUnmanaged[] = "unmanaged";
+
 #if defined(OS_CHROMEOS)
-// Defines directory with web apps for child users.
-const base::FilePath::CharType kChildUsersSubdir[] =
-    FILE_PATH_LITERAL("child_users");
-
-// Defines directory with web apps for managed users.
-const base::FilePath::CharType kManagedUsersSubdir[] =
-    FILE_PATH_LITERAL("managed_users");
-
 // The sub-directory of the extensions directory in which to scan for external
 // web apps (as opposed to external extensions or external ARC apps).
 const base::FilePath::CharType kWebAppsSubDirectory[] =
@@ -94,11 +97,12 @@
 }
 
 std::vector<web_app::PendingAppManager::AppInfo> ScanDir(
-    const base::FilePath& dir) {
+    const base::FilePath& dir,
+    const std::string& user_type) {
   base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
   base::FilePath::StringType extension(FILE_PATH_LITERAL(".json"));
   base::FileEnumerator json_files(dir,
-                                  true,  // Recursive.
+                                  false,  // Recursive.
                                   base::FileEnumerator::FILES);
 
   std::vector<web_app::PendingAppManager::AppInfo> app_infos;
@@ -122,8 +126,28 @@
       continue;
     }
 
-    base::Value* value =
-        dict->FindKeyOfType(kFeatureName, base::Value::Type::STRING);
+    const base::Value* value =
+        dict->FindKeyOfType(kUserType, base::Value::Type::LIST);
+    if (!value) {
+      LOG(ERROR) << file.value() << " has no user type filter";
+      continue;
+    }
+    bool user_type_match = false;
+    for (const auto& it : value->GetList()) {
+      if (!it.is_string()) {
+        LOG(ERROR) << file.value() << " has invalid user type value";
+        user_type_match = false;
+        break;
+      }
+      user_type_match |= (it.GetString() == user_type);
+    }
+    if (!user_type_match) {
+      VLOG(1) << file.value() << " skip, does not match user type "
+              << user_type;
+      continue;
+    }
+
+    value = dict->FindKeyOfType(kFeatureName, base::Value::Type::STRING);
     if (value) {
       std::string feature_name = value->GetString();
       VLOG(1) << file.value() << " checking feature " << feature_name;
@@ -182,7 +206,7 @@
   return app_infos;
 }
 
-base::FilePath DetermineScanDir(Profile* profile) {
+base::FilePath DetermineScanDir(const Profile* profile) {
   base::FilePath dir;
 #if defined(OS_CHROMEOS)
   // As of mid 2018, only Chrome OS has default/external web apps, and
@@ -199,16 +223,6 @@
       LOG(ERROR) << "ScanForExternalWebApps: base::PathService::Get failed";
     } else {
       dir = dir.Append(kWebAppsSubDirectory);
-
-      // Limit web apps for known type of users. Unmanaged users have all apps,
-      // including sub-dirs.
-      if (profile->IsChild()) {
-        dir = dir.Append(kChildUsersSubdir);
-      } else if (policy::ProfilePolicyConnectorFactory::GetForBrowserContext(
-                     profile)
-                     ->IsManaged()) {
-        dir = dir.Append(kManagedUsersSubdir);
-      }
     }
   }
 
@@ -216,13 +230,28 @@
   return dir;
 }
 
+std::string DetermineUserType(Profile* profile) {
+  DCHECK(!profile->IsOffTheRecord());
+  if (profile->IsGuestSession())
+    return kUserTypeGuest;
+  if (profile->IsChild())
+    return kUserTypeChild;
+  if (profile->IsLegacySupervised())
+    return kUserTypeSupervised;
+  if (policy::ProfilePolicyConnectorFactory::GetForBrowserContext(profile)
+          ->IsManaged()) {
+    return kUserTypeManaged;
+  }
+  return kUserTypeUnmanaged;
+}
+
 }  // namespace
 
 namespace web_app {
 
 std::vector<web_app::PendingAppManager::AppInfo>
 ScanDirForExternalWebAppsForTesting(const base::FilePath& dir) {
-  return ScanDir(dir);
+  return ScanDir(dir, kUserTypeUnmanaged);
 }
 
 void ScanForExternalWebApps(Profile* profile,
@@ -246,7 +275,8 @@
       FROM_HERE,
       {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
        base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
-      base::BindOnce(&ScanDir, dir), std::move(callback));
+      base::BindOnce(&ScanDir, dir, DetermineUserType(profile)),
+      std::move(callback));
 }
 
 }  //  namespace web_app
diff --git a/chrome/common/mac/launchd.h b/chrome/common/mac/launchd.h
index 194acbb..ede71ff 100644
--- a/chrome/common/mac/launchd.h
+++ b/chrome/common/mac/launchd.h
@@ -9,6 +9,7 @@
 
 #include "base/macros.h"
 #include "base/memory/singleton.h"
+#include "chrome/common/mac/service_management.h"
 
 class Launchd {
  public:
@@ -33,11 +34,14 @@
 
   virtual ~Launchd();
 
-  // Return a dictionary with the launchd entries for job labeled |name|.
-  virtual CFDictionaryRef CopyJobDictionary(CFStringRef label);
+  virtual bool GetJobInfo(const std::string& label,
+                          mac::services::JobInfo* info);
 
-  // Return a dictionary for launchd process.
-  virtual CFDictionaryRef CopyDictionaryByCheckingIn(CFErrorRef* error);
+  // Checks in with launchd, retrieving |info| in the process. The |socket_key|
+  // argument is the name of a socket to extract from the job's sockets
+  // dictionary (see launchd.plist(5)).
+  virtual bool CheckIn(const std::string& socket_key,
+                       mac::services::JobCheckinInfo* info);
 
   // Remove a launchd process from launchd.
   virtual bool RemoveJob(const std::string& label);
diff --git a/chrome/common/mac/launchd.mm b/chrome/common/mac/launchd.mm
index 1feef45..0f19b35 100644
--- a/chrome/common/mac/launchd.mm
+++ b/chrome/common/mac/launchd.mm
@@ -14,7 +14,6 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/sys_string_conversions.h"
 #include "chrome/common/mac/service_management.h"
-#include "third_party/google_toolbox_for_mac/src/Foundation/GTMServiceManagement.h"
 
 namespace {
 
@@ -88,12 +87,14 @@
 
 Launchd::~Launchd() { }
 
-CFDictionaryRef Launchd::CopyJobDictionary(CFStringRef label) {
-  return GTMSMJobCopyDictionary(label);
+bool Launchd::GetJobInfo(const std::string& label,
+                         mac::services::JobInfo* info) {
+  return mac::services::GetJobInfo(label, info);
 }
 
-CFDictionaryRef Launchd::CopyDictionaryByCheckingIn(CFErrorRef* error) {
-  return GTMSMCopyJobCheckInDictionary(error);
+bool Launchd::CheckIn(const std::string& socket_key,
+                      mac::services::JobCheckinInfo* info) {
+  return mac::services::CheckIn(socket_key, info);
 }
 
 bool Launchd::RemoveJob(const std::string& label) {
diff --git a/chrome/common/mac/mock_launchd.h b/chrome/common/mac/mock_launchd.h
index 341e61d5..0bff694 100644
--- a/chrome/common/mac/mock_launchd.h
+++ b/chrome/common/mac/mock_launchd.h
@@ -37,8 +37,10 @@
               bool as_service);
   ~MockLaunchd() override;
 
-  CFDictionaryRef CopyJobDictionary(CFStringRef label) override;
-  CFDictionaryRef CopyDictionaryByCheckingIn(CFErrorRef* error) override;
+  bool GetJobInfo(const std::string& label,
+                  mac::services::JobInfo* info) override;
+  bool CheckIn(const std::string& socket_key,
+               mac::services::JobCheckinInfo* info) override;
   bool RemoveJob(const std::string& label) override;
   bool RestartJob(Domain domain,
                   Type type,
diff --git a/chrome/common/mac/mock_launchd.mm b/chrome/common/mac/mock_launchd.mm
index 950ea28..a60f388 100644
--- a/chrome/common/mac/mock_launchd.mm
+++ b/chrome/common/mac/mock_launchd.mm
@@ -108,51 +108,28 @@
 
 MockLaunchd::~MockLaunchd() {}
 
-CFDictionaryRef MockLaunchd::CopyJobDictionary(CFStringRef label) {
+bool MockLaunchd::GetJobInfo(const std::string& label,
+                             mac::services::JobInfo* info) {
   if (!as_service_) {
     std::unique_ptr<MultiProcessLock> running_lock(
         TakeNamedLock(pipe_name_, false));
     if (running_lock.get())
-      return NULL;
+      return false;
   }
 
-  CFStringRef program = CFSTR(LAUNCH_JOBKEY_PROGRAM);
-  CFStringRef program_pid = CFSTR(LAUNCH_JOBKEY_PID);
-  const void* keys[] = {program, program_pid};
-  base::ScopedCFTypeRef<CFStringRef> path(
-      base::SysUTF8ToCFStringRef(file_.value()));
-  int process_id = base::GetCurrentProcId();
-  base::ScopedCFTypeRef<CFNumberRef> pid(
-      CFNumberCreate(NULL, kCFNumberIntType, &process_id));
-  const void* values[] = {path, pid};
-  static_assert(base::size(keys) == base::size(values),
-                "keys must have the same number of elements as values");
-  return CFDictionaryCreate(kCFAllocatorDefault, keys, values, base::size(keys),
-                            &kCFTypeDictionaryKeyCallBacks,
-                            &kCFTypeDictionaryValueCallBacks);
+  info->program = file_.value();
+  info->pid = base::GetCurrentProcId();
+  return true;
 }
 
-CFDictionaryRef MockLaunchd::CopyDictionaryByCheckingIn(CFErrorRef* error) {
+bool MockLaunchd::CheckIn(const std::string& socket_key,
+                          mac::services::JobCheckinInfo* info) {
   checkin_called_ = true;
-  CFStringRef program = CFSTR(LAUNCH_JOBKEY_PROGRAM);
-  CFStringRef program_args = CFSTR(LAUNCH_JOBKEY_PROGRAMARGUMENTS);
-  base::ScopedCFTypeRef<CFStringRef> path(
-      base::SysUTF8ToCFStringRef(file_.value()));
-  const void* array_values[] = {path.get()};
-  base::ScopedCFTypeRef<CFArrayRef> args(CFArrayCreate(
-      kCFAllocatorDefault, array_values, 1, &kCFTypeArrayCallBacks));
 
-  if (!create_socket_) {
-    const void* keys[] = {program, program_args};
-    const void* values[] = {path, args};
-    static_assert(base::size(keys) == base::size(values),
-                  "keys must have the same number of elements as values");
-    return CFDictionaryCreate(kCFAllocatorDefault, keys, values,
-                              base::size(keys), &kCFTypeDictionaryKeyCallBacks,
-                              &kCFTypeDictionaryValueCallBacks);
-  }
+  info->program = file_.value();
+  if (!create_socket_)
+    return true;
 
-  CFStringRef socket_key = CFSTR(LAUNCH_JOBKEY_SOCKETS);
   int local_pipe = -1;
   EXPECT_TRUE(as_service_);
 
@@ -177,36 +154,12 @@
       CFSocketCreateWithSocketSignature(NULL, &signature, 0, NULL, NULL);
 
   local_pipe = CFSocketGetNative(socket);
-  EXPECT_NE(-1, local_pipe);
-  if (local_pipe == -1) {
-    if (error) {
-      *error =
-          CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainPOSIX, errno, NULL);
-    }
-    return NULL;
-  }
+  EXPECT_NE(-1, local_pipe) << "errno: " << errno;
+  if (local_pipe == -1)
+    return false;
 
-  base::ScopedCFTypeRef<CFNumberRef> socket_fd(
-      CFNumberCreate(NULL, kCFNumberIntType, &local_pipe));
-  const void* socket_array_values[] = {socket_fd};
-  base::ScopedCFTypeRef<CFArrayRef> sockets(CFArrayCreate(
-      kCFAllocatorDefault, socket_array_values, 1, &kCFTypeArrayCallBacks));
-  CFStringRef socket_dict_key = CFSTR("ServiceProcessSocket");
-  const void* socket_keys[] = {socket_dict_key};
-  const void* socket_values[] = {sockets};
-  static_assert(base::size(socket_keys) == base::size(socket_values),
-                "socket_keys must have the same number of elements "
-                "as socket_values");
-  base::ScopedCFTypeRef<CFDictionaryRef> socket_dict(CFDictionaryCreate(
-      kCFAllocatorDefault, socket_keys, socket_values, base::size(socket_keys),
-      &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
-  const void* keys[] = {program, program_args, socket_key};
-  const void* values[] = {path, args, socket_dict};
-  static_assert(base::size(keys) == base::size(values),
-                "keys must have the same number of elements as values");
-  return CFDictionaryCreate(kCFAllocatorDefault, keys, values, base::size(keys),
-                            &kCFTypeDictionaryKeyCallBacks,
-                            &kCFTypeDictionaryValueCallBacks);
+  info->socket = local_pipe;
+  return true;
 }
 
 bool MockLaunchd::RemoveJob(const std::string& label) {
@@ -227,8 +180,25 @@
 CFMutableDictionaryRef MockLaunchd::CreatePlistFromFile(Domain domain,
                                                         Type type,
                                                         CFStringRef name) {
-  base::ScopedCFTypeRef<CFDictionaryRef> dict(CopyDictionaryByCheckingIn(NULL));
-  return CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, dict);
+  mac::services::JobCheckinInfo info;
+  NSString* socket_key = @"ServiceProcessSocket";
+  if (!CheckIn(base::SysNSStringToUTF8(socket_key), &info))
+    return nil;
+
+  NSString* ns_program = base::SysUTF8ToNSString(info.program);
+
+  NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithDictionary:@{
+    @LAUNCH_JOBKEY_PROGRAM : ns_program,
+    @LAUNCH_JOBKEY_PROGRAMARGUMENTS : @[ ns_program ],
+  }];
+
+  if (create_socket_) {
+    dict[@LAUNCH_JOBKEY_SOCKETS] = @{socket_key : @(info.socket)};
+  }
+
+  // Callers expect to be given a reference but dictionaryWithDictionary: is
+  // autoreleased, so it's necessary to do a manual retain here.
+  return base::mac::NSToCFCast([dict retain]);
 }
 
 bool MockLaunchd::WritePlistToFile(Domain domain,
diff --git a/chrome/common/mac/service_management.h b/chrome/common/mac/service_management.h
index 6e5ef64e..5d78d33 100644
--- a/chrome/common/mac/service_management.h
+++ b/chrome/common/mac/service_management.h
@@ -8,9 +8,30 @@
 #include <string>
 #include <vector>
 
+#include "base/files/scoped_file.h"
+#include "base/optional.h"
+
 namespace mac {
 namespace services {
 
+struct JobInfo {
+  JobInfo();
+  JobInfo(const JobInfo& other);
+  ~JobInfo();
+
+  std::string program;
+  base::Optional<int> pid;
+};
+
+struct JobCheckinInfo {
+  JobCheckinInfo();
+  JobCheckinInfo(const JobCheckinInfo& info);
+  ~JobCheckinInfo();
+
+  std::string program;
+  int socket;
+};
+
 struct JobOptions {
   JobOptions();
   JobOptions(const JobOptions& other);
@@ -44,6 +65,9 @@
   bool auto_launch;
 };
 
+bool GetJobInfo(const std::string& label, JobInfo* info);
+bool CheckIn(const std::string& socket_key, JobCheckinInfo* info);
+
 bool SubmitJob(const JobOptions& options);
 bool RemoveJob(const std::string& label);
 
diff --git a/chrome/common/mac/service_management.mm b/chrome/common/mac/service_management.mm
index df57dbbc..52dbdd6 100644
--- a/chrome/common/mac/service_management.mm
+++ b/chrome/common/mac/service_management.mm
@@ -66,6 +66,47 @@
   return launch_data_get_errno(data);
 }
 
+bool StringFromLaunchDataDictEntry(launch_data_t dict,
+                                   const char* key,
+                                   std::string* value) {
+  launch_data_t entry = launch_data_dict_lookup(dict, key);
+  if (!entry || launch_data_get_type(entry) != LAUNCH_DATA_STRING)
+    return false;
+  *value = std::string(launch_data_get_string(entry));
+  return true;
+}
+
+bool IntFromLaunchDataDictEntry(launch_data_t dict,
+                                const char* key,
+                                int* value) {
+  launch_data_t entry = launch_data_dict_lookup(dict, key);
+  if (!entry || launch_data_get_type(entry) != LAUNCH_DATA_INTEGER)
+    return false;
+  *value = launch_data_get_integer(entry);
+  return true;
+}
+
+// Extracts the first integer value from |dict[key]|, which is itself an array,
+// and returns it in |*value|. This means that the type of dict is:
+//    map<string, array<int>>
+bool FirstIntFromLaunchDataDictEntry(launch_data_t dict,
+                                     const char* key,
+                                     int* value) {
+  launch_data_t array = launch_data_dict_lookup(dict, key);
+  if (!array || launch_data_get_type(array) != LAUNCH_DATA_ARRAY ||
+      launch_data_array_get_count(array) == 0) {
+    return false;
+  }
+  launch_data_t entry = launch_data_array_get_index(array, 0);
+  if (launch_data_get_type(entry) == LAUNCH_DATA_INTEGER)
+    *value = launch_data_get_integer(entry);
+  else if (launch_data_get_type(entry) == LAUNCH_DATA_FD)
+    *value = launch_data_get_fd(entry);
+  else
+    return false;
+  return true;
+}
+
 ScopedLaunchData DoServiceOp(const char* verb,
                              const std::string& label,
                              int* error) {
@@ -135,10 +176,64 @@
 namespace mac {
 namespace services {
 
+JobInfo::JobInfo() = default;
+JobInfo::JobInfo(const JobInfo& other) = default;
+JobInfo::~JobInfo() = default;
+
+JobCheckinInfo::JobCheckinInfo() = default;
+JobCheckinInfo::JobCheckinInfo(const JobCheckinInfo& other) = default;
+JobCheckinInfo::~JobCheckinInfo() = default;
+
 JobOptions::JobOptions() = default;
 JobOptions::JobOptions(const JobOptions& other) = default;
 JobOptions::~JobOptions() = default;
 
+bool GetJobInfo(const std::string& label, JobInfo* info) {
+  int error = 0;
+  ScopedLaunchData resp = DoServiceOp(LAUNCH_KEY_GETJOB, label, &error);
+
+  if (error)
+    return false;
+
+  std::string program;
+  if (!StringFromLaunchDataDictEntry(resp.get(), LAUNCH_JOBKEY_PROGRAM,
+                                     &program))
+    return false;
+
+  info->program = program;
+  int pid;
+  if (IntFromLaunchDataDictEntry(resp.get(), LAUNCH_JOBKEY_PID, &pid))
+    info->pid = pid;
+
+  return true;
+}
+
+bool CheckIn(const std::string& socket_key, JobCheckinInfo* info) {
+  ScopedLaunchData resp =
+      SendLaunchMessage(LaunchDataFromString(LAUNCH_KEY_CHECKIN));
+
+  if (launch_data_get_type(resp.get()) != LAUNCH_DATA_DICTIONARY)
+    return false;
+
+  std::string program;
+  if (!StringFromLaunchDataDictEntry(resp.get(), LAUNCH_JOBKEY_PROGRAM,
+                                     &program))
+    return false;
+
+  launch_data_t sockets = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SOCKETS);
+
+  if (launch_data_get_type(sockets) != LAUNCH_DATA_DICTIONARY)
+    return false;
+
+  int socket_fd;
+  if (!FirstIntFromLaunchDataDictEntry(sockets, socket_key.c_str(), &socket_fd))
+    return false;
+
+  info->program = program;
+  info->socket = socket_fd;
+  return true;
+}
+
 bool SubmitJob(const JobOptions& options) {
   base::scoped_nsobject<NSDictionary> options_dict =
       DictionaryForJobOptions(options);
diff --git a/chrome/common/service_process_util_mac.mm b/chrome/common/service_process_util_mac.mm
index 04e0197c..a3df2fd3 100644
--- a/chrome/common/service_process_util_mac.mm
+++ b/chrome/common/service_process_util_mac.mm
@@ -115,17 +115,15 @@
 
 bool GetServiceProcessData(std::string* version, base::ProcessId* pid) {
   base::mac::ScopedNSAutoreleasePool pool;
-  CFStringRef label = base::mac::NSToCFCast(GetServiceProcessLaunchDLabel());
-  base::scoped_nsobject<NSDictionary> launchd_conf(
-      base::mac::CFToNSCast(Launchd::GetInstance()->CopyJobDictionary(label)));
-  if (!launchd_conf.get()) {
+  std::string label = base::SysNSStringToUTF8(GetServiceProcessLaunchDLabel());
+  mac::services::JobInfo info;
+  if (!Launchd::GetInstance()->GetJobInfo(label, &info))
     return false;
-  }
   // Anything past here will return true in that there does appear
   // to be a service process of some sort registered with launchd.
   if (version) {
     *version = "0";
-    NSString* exe_path = launchd_conf.get()[@LAUNCH_JOBKEY_PROGRAM];
+    NSString* exe_path = base::SysUTF8ToNSString(info.program);
     if (exe_path) {
       NSString* bundle_path = [[[exe_path stringByDeletingLastPathComponent]
                                 stringByDeletingLastPathComponent]
@@ -151,41 +149,27 @@
     }
   }
   if (pid) {
-    *pid = -1;
-    NSNumber* ns_pid = launchd_conf.get()[@LAUNCH_JOBKEY_PID];
-    if (ns_pid) {
-     *pid = [ns_pid intValue];
-    }
+    *pid = info.pid ? *info.pid : -1;
   }
   return true;
 }
 
 bool ServiceProcessState::Initialize() {
-  CFErrorRef err = NULL;
-  CFDictionaryRef dict =
-      Launchd::GetInstance()->CopyDictionaryByCheckingIn(&err);
-  if (!dict) {
-    DLOG(ERROR) << "ServiceProcess must be launched by launchd. "
-                << "CopyLaunchdDictionaryByCheckingIn: " << err;
-    CFRelease(err);
+  mac::services::JobCheckinInfo info;
+  std::string socket_key =
+      base::SysNSStringToUTF8(GetServiceProcessLaunchDSocketKey());
+  if (!Launchd::GetInstance()->CheckIn(socket_key, &state_->job_info)) {
+    DLOG(ERROR) << "ServiceProcess must be launched by launchd but CheckIn "
+                << "failed.";
     return false;
   }
-  state_->launchd_conf.reset(dict);
   return true;
 }
 
 mojo::PlatformChannelServerEndpoint
 ServiceProcessState::GetServiceProcessServerEndpoint() {
-  DCHECK(state_);
-  NSDictionary* ns_launchd_conf = base::mac::CFToNSCast(state_->launchd_conf);
-  NSDictionary* socket_dict =
-      [ns_launchd_conf objectForKey:@ LAUNCH_JOBKEY_SOCKETS];
-  NSArray* sockets =
-      [socket_dict objectForKey:GetServiceProcessLaunchDSocketKey()];
-  DCHECK_EQ([sockets count], 1U);
-  int socket = [[sockets objectAtIndex:0] intValue];
   return mojo::PlatformChannelServerEndpoint(
-      mojo::PlatformHandle(base::ScopedFD(socket)));
+      mojo::PlatformHandle(base::ScopedFD(state_->job_info.socket)));
 }
 
 bool CheckServiceProcessReady() {
@@ -306,15 +290,8 @@
 
 bool ServiceProcessState::StateData::WatchExecutable() {
   base::mac::ScopedNSAutoreleasePool pool;
-  NSDictionary* ns_launchd_conf = base::mac::CFToNSCast(launchd_conf);
-  NSString* exe_path = ns_launchd_conf[@LAUNCH_JOBKEY_PROGRAM];
-  if (!exe_path) {
-    DLOG(ERROR) << "No " LAUNCH_JOBKEY_PROGRAM;
-    return false;
-  }
 
-  base::FilePath executable_path =
-      base::FilePath([exe_path fileSystemRepresentation]);
+  base::FilePath executable_path = base::FilePath(job_info.program);
   std::unique_ptr<ExecFilePathWatcherCallback> callback(
       new ExecFilePathWatcherCallback);
   if (!callback->Init(executable_path)) {
diff --git a/chrome/common/service_process_util_posix.h b/chrome/common/service_process_util_posix.h
index 3d56d7c..bcba5bfe 100644
--- a/chrome/common/service_process_util_posix.h
+++ b/chrome/common/service_process_util_posix.h
@@ -73,7 +73,7 @@
 #if defined(OS_MACOSX)
   bool WatchExecutable();
 
-  base::ScopedCFTypeRef<CFDictionaryRef> launchd_conf;
+  mac::services::JobCheckinInfo job_info;
   base::FilePathWatcher executable_watcher;
 #else
   std::unique_ptr<MultiProcessLock> initializing_lock;
diff --git a/chrome/common/webui_url_constants.cc b/chrome/common/webui_url_constants.cc
index 0139064..0c1d077 100644
--- a/chrome/common/webui_url_constants.cc
+++ b/chrome/common/webui_url_constants.cc
@@ -22,7 +22,6 @@
 const char kChromeUIAppIconHost[] = "app-icon";
 const char kChromeUIAppIconURL[] = "chrome://app-icon/";
 const char kChromeUIAppLauncherPageHost[] = "apps";
-const char kChromeUIAppListStartPageURL[] = "chrome://app-list/";
 const char kChromeUIAppsURL[] = "chrome://apps/";
 const char kChromeUIBluetoothInternalsHost[] = "bluetooth-internals";
 const char kChromeUIBookmarksHost[] = "bookmarks";
diff --git a/chrome/common/webui_url_constants.h b/chrome/common/webui_url_constants.h
index 09809e0..3a2bbe34 100644
--- a/chrome/common/webui_url_constants.h
+++ b/chrome/common/webui_url_constants.h
@@ -29,7 +29,6 @@
 extern const char kChromeUIAppIconHost[];
 extern const char kChromeUIAppIconURL[];
 extern const char kChromeUIAppLauncherPageHost[];
-extern const char kChromeUIAppListStartPageURL[];
 extern const char kChromeUIAppsURL[];
 extern const char kChromeUIBluetoothInternalsHost[];
 extern const char kChromeUIBookmarksHost[];
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
index 3b6a46d25..f401c50 100644
--- a/chrome/renderer/chrome_content_renderer_client.cc
+++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -1082,10 +1082,7 @@
     bool is_nacl_unrestricted,
     const Extension* extension,
     WebPluginParams* params) {
-  // Temporarily allow these whitelisted apps and WebUIs to use NaCl.
-  bool is_whitelisted_web_ui =
-      app_url.spec() == chrome::kChromeUIAppListStartPageURL;
-
+  // Temporarily allow these whitelisted apps to use NaCl.
   bool is_invoked_by_webstore_installed_extension = false;
   bool is_extension_unrestricted = false;
   bool is_extension_force_installed = false;
@@ -1117,7 +1114,6 @@
   //     context (hosted app URL or chrome-extension:// scheme).
   //  5) --enable-nacl is set.
   bool is_nacl_allowed_by_location =
-      is_whitelisted_web_ui ||
       AppCategorizer::IsWhitelistedApp(manifest_url, app_url) ||
       is_extension_unrestricted ||
       is_extension_force_installed ||
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index b023b51..76e6b61 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2987,10 +2987,10 @@
 
   if (enable_offline_pages) {
     sources += [
-      "../browser/offline_pages/auto_fetch_page_load_watcher_unittest.cc",
+      "../browser/offline_pages/android/auto_fetch_page_load_watcher_unittest.cc",
+      "../browser/offline_pages/android/offline_page_auto_fetcher_service_unittest.cc",
       "../browser/offline_pages/background_loader_offliner_unittest.cc",
       "../browser/offline_pages/download_archive_manager_unittest.cc",
-      "../browser/offline_pages/offline_page_auto_fetcher_service_unittest.cc",
       "../browser/offline_pages/offline_page_mhtml_archiver_unittest.cc",
       "../browser/offline_pages/offline_page_request_handler_unittest.cc",
       "../browser/offline_pages/offline_page_tab_helper_unittest.cc",
@@ -5315,8 +5315,8 @@
       "../browser/sync/test/integration/retry_verifier.h",
       "../browser/sync/test/integration/search_engines_helper.cc",
       "../browser/sync/test/integration/search_engines_helper.h",
-      "../browser/sync/test/integration/secondary_account_helper.cc",
-      "../browser/sync/test/integration/secondary_account_helper.h",
+      "../browser/sync/test/integration/secondary_account_sync_test.cc",
+      "../browser/sync/test/integration/secondary_account_sync_test.h",
       "../browser/sync/test/integration/session_hierarchy_match_checker.cc",
       "../browser/sync/test/integration/session_hierarchy_match_checker.h",
       "../browser/sync/test/integration/sessions_helper.cc",
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index 65468f8..dfb0d87 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -1512,6 +1512,8 @@
         '/chromedriver/shadow_dom_test.html'))
     elem = self._driver.FindElement("css", "* /deep/ #olderButton")
     self.assertTrue(elem.IsDisplayed())
+    elem2 = self._driver.FindElement("css", "* /deep/ #hostContent")
+    self.assertTrue(elem2.IsDisplayed())
     self._driver.ExecuteScript(
         'document.querySelector("#outerDiv").style.display="None";')
     self.assertFalse(elem.IsDisplayed())
diff --git a/chrome/test/data/chromedriver/shadow_dom_test.html b/chrome/test/data/chromedriver/shadow_dom_test.html
index c2f98a1c..eb167be3 100644
--- a/chrome/test/data/chromedriver/shadow_dom_test.html
+++ b/chrome/test/data/chromedriver/shadow_dom_test.html
@@ -9,7 +9,7 @@
 </script>
 <div id="outerDiv">
   <div id="innerDiv" style="border-style:solid;border-color:yellow">
-    stuff
+    <span id="hostContent">stuff</span>
   </div>
 </div>
 
diff --git a/chrome/test/data/subresource_filter/frame_set_special_urls.html b/chrome/test/data/subresource_filter/frame_set_special_urls.html
index e216330..6b6b25d 100644
--- a/chrome/test/data/subresource_filter/frame_set_special_urls.html
+++ b/chrome/test/data/subresource_filter/frame_set_special_urls.html
@@ -1,7 +1,7 @@
 <html>
   <body>
     <iframe name="blank" src="about:blank"></iframe>
-    <iframe name="js" src="javascript:'<html><\/html>'"></iframe>
+    <iframe name="js" src="javascript:'<script src=included_script.js></script>'"></iframe>
     <iframe name="srcdoc" srcdoc="<script src='included_script.js'></script>"></iframe>
   </body>
   <script>
@@ -17,11 +17,6 @@
     grandChild.src = "frame_with_included_script.html";
     blankFrame.contentDocument.body.appendChild(grandChild);
 
-    let jsFrame = document.getElementsByName("js")[0];
-    let script2 = document.createElement("script");
-    script2.src = "included_script.js";
-    jsFrame.contentDocument.body.appendChild(script2);
-
     // Add a frame with a data URL, making sure it loads a script pointing to
     // the right host and port.
     let dataFrame = document.createElement('iframe');
diff --git a/chrome/test/data/web_app_default_apps/empty_app_url/chrome_platform_status.json b/chrome/test/data/web_app_default_apps/empty_app_url/chrome_platform_status.json
index 9cb81a5..28dae837 100644
--- a/chrome/test/data/web_app_default_apps/empty_app_url/chrome_platform_status.json
+++ b/chrome/test/data/web_app_default_apps/empty_app_url/chrome_platform_status.json
@@ -1,5 +1,6 @@
 {
   "app_url": "",
   "create_shortcuts": true,
-  "launch_container": "tab"
+  "launch_container": "tab",
+  "user_type": ["unmanaged"]
 }
diff --git a/chrome/test/data/web_app_default_apps/enabled_by_finch/chrome_platform_status.json b/chrome/test/data/web_app_default_apps/enabled_by_finch/chrome_platform_status.json
index 27013c3..de603034 100644
--- a/chrome/test/data/web_app_default_apps/enabled_by_finch/chrome_platform_status.json
+++ b/chrome/test/data/web_app_default_apps/enabled_by_finch/chrome_platform_status.json
@@ -2,5 +2,6 @@
   "app_url": "https://www.chromestatus.com/features",
   "create_shortcuts": true,
   "feature_name": "test_feature_name",
-  "launch_container": "tab"
+  "launch_container": "tab",
+  "user_type": ["unmanaged"]
 }
diff --git a/chrome/test/data/web_app_default_apps/enabled_by_finch/google_search.json b/chrome/test/data/web_app_default_apps/enabled_by_finch/google_search.json
index 9fb169dc..13875ff 100644
--- a/chrome/test/data/web_app_default_apps/enabled_by_finch/google_search.json
+++ b/chrome/test/data/web_app_default_apps/enabled_by_finch/google_search.json
@@ -2,5 +2,6 @@
   "app_url": "https://google.com",
   "create_shortcuts": true,
   "feature_name": "test_feature_name",
-  "launch_container": "tab"
+  "launch_container": "tab",
+  "user_type": ["unmanaged"]
 }
diff --git a/chrome/test/data/web_app_default_apps/good_json/chrome_platform_status.json b/chrome/test/data/web_app_default_apps/good_json/chrome_platform_status.json
index 1481169c..0ca68aa 100644
--- a/chrome/test/data/web_app_default_apps/good_json/chrome_platform_status.json
+++ b/chrome/test/data/web_app_default_apps/good_json/chrome_platform_status.json
@@ -1,5 +1,6 @@
 {
   "app_url": "https://www.chromestatus.com/features",
   "create_shortcuts": true,
-  "launch_container": "tab"
+  "launch_container": "tab",
+  "user_type": ["unmanaged"]
 }
diff --git a/chrome/test/data/web_app_default_apps/good_json/google_io_2016.json b/chrome/test/data/web_app_default_apps/good_json/google_io_2016.json
index 0c1df76..11a0d882 100644
--- a/chrome/test/data/web_app_default_apps/good_json/google_io_2016.json
+++ b/chrome/test/data/web_app_default_apps/good_json/google_io_2016.json
@@ -1,4 +1,5 @@
 {
   "app_url": "https://events.google.com/io2016/?utm_source=web_app_manifest",
-  "launch_container": "window"
+  "launch_container": "window",
+  "user_type": ["unmanaged"]
 }
diff --git a/chrome/test/data/web_app_default_apps/invalid_launch_container/chrome_platform_status.json b/chrome/test/data/web_app_default_apps/invalid_launch_container/chrome_platform_status.json
index b1d6e10..c7c91625 100644
--- a/chrome/test/data/web_app_default_apps/invalid_launch_container/chrome_platform_status.json
+++ b/chrome/test/data/web_app_default_apps/invalid_launch_container/chrome_platform_status.json
@@ -1,5 +1,6 @@
 {
   "app_url": "https://www.chromestatus.com/features",
   "create_shortcuts": true,
-  "launch_container": "elephant"
+  "launch_container": "elephant",
+  "user_type": ["unmanaged"]
 }
diff --git a/chrome/test/data/web_app_default_apps/missing_launch_container/chrome_platform_status.json b/chrome/test/data/web_app_default_apps/missing_launch_container/chrome_platform_status.json
index d823afe..ba5a5ef 100644
--- a/chrome/test/data/web_app_default_apps/missing_launch_container/chrome_platform_status.json
+++ b/chrome/test/data/web_app_default_apps/missing_launch_container/chrome_platform_status.json
@@ -1,4 +1,5 @@
 {
   "app_url": "https://www.chromestatus.com/features",
-  "create_shortcuts": true
+  "create_shortcuts": true,
+  "user_type": ["unmanaged"]
 }
diff --git a/chrome/test/data/web_app_default_apps/mixed_json/malformed1.json b/chrome/test/data/web_app_default_apps/mixed_json/malformed1.json
index b4ee1955..5a25e29b 100644
--- a/chrome/test/data/web_app_default_apps/mixed_json/malformed1.json
+++ b/chrome/test/data/web_app_default_apps/mixed_json/malformed1.json
@@ -1,5 +1,6 @@
 {
   "app_url": "https://www.chromestatus.com/features",
   "launch_container": "window",
+  "user_type": ["unmanaged"],
   "this is malformed JSON because there's no end quote
 }
diff --git a/chrome/test/data/web_app_default_apps/mixed_json/polytimer.json b/chrome/test/data/web_app_default_apps/mixed_json/polytimer.json
index 3d71ed0..cf8d36e0 100644
--- a/chrome/test/data/web_app_default_apps/mixed_json/polytimer.json
+++ b/chrome/test/data/web_app_default_apps/mixed_json/polytimer.json
@@ -1,4 +1,5 @@
 {
   "app_url": "https://polytimer.rocks/?homescreen=1",
-  "launch_container": "window"
+  "launch_container": "window",
+  "user_type": ["unmanaged"]
 }
diff --git a/chrome/test/data/web_app_default_apps/user_types/web_apps/app_all.json b/chrome/test/data/web_app_default_apps/user_types/web_apps/app_all.json
new file mode 100644
index 0000000..5a8de914
--- /dev/null
+++ b/chrome/test/data/web_app_default_apps/user_types/web_apps/app_all.json
@@ -0,0 +1,6 @@
+{
+  "app_url": "https://www.google.com/all",
+  "create_shortcuts": true,
+  "launch_container": "tab",
+  "user_type": ["unmanaged", "managed", "child", "supervised", "guest"]
+}
diff --git a/chrome/test/data/web_app_default_apps/user_types/web_apps/app_child.json b/chrome/test/data/web_app_default_apps/user_types/web_apps/app_child.json
new file mode 100644
index 0000000..3eec5d7
--- /dev/null
+++ b/chrome/test/data/web_app_default_apps/user_types/web_apps/app_child.json
@@ -0,0 +1,6 @@
+{
+  "app_url": "https://www.google.com/child",
+  "create_shortcuts": true,
+  "launch_container": "tab",
+  "user_type": ["child"]
+}
diff --git a/chrome/test/data/web_app_default_apps/user_types/web_apps/app_guest.json b/chrome/test/data/web_app_default_apps/user_types/web_apps/app_guest.json
new file mode 100644
index 0000000..849c15a
--- /dev/null
+++ b/chrome/test/data/web_app_default_apps/user_types/web_apps/app_guest.json
@@ -0,0 +1,6 @@
+{
+  "app_url": "https://www.google.com/guest",
+  "create_shortcuts": true,
+  "launch_container": "tab",
+  "user_type": ["guest"]
+}
diff --git a/chrome/test/data/web_app_default_apps/user_types/web_apps/app_managed.json b/chrome/test/data/web_app_default_apps/user_types/web_apps/app_managed.json
new file mode 100644
index 0000000..a868f9e
--- /dev/null
+++ b/chrome/test/data/web_app_default_apps/user_types/web_apps/app_managed.json
@@ -0,0 +1,6 @@
+{
+  "app_url": "https://www.google.com/all",
+  "create_shortcuts": true,
+  "launch_container": "tab",
+  "user_type": ["managed"]
+}
diff --git a/chrome/test/data/web_app_default_apps/user_types/web_apps/app_supervised.json b/chrome/test/data/web_app_default_apps/user_types/web_apps/app_supervised.json
new file mode 100644
index 0000000..b0c99c30
--- /dev/null
+++ b/chrome/test/data/web_app_default_apps/user_types/web_apps/app_supervised.json
@@ -0,0 +1,6 @@
+{
+  "app_url": "https://www.google.com/supervised",
+  "create_shortcuts": true,
+  "launch_container": "tab",
+  "user_type": ["supervised"]
+}
diff --git a/chrome/test/data/web_app_default_apps/user_types/web_apps/app_unmanaged.json b/chrome/test/data/web_app_default_apps/user_types/web_apps/app_unmanaged.json
index a1145b3..0a96a59 100644
--- a/chrome/test/data/web_app_default_apps/user_types/web_apps/app_unmanaged.json
+++ b/chrome/test/data/web_app_default_apps/user_types/web_apps/app_unmanaged.json
@@ -1,5 +1,6 @@
 {
   "app_url": "https://www.google.com/unmanaged",
   "create_shortcuts": true,
-  "launch_container": "tab"
+  "launch_container": "tab",
+  "user_type": ["unmanaged"]
 }
diff --git a/chrome/test/data/web_app_default_apps/user_types/web_apps/child_users/app_child.json b/chrome/test/data/web_app_default_apps/user_types/web_apps/child_users/app_child.json
deleted file mode 100644
index 6563963..0000000
--- a/chrome/test/data/web_app_default_apps/user_types/web_apps/child_users/app_child.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-  "app_url": "https://www.google.com/child",
-  "create_shortcuts": true,
-  "launch_container": "tab"
-}
diff --git a/chrome/test/data/web_app_default_apps/user_types/web_apps/managed_users/app_managed.json b/chrome/test/data/web_app_default_apps/user_types/web_apps/managed_users/app_managed.json
deleted file mode 100644
index dcbf4f3e..0000000
--- a/chrome/test/data/web_app_default_apps/user_types/web_apps/managed_users/app_managed.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-  "app_url": "https://www.google.com/managed",
-  "create_shortcuts": true,
-  "launch_container": "tab"
-}
diff --git a/chrome/test/data/web_app_default_apps/wrong_user_type/wrong_user_type.json b/chrome/test/data/web_app_default_apps/wrong_user_type/wrong_user_type.json
new file mode 100644
index 0000000..ffee551
--- /dev/null
+++ b/chrome/test/data/web_app_default_apps/wrong_user_type/wrong_user_type.json
@@ -0,0 +1,5 @@
+{
+  "app_url": "https://events.google.com/io2016/?utm_source=web_app_manifest",
+  "launch_container": "window",
+  "user_type": ["unmanaged", "and_wrong_user_type"]
+}
diff --git a/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js b/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js
index 9c7e56b2..28dbff7 100644
--- a/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js
+++ b/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js
@@ -123,12 +123,6 @@
   ]),
 };
 
-// This test is flaky on ChromeOS. See https://crbug.com/895832.
-GEN('#if defined(OS_CHROMEOS)');
-GEN('#define MAYBE_All DISABLED_All');
-GEN('#else');
-GEN('#define MAYBE_All All');
-GEN('#endif');
-TEST_F('CrElementsInputTest', 'MAYBE_All', function() {
+TEST_F('CrElementsInputTest', 'All', function() {
   mocha.run();
 });
diff --git a/chrome/test/data/webui/cr_elements/cr_input_test.js b/chrome/test/data/webui/cr_elements/cr_input_test.js
index fba73e4..87509dda 100644
--- a/chrome/test/data/webui/cr_elements/cr_input_test.js
+++ b/chrome/test/data/webui/cr_elements/cr_input_test.js
@@ -73,11 +73,13 @@
     input = crInput.$.input;
     Polymer.dom.flush();
 
-    assertEquals(null, crInput.getAttribute('tabindex'));
-    assertEquals(true, input.disabled);
-    crInput.disabled = false;
-    assertEquals('14', crInput.getAttribute('tabindex'));
-    assertEquals(14, input.tabIndex);
+    return test_util.whenAttributeIs(input, 'tabindex', null).then(() => {
+      assertEquals(null, crInput.getAttribute('tabindex'));
+      assertEquals(true, input.disabled);
+      crInput.disabled = false;
+      assertEquals('14', crInput.getAttribute('tabindex'));
+      assertEquals(14, input.tabIndex);
+    });
   });
 
   test('pointerDownAndTabIndex', function() {
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn
index c351215..cd13474c 100644
--- a/chromeos/BUILD.gn
+++ b/chromeos/BUILD.gn
@@ -54,9 +54,7 @@
     "//components/prefs",
     "//components/user_manager",
     "//crypto:platform",
-    "//dbus",
     "//google_apis",
-    "//media/base:video_facing",
     "//services/network/public/cpp:cpp",
     "//third_party/protobuf:protobuf_lite",
     "//ui/gfx/geometry",  # For accelerometer.
@@ -72,25 +70,6 @@
     "account_manager/account_manager_factory.h",
     "app_mode/kiosk_oem_manifest_parser.cc",
     "app_mode/kiosk_oem_manifest_parser.h",
-    "attestation/attestation_flow.cc",
-    "attestation/attestation_flow.h",
-    "audio/audio_device.cc",
-    "audio/audio_device.h",
-    "audio/audio_devices_pref_handler.h",
-    "audio/audio_devices_pref_handler_impl.cc",
-    "audio/audio_devices_pref_handler_impl.h",
-    "audio/audio_devices_pref_handler_stub.cc",
-    "audio/audio_devices_pref_handler_stub.h",
-    "audio/audio_pref_observer.h",
-    "audio/chromeos_sounds.h",
-    "audio/cras_audio_handler.cc",
-    "audio/cras_audio_handler.h",
-    "disks/disk.cc",
-    "disks/disk.h",
-    "disks/disk_mount_manager.cc",
-    "disks/disk_mount_manager.h",
-    "disks/suspend_unmount_manager.cc",
-    "disks/suspend_unmount_manager.h",
     "geolocation/geoposition.cc",
     "geolocation/geoposition.h",
     "geolocation/simple_geolocation_provider.cc",
@@ -228,7 +207,9 @@
     "//chromeos/dbus:test_support",
   ]
   deps = [
-    "//chromeos/cryptohome",
+    "//chromeos/attestation:test_support",
+    "//chromeos/cryptohome:test_support",
+    "//chromeos/disks:test_support",
     "//chromeos/login/auth:test_support",
     "//chromeos/login/login_state:test_support",
     "//components/account_id",
@@ -239,14 +220,6 @@
     "//testing/gtest",
   ]
   sources = [
-    "attestation/mock_attestation_flow.cc",
-    "attestation/mock_attestation_flow.h",
-    "cryptohome/mock_async_method_caller.cc",
-    "cryptohome/mock_async_method_caller.h",
-    "cryptohome/mock_homedir_methods.cc",
-    "cryptohome/mock_homedir_methods.h",
-    "disks/mock_disk_mount_manager.cc",
-    "disks/mock_disk_mount_manager.h",
     "network/fake_network_device_handler.cc",
     "network/fake_network_device_handler.h",
     "network/mock_managed_network_configuration_handler.cc",
@@ -283,6 +256,8 @@
     ":test_support",
     ":test_support_without_gmock",
     "//base/test:test_support",
+    "//chromeos/attestation:unit_tests",
+    "//chromeos/audio:unit_tests",
     "//chromeos/cryptohome",
     "//chromeos/cryptohome:unit_tests",
     "//chromeos/dbus:authpolicy_proto",
@@ -291,6 +266,7 @@
     "//chromeos/dbus:power_manager_proto",
     "//chromeos/dbus:unit_tests",
     "//chromeos/dbus/services:unit_tests",
+    "//chromeos/disks:unit_tests",
     "//chromeos/login/auth:unit_tests",
     "//chromeos/login/login_state:unit_tests",
     "//chromeos/network:unit_tests",
@@ -307,7 +283,6 @@
     "//crypto:test_support",
     "//dbus:test_support",
     "//google_apis",
-    "//media/base:video_facing",
     "//mojo/core/embedder",
     "//net",
     "//net:test_support",
@@ -321,12 +296,6 @@
   sources = [
     "account_manager/account_manager_unittest.cc",
     "app_mode/kiosk_oem_manifest_parser_unittest.cc",
-    "attestation/attestation_flow_unittest.cc",
-    "audio/audio_devices_pref_handler_impl_unittest.cc",
-    "audio/cras_audio_handler_unittest.cc",
-    "disks/disk_mount_manager_unittest.cc",
-    "disks/disk_unittest.cc",
-    "disks/suspend_unmount_manager_unittest.cc",
     "geolocation/simple_geolocation_unittest.cc",
     "policy/weekly_time/time_utils_unittest.cc",
     "policy/weekly_time/weekly_time_interval_unittest.cc",
diff --git a/chromeos/attestation/BUILD.gn b/chromeos/attestation/BUILD.gn
new file mode 100644
index 0000000..e0e9af3
--- /dev/null
+++ b/chromeos/attestation/BUILD.gn
@@ -0,0 +1,56 @@
+# Copyright 2019 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("//testing/test.gni")
+
+assert(is_chromeos, "Non-Chrome-OS builds must not depend on //chromeos")
+
+component("attestation") {
+  defines = [ "IS_CHROMEOS_ATTESTATION_IMPL" ]
+  deps = [
+    "//base",
+    "//chromeos:chromeos_constants",
+    "//chromeos/cryptohome",
+    "//chromeos/dbus",
+    "//chromeos/dbus:cryptohome_proto",
+    "//components/account_id",
+    "//crypto",
+  ]
+  sources = [
+    "attestation_flow.cc",
+    "attestation_flow.h",
+  ]
+}
+
+source_set("test_support") {
+  testonly = true
+  public_deps = [
+    ":attestation",
+  ]
+  deps = [
+    "//base/test:test_support",
+    "//components/account_id",
+    "//testing/gmock",
+  ]
+  sources = [
+    "mock_attestation_flow.cc",
+    "mock_attestation_flow.h",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  deps = [
+    ":test_support",
+    "//base/test:test_support",
+    "//chromeos/cryptohome:test_support",
+    "//chromeos/dbus",
+    "//components/account_id",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+  sources = [
+    "attestation_flow_unittest.cc",
+  ]
+}
diff --git a/chromeos/attestation/DEPS b/chromeos/attestation/DEPS
new file mode 100644
index 0000000..5336acb7
--- /dev/null
+++ b/chromeos/attestation/DEPS
@@ -0,0 +1,12 @@
+noparent = True
+
+include_rules = [
+  "+base",
+  "+chromeos/chromeos_constants",
+  "+chromeos/cryptohome",
+  "+chromeos/dbus",
+  "+components/account_id",
+  "+crypto",
+  "+testing",
+  "+third_party/cros_system_api",
+]
diff --git a/chromeos/attestation/attestation_flow.cc b/chromeos/attestation/attestation_flow.cc
index f1c046fd..9c19421a 100644
--- a/chromeos/attestation/attestation_flow.cc
+++ b/chromeos/attestation/attestation_flow.cc
@@ -160,9 +160,7 @@
   async_caller_->AsyncTpmAttestationCreateEnrollRequest(
       server_proxy_->GetType(),
       base::Bind(&AttestationFlow::SendEnrollRequestToPCA,
-                 weak_factory_.GetWeakPtr(),
-                 on_failure,
-                 next_task));
+                 weak_factory_.GetWeakPtr(), on_failure, next_task));
 }
 
 void AttestationFlow::SendEnrollRequestToPCA(const base::Closure& on_failure,
@@ -178,11 +176,8 @@
 
   // Send the request to the Privacy CA.
   server_proxy_->SendEnrollRequest(
-      data,
-      base::Bind(&AttestationFlow::SendEnrollResponseToDaemon,
-                 weak_factory_.GetWeakPtr(),
-                 on_failure,
-                 next_task));
+      data, base::Bind(&AttestationFlow::SendEnrollResponseToDaemon,
+                       weak_factory_.GetWeakPtr(), on_failure, next_task));
 }
 
 void AttestationFlow::SendEnrollResponseToDaemon(
@@ -199,12 +194,9 @@
 
   // Forward the response to the attestation service to complete enrollment.
   async_caller_->AsyncTpmAttestationEnroll(
-      server_proxy_->GetType(),
-      data,
-      base::Bind(&AttestationFlow::OnEnrollComplete,
-                 weak_factory_.GetWeakPtr(),
-                 on_failure,
-                 next_task));
+      server_proxy_->GetType(), data,
+      base::Bind(&AttestationFlow::OnEnrollComplete, weak_factory_.GetWeakPtr(),
+                 on_failure, next_task));
 }
 
 void AttestationFlow::OnEnrollComplete(const base::Closure& on_failure,
@@ -230,8 +222,8 @@
     bool generate_new_key,
     const CertificateCallback& callback) {
   AttestationKeyType key_type = GetKeyTypeForProfile(certificate_profile);
-  std::string key_name = GetKeyNameForProfile(certificate_profile,
-                                              request_origin);
+  std::string key_name =
+      GetKeyNameForProfile(certificate_profile, request_origin);
   if (generate_new_key) {
     // Get the attestation service to create a Privacy CA certificate request.
     async_caller_->AsyncTpmAttestationCreateCertRequest(
diff --git a/chromeos/attestation/attestation_flow.h b/chromeos/attestation/attestation_flow.h
index d4b1c42..5faaf21 100644
--- a/chromeos/attestation/attestation_flow.h
+++ b/chromeos/attestation/attestation_flow.h
@@ -9,11 +9,11 @@
 #include <string>
 
 #include "base/callback_forward.h"
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
-#include "chromeos/chromeos_export.h"
 #include "chromeos/dbus/attestation_constants.h"
 #include "chromeos/dbus/dbus_method_call_status.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
@@ -33,10 +33,10 @@
 namespace attestation {
 
 // Interface for access to the Privacy CA server.
-class CHROMEOS_EXPORT ServerProxy {
+class COMPONENT_EXPORT(CHROMEOS_ATTESTATION) ServerProxy {
  public:
-  typedef base::Callback<void(bool success,
-                              const std::string& data)> DataCallback;
+  typedef base::Callback<void(bool success, const std::string& data)>
+      DataCallback;
   virtual ~ServerProxy();
   virtual void SendEnrollRequest(const std::string& request,
                                  const DataCallback& on_response) = 0;
@@ -56,7 +56,7 @@
 //    flow.GetCertificate(ENTERPRISE_USER_CERTIFICATE, false, callback);
 //
 // This class is not thread safe.
-class CHROMEOS_EXPORT AttestationFlow {
+class COMPONENT_EXPORT(CHROMEOS_ATTESTATION) AttestationFlow {
  public:
   typedef base::RepeatingCallback<
       void(AttestationStatus status, const std::string& pem_certificate_chain)>
diff --git a/chromeos/attestation/attestation_flow_unittest.cc b/chromeos/attestation/attestation_flow_unittest.cc
index ee926df..18a45d9 100644
--- a/chromeos/attestation/attestation_flow_unittest.cc
+++ b/chromeos/attestation/attestation_flow_unittest.cc
@@ -176,10 +176,12 @@
   std::unique_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>());
   proxy->DeferToFake(true);
   EXPECT_CALL(*proxy, GetType()).WillRepeatedly(DoDefault());
-  EXPECT_CALL(*proxy, SendEnrollRequest(
-      cryptohome::MockAsyncMethodCaller::kFakeAttestationEnrollRequest,
-      _)).Times(1)
-         .InSequence(flow_order);
+  EXPECT_CALL(
+      *proxy,
+      SendEnrollRequest(
+          cryptohome::MockAsyncMethodCaller::kFakeAttestationEnrollRequest, _))
+      .Times(1)
+      .InSequence(flow_order);
 
   std::string fake_enroll_response =
       cryptohome::MockAsyncMethodCaller::kFakeAttestationEnrollRequest;
@@ -197,10 +199,12 @@
       .Times(1)
       .InSequence(flow_order);
 
-  EXPECT_CALL(*proxy, SendCertificateRequest(
-      cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest,
-      _)).Times(1)
-         .InSequence(flow_order);
+  EXPECT_CALL(
+      *proxy,
+      SendCertificateRequest(
+          cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest, _))
+      .Times(1)
+      .InSequence(flow_order);
 
   std::string fake_cert_response =
       cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest;
@@ -217,10 +221,11 @@
                   cryptohome::MockAsyncMethodCaller::kFakeAttestationCert))
       .Times(1)
       .InSequence(flow_order);
-  AttestationFlow::CertificateCallback callback = base::Bind(
-      &AttestationFlowTest::QuitRunLoopCertificateCallback,
-      base::Unretained(this), base::Bind(&MockObserver::MockCertificateCallback,
-                                         base::Unretained(&observer)));
+  AttestationFlow::CertificateCallback callback =
+      base::Bind(&AttestationFlowTest::QuitRunLoopCertificateCallback,
+                 base::Unretained(this),
+                 base::Bind(&MockObserver::MockCertificateCallback,
+                            base::Unretained(&observer)));
 
   std::unique_ptr<ServerProxy> proxy_interface(proxy.release());
   AttestationFlow flow(&async_caller, &client, std::move(proxy_interface));
@@ -247,10 +252,11 @@
   EXPECT_CALL(observer,
               MockCertificateCallback(ATTESTATION_UNSPECIFIED_FAILURE, ""))
       .Times(1);
-  AttestationFlow::CertificateCallback callback = base::Bind(
-      &AttestationFlowTest::QuitRunLoopCertificateCallback,
-      base::Unretained(this), base::Bind(&MockObserver::MockCertificateCallback,
-                                         base::Unretained(&observer)));
+  AttestationFlow::CertificateCallback callback =
+      base::Bind(&AttestationFlowTest::QuitRunLoopCertificateCallback,
+                 base::Unretained(this),
+                 base::Bind(&MockObserver::MockCertificateCallback,
+                            base::Unretained(&observer)));
 
   std::unique_ptr<ServerProxy> proxy_interface(proxy.release());
   AttestationFlow flow(&async_caller, &client, std::move(proxy_interface));
@@ -281,8 +287,7 @@
               MockCertificateCallback(ATTESTATION_UNSPECIFIED_FAILURE, ""))
       .Times(1);
   AttestationFlow::CertificateCallback mock_callback = base::Bind(
-      &MockObserver::MockCertificateCallback,
-      base::Unretained(&observer));
+      &MockObserver::MockCertificateCallback, base::Unretained(&observer));
 
   std::unique_ptr<ServerProxy> proxy_interface(proxy.release());
   AttestationFlow flow(&async_caller, &client, std::move(proxy_interface));
@@ -304,17 +309,18 @@
   std::unique_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>());
   proxy->DeferToFake(false);
   EXPECT_CALL(*proxy, GetType()).WillRepeatedly(DoDefault());
-  EXPECT_CALL(*proxy, SendEnrollRequest(
-      cryptohome::MockAsyncMethodCaller::kFakeAttestationEnrollRequest,
-      _)).Times(1);
+  EXPECT_CALL(
+      *proxy,
+      SendEnrollRequest(
+          cryptohome::MockAsyncMethodCaller::kFakeAttestationEnrollRequest, _))
+      .Times(1);
 
   StrictMock<MockObserver> observer;
   EXPECT_CALL(observer,
               MockCertificateCallback(ATTESTATION_UNSPECIFIED_FAILURE, ""))
       .Times(1);
   AttestationFlow::CertificateCallback mock_callback = base::Bind(
-      &MockObserver::MockCertificateCallback,
-      base::Unretained(&observer));
+      &MockObserver::MockCertificateCallback, base::Unretained(&observer));
 
   std::unique_ptr<ServerProxy> proxy_interface(proxy.release());
   AttestationFlow flow(&async_caller, &client, std::move(proxy_interface));
@@ -342,17 +348,18 @@
   std::unique_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>());
   proxy->DeferToFake(true);
   EXPECT_CALL(*proxy, GetType()).WillRepeatedly(DoDefault());
-  EXPECT_CALL(*proxy, SendEnrollRequest(
-      cryptohome::MockAsyncMethodCaller::kFakeAttestationEnrollRequest,
-      _)).Times(1);
+  EXPECT_CALL(
+      *proxy,
+      SendEnrollRequest(
+          cryptohome::MockAsyncMethodCaller::kFakeAttestationEnrollRequest, _))
+      .Times(1);
 
   StrictMock<MockObserver> observer;
   EXPECT_CALL(observer,
               MockCertificateCallback(ATTESTATION_UNSPECIFIED_FAILURE, ""))
       .Times(1);
   AttestationFlow::CertificateCallback mock_callback = base::Bind(
-      &MockObserver::MockCertificateCallback,
-      base::Unretained(&observer));
+      &MockObserver::MockCertificateCallback, base::Unretained(&observer));
 
   std::unique_ptr<ServerProxy> proxy_interface(proxy.release());
   AttestationFlow flow(&async_caller, &client, std::move(proxy_interface));
@@ -382,9 +389,11 @@
   std::unique_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>());
   proxy->DeferToFake(true);
   EXPECT_CALL(*proxy, GetType()).WillRepeatedly(DoDefault());
-  EXPECT_CALL(*proxy, SendCertificateRequest(
-      cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest,
-      _)).Times(1);
+  EXPECT_CALL(
+      *proxy,
+      SendCertificateRequest(
+          cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest, _))
+      .Times(1);
 
   StrictMock<MockObserver> observer;
   EXPECT_CALL(observer,
@@ -393,8 +402,7 @@
                   cryptohome::MockAsyncMethodCaller::kFakeAttestationCert))
       .Times(1);
   AttestationFlow::CertificateCallback mock_callback = base::Bind(
-      &MockObserver::MockCertificateCallback,
-      base::Unretained(&observer));
+      &MockObserver::MockCertificateCallback, base::Unretained(&observer));
 
   std::unique_ptr<ServerProxy> proxy_interface(proxy.release());
   AttestationFlow flow(&async_caller, &client, std::move(proxy_interface));
@@ -465,8 +473,7 @@
               MockCertificateCallback(ATTESTATION_UNSPECIFIED_FAILURE, ""))
       .Times(1);
   AttestationFlow::CertificateCallback mock_callback = base::Bind(
-      &MockObserver::MockCertificateCallback,
-      base::Unretained(&observer));
+      &MockObserver::MockCertificateCallback, base::Unretained(&observer));
 
   std::unique_ptr<ServerProxy> proxy_interface(proxy.release());
   AttestationFlow flow(&async_caller, &client, std::move(proxy_interface));
@@ -488,9 +495,11 @@
   std::unique_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>());
   proxy->DeferToFake(false);
   EXPECT_CALL(*proxy, GetType()).WillRepeatedly(DoDefault());
-  EXPECT_CALL(*proxy, SendCertificateRequest(
-      cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest,
-      _)).Times(1);
+  EXPECT_CALL(
+      *proxy,
+      SendCertificateRequest(
+          cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest, _))
+      .Times(1);
 
   StrictMock<MockObserver> observer;
   EXPECT_CALL(observer,
@@ -536,8 +545,7 @@
                             ATTESTATION_SERVER_BAD_REQUEST_FAILURE, ""))
       .Times(1);
   AttestationFlow::CertificateCallback mock_callback = base::Bind(
-      &MockObserver::MockCertificateCallback,
-      base::Unretained(&observer));
+      &MockObserver::MockCertificateCallback, base::Unretained(&observer));
 
   std::unique_ptr<ServerProxy> proxy_interface(proxy.release());
   AttestationFlow flow(&async_caller, &client, std::move(proxy_interface));
@@ -562,8 +570,7 @@
               MockCertificateCallback(ATTESTATION_UNSPECIFIED_FAILURE, ""))
       .Times(1);
   AttestationFlow::CertificateCallback mock_callback = base::Bind(
-      &MockObserver::MockCertificateCallback,
-      base::Unretained(&observer));
+      &MockObserver::MockCertificateCallback, base::Unretained(&observer));
 
   std::unique_ptr<ServerProxy> proxy_interface(proxy.release());
   AttestationFlow flow(&async_caller, &client, std::move(proxy_interface));
@@ -593,9 +600,11 @@
   std::unique_ptr<MockServerProxy> proxy(new StrictMock<MockServerProxy>());
   proxy->DeferToFake(true);
   EXPECT_CALL(*proxy, GetType()).WillRepeatedly(DoDefault());
-  EXPECT_CALL(*proxy, SendCertificateRequest(
-      cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest,
-      _)).Times(1);
+  EXPECT_CALL(
+      *proxy,
+      SendCertificateRequest(
+          cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest, _))
+      .Times(1);
 
   StrictMock<MockObserver> observer;
   EXPECT_CALL(observer,
@@ -604,8 +613,7 @@
                   cryptohome::MockAsyncMethodCaller::kFakeAttestationCert))
       .Times(1);
   AttestationFlow::CertificateCallback mock_callback = base::Bind(
-      &MockObserver::MockCertificateCallback,
-      base::Unretained(&observer));
+      &MockObserver::MockCertificateCallback, base::Unretained(&observer));
 
   std::unique_ptr<ServerProxy> proxy_interface(proxy.release());
   AttestationFlow flow(&async_caller, &client, std::move(proxy_interface));
@@ -631,8 +639,7 @@
               MockCertificateCallback(ATTESTATION_SUCCESS, "fake_cert"))
       .Times(1);
   AttestationFlow::CertificateCallback mock_callback = base::Bind(
-      &MockObserver::MockCertificateCallback,
-      base::Unretained(&observer));
+      &MockObserver::MockCertificateCallback, base::Unretained(&observer));
 
   std::unique_ptr<ServerProxy> proxy_interface(proxy.release());
   AttestationFlow flow(&async_caller, &client, std::move(proxy_interface));
diff --git a/chromeos/audio/BUILD.gn b/chromeos/audio/BUILD.gn
new file mode 100644
index 0000000..9a715c2
--- /dev/null
+++ b/chromeos/audio/BUILD.gn
@@ -0,0 +1,48 @@
+# Copyright 2019 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("//testing/test.gni")
+
+assert(is_chromeos, "Non-Chrome-OS builds must not depend on //chromeos")
+
+component("audio") {
+  defines = [ "IS_CHROMEOS_AUDIO_IMPL" ]
+  deps = [
+    "//base",
+    "//chromeos:chromeos_constants",
+    "//chromeos/dbus",
+    "//components/prefs",
+    "//media/base:video_facing",
+  ]
+  sources = [
+    "audio_device.cc",
+    "audio_device.h",
+    "audio_devices_pref_handler.h",
+    "audio_devices_pref_handler_impl.cc",
+    "audio_devices_pref_handler_impl.h",
+    "audio_devices_pref_handler_stub.cc",
+    "audio_devices_pref_handler_stub.h",
+    "audio_pref_observer.h",
+    "chromeos_sounds.h",
+    "cras_audio_handler.cc",
+    "cras_audio_handler.h",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  deps = [
+    ":audio",
+    "//base/test:test_support",
+    "//chromeos:chromeos_constants",
+    "//chromeos/dbus",
+    "//components/prefs:test_support",
+    "//media/base:video_facing",
+    "//testing/gtest",
+  ]
+  sources = [
+    "audio_devices_pref_handler_impl_unittest.cc",
+    "cras_audio_handler_unittest.cc",
+  ]
+}
diff --git a/chromeos/audio/DEPS b/chromeos/audio/DEPS
new file mode 100644
index 0000000..418afb0
--- /dev/null
+++ b/chromeos/audio/DEPS
@@ -0,0 +1,10 @@
+noparent = True
+
+include_rules = [
+  "+base",
+  "+chromeos/constants",
+  "+chromeos/dbus",
+  "+components/prefs",
+  "+media",
+  "+testing",
+]
diff --git a/chromeos/audio/audio_device.h b/chromeos/audio/audio_device.h
index 90fabcf..c26e2de 100644
--- a/chromeos/audio/audio_device.h
+++ b/chromeos/audio/audio_device.h
@@ -11,7 +11,7 @@
 #include <string>
 #include <vector>
 
-#include "chromeos/chromeos_export.h"
+#include "base/component_export.h"
 #include "chromeos/dbus/audio_node.h"
 
 namespace chromeos {
@@ -35,7 +35,7 @@
   AUDIO_TYPE_OTHER,
 };
 
-struct CHROMEOS_EXPORT AudioDevice {
+struct COMPONENT_EXPORT(CHROMEOS_AUDIO) AudioDevice {
   AudioDevice();
   explicit AudioDevice(const AudioNode& node);
   AudioDevice(const AudioDevice& other);
diff --git a/chromeos/audio/audio_devices_pref_handler.h b/chromeos/audio/audio_devices_pref_handler.h
index 09bb787..8c4c3c5a 100644
--- a/chromeos/audio/audio_devices_pref_handler.h
+++ b/chromeos/audio/audio_devices_pref_handler.h
@@ -5,9 +5,9 @@
 #ifndef CHROMEOS_AUDIO_AUDIO_DEVICES_PREF_HANDLER_H_
 #define CHROMEOS_AUDIO_AUDIO_DEVICES_PREF_HANDLER_H_
 
+#include "base/component_export.h"
 #include "base/memory/ref_counted.h"
 #include "chromeos/audio/audio_pref_observer.h"
-#include "chromeos/chromeos_export.h"
 
 namespace chromeos {
 
@@ -16,7 +16,7 @@
 // Interface that handles audio preference related work, reads and writes
 // audio preferences, and notifies AudioPrefObserver for audio preference
 // changes.
-class CHROMEOS_EXPORT AudioDevicesPrefHandler
+class COMPONENT_EXPORT(CHROMEOS_AUDIO) AudioDevicesPrefHandler
     : public base::RefCountedThreadSafe<AudioDevicesPrefHandler> {
  public:
   // Integer because C++ does not allow static const double in header files.
diff --git a/chromeos/audio/audio_devices_pref_handler_impl.h b/chromeos/audio/audio_devices_pref_handler_impl.h
index 5922eba7..f476c8e1 100644
--- a/chromeos/audio/audio_devices_pref_handler_impl.h
+++ b/chromeos/audio/audio_devices_pref_handler_impl.h
@@ -8,11 +8,11 @@
 #include <memory>
 #include <string>
 
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
 #include "base/values.h"
 #include "chromeos/audio/audio_devices_pref_handler.h"
-#include "chromeos/chromeos_export.h"
 #include "components/prefs/pref_change_registrar.h"
 
 class PrefRegistrySimple;
@@ -22,7 +22,7 @@
 
 // Class which implements AudioDevicesPrefHandler interface and register audio
 // preferences as well.
-class CHROMEOS_EXPORT AudioDevicesPrefHandlerImpl
+class COMPONENT_EXPORT(CHROMEOS_AUDIO) AudioDevicesPrefHandlerImpl
     : public AudioDevicesPrefHandler {
  public:
   // |local_state| is the device-wide preference service.
diff --git a/chromeos/audio/audio_devices_pref_handler_stub.h b/chromeos/audio/audio_devices_pref_handler_stub.h
index dd5dd52..efb7934 100644
--- a/chromeos/audio/audio_devices_pref_handler_stub.h
+++ b/chromeos/audio/audio_devices_pref_handler_stub.h
@@ -9,13 +9,14 @@
 
 #include <map>
 
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "chromeos/audio/audio_devices_pref_handler.h"
 
 namespace chromeos {
 
 // Stub class for AudioDevicesPrefHandler, used for testing.
-class CHROMEOS_EXPORT AudioDevicesPrefHandlerStub
+class COMPONENT_EXPORT(CHROMEOS_AUDIO) AudioDevicesPrefHandlerStub
     : public AudioDevicesPrefHandler {
  public:
   struct DeviceState {
diff --git a/chromeos/audio/audio_pref_observer.h b/chromeos/audio/audio_pref_observer.h
index f701fcdd..9a025610 100644
--- a/chromeos/audio/audio_pref_observer.h
+++ b/chromeos/audio/audio_pref_observer.h
@@ -5,13 +5,13 @@
 #ifndef CHROMEOS_AUDIO_AUDIO_PREF_OBSERVER_H_
 #define CHROMEOS_AUDIO_AUDIO_PREF_OBSERVER_H_
 
+#include "base/component_export.h"
 #include "base/memory/ref_counted.h"
-#include "chromeos/chromeos_export.h"
 
 namespace chromeos {
 
 // Interface for observing audio preference changes.
-class CHROMEOS_EXPORT AudioPrefObserver {
+class COMPONENT_EXPORT(CHROMEOS_AUDIO) AudioPrefObserver {
  public:
   // Called when audio policy prefs changed.
   virtual void OnAudioPolicyPrefChanged() = 0;
diff --git a/chromeos/audio/cras_audio_handler.h b/chromeos/audio/cras_audio_handler.h
index e4959018..ea73c76 100644
--- a/chromeos/audio/cras_audio_handler.h
+++ b/chromeos/audio/cras_audio_handler.h
@@ -11,6 +11,7 @@
 #include <queue>
 #include <vector>
 
+#include "base/component_export.h"
 #include "base/containers/circular_deque.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -36,9 +37,10 @@
 
 // This class is not thread safe. The public functions should be called on
 // browser main thread.
-class CHROMEOS_EXPORT CrasAudioHandler : public CrasAudioClient::Observer,
-                                         public AudioPrefObserver,
-                                         public media::VideoCaptureObserver {
+class COMPONENT_EXPORT(CHROMEOS_AUDIO) CrasAudioHandler
+    : public CrasAudioClient::Observer,
+      public AudioPrefObserver,
+      public media::VideoCaptureObserver {
  public:
   typedef std::
       priority_queue<AudioDevice, std::vector<AudioDevice>, AudioDeviceCompare>
diff --git a/chromeos/components/drivefs/BUILD.gn b/chromeos/components/drivefs/BUILD.gn
index b335612..e269090 100644
--- a/chromeos/components/drivefs/BUILD.gn
+++ b/chromeos/components/drivefs/BUILD.gn
@@ -20,6 +20,7 @@
     "//base",
     "//chromeos",
     "//chromeos/components/drivefs/mojom",
+    "//chromeos/disks",
     "//components/account_id",
     "//components/drive",
     "//dbus",
@@ -63,6 +64,7 @@
     "//base/test:test_support",
     "//chromeos:test_support",
     "//chromeos/components/drivefs/mojom",
+    "//chromeos/disks:test_support",
     "//components/drive",
     "//components/invalidation/impl:test_support",
     "//mojo/public/cpp/bindings",
diff --git a/chromeos/cryptohome/BUILD.gn b/chromeos/cryptohome/BUILD.gn
index 4131ffb9..22a33b5 100644
--- a/chromeos/cryptohome/BUILD.gn
+++ b/chromeos/cryptohome/BUILD.gn
@@ -34,14 +34,34 @@
   ]
 }
 
+source_set("test_support") {
+  testonly = true
+  public_deps = [
+    ":cryptohome",
+    "//chromeos/dbus:cryptohome_proto",
+  ]
+  deps = [
+    "//base",
+    "//base/test:test_support",
+    "//components/account_id",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+  sources = [
+    "mock_async_method_caller.cc",
+    "mock_async_method_caller.h",
+    "mock_homedir_methods.cc",
+    "mock_homedir_methods.h",
+  ]
+}
+
 source_set("unit_tests") {
   testonly = true
   deps = [
-    ":cryptohome",
+    ":test_support",
     "//base",
     "//base/test:test_support",
     "//chromeos/dbus",
-    "//chromeos/dbus:cryptohome_proto",
     "//chromeos/login/auth:challenge_response_key",
     "//testing/gtest:gtest",
   ]
diff --git a/chromeos/disks/BUILD.gn b/chromeos/disks/BUILD.gn
new file mode 100644
index 0000000..28757a2f
--- /dev/null
+++ b/chromeos/disks/BUILD.gn
@@ -0,0 +1,63 @@
+# Copyright 2019 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("//testing/test.gni")
+
+assert(is_chromeos, "Non-Chrome-OS builds must not depend on //chromeos")
+
+component("disks") {
+  defines = [ "IS_CHROMEOS_DISKS_IMPL" ]
+  deps = [
+    "//base",
+    "//chromeos:chromeos_constants",
+    "//chromeos/dbus",
+    "//chromeos/dbus:power_manager_proto",
+  ]
+  sources = [
+    "disk.cc",
+    "disk.h",
+    "disk_mount_manager.cc",
+    "disk_mount_manager.h",
+    "suspend_unmount_manager.cc",
+    "suspend_unmount_manager.h",
+  ]
+}
+
+source_set("test_support") {
+  testonly = true
+  public_deps = [
+    ":disks",
+  ]
+  deps = [
+    "//base",
+    "//base/test:test_support",
+    "//chromeos/dbus",
+    "//chromeos/dbus:power_manager_proto",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+  sources = [
+    "mock_disk_mount_manager.cc",
+    "mock_disk_mount_manager.h",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  deps = [
+    ":disks",
+    ":test_support",
+    "//base/test:test_support",
+    "//chromeos:chromeos_constants",
+    "//chromeos/dbus",
+    "//chromeos/dbus:power_manager_proto",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+  sources = [
+    "disk_mount_manager_unittest.cc",
+    "disk_unittest.cc",
+    "suspend_unmount_manager_unittest.cc",
+  ]
+}
diff --git a/chromeos/disks/DEPS b/chromeos/disks/DEPS
index aed2994..aa18272 100644
--- a/chromeos/disks/DEPS
+++ b/chromeos/disks/DEPS
@@ -1,5 +1,10 @@
-specific_include_rules = {
-  "disk_unittest.cc": [
-    "+dbus",
-  ],
-}
+noparent = True
+
+include_rules = [
+  "+base",
+  "+chromeos/constants",
+  "+chromeos/dbus",
+  "+dbus",
+  "+testing",
+  "+third_party/cros_system_api",
+]
diff --git a/chromeos/disks/disk.h b/chromeos/disks/disk.h
index 4e6d6517..a9f9d30 100644
--- a/chromeos/disks/disk.h
+++ b/chromeos/disks/disk.h
@@ -8,14 +8,14 @@
 #include <memory>
 #include <string>
 
+#include "base/component_export.h"
 #include "base/macros.h"
-#include "chromeos/chromeos_export.h"
 #include "chromeos/dbus/cros_disks_client.h"
 
 namespace chromeos {
 namespace disks {
 
-class CHROMEOS_EXPORT Disk {
+class COMPONENT_EXPORT(CHROMEOS_DISKS) Disk {
  public:
   class Builder;
 
@@ -166,7 +166,7 @@
   std::string base_mount_path_;
 };
 
-class CHROMEOS_EXPORT Disk::Builder {
+class COMPONENT_EXPORT(CHROMEOS_DISKS) Disk::Builder {
  public:
   Builder();
   ~Builder();
diff --git a/chromeos/disks/disk_mount_manager.h b/chromeos/disks/disk_mount_manager.h
index bdee20af..e05aff47 100644
--- a/chromeos/disks/disk_mount_manager.h
+++ b/chromeos/disks/disk_mount_manager.h
@@ -11,8 +11,8 @@
 #include <memory>
 
 #include "base/callback_forward.h"
+#include "base/component_export.h"
 #include "base/files/file_path.h"
-#include "chromeos/chromeos_export.h"
 #include "chromeos/dbus/cros_disks_client.h"
 
 namespace chromeos {
@@ -29,7 +29,7 @@
 
 // This class handles the interaction with cros-disks.
 // Other classes can add themselves as observers.
-class CHROMEOS_EXPORT DiskMountManager {
+class COMPONENT_EXPORT(CHROMEOS_DISKS) DiskMountManager {
  public:
   // Event types passed to the observers.
   enum DiskEvent {
diff --git a/chromeos/disks/suspend_unmount_manager.h b/chromeos/disks/suspend_unmount_manager.h
index bbcd637..a1ca7757 100644
--- a/chromeos/disks/suspend_unmount_manager.h
+++ b/chromeos/disks/suspend_unmount_manager.h
@@ -8,8 +8,8 @@
 #include <set>
 #include <string>
 
+#include "base/component_export.h"
 #include "base/macros.h"
-#include "chromeos/chromeos_export.h"
 #include "chromeos/dbus/cros_disks_client.h"
 #include "chromeos/dbus/power_manager_client.h"
 
@@ -19,7 +19,7 @@
 class DiskMountManager;
 
 // Class to unmount disks at suspend.
-class CHROMEOS_EXPORT SuspendUnmountManager
+class COMPONENT_EXPORT(CHROMEOS_DISKS) SuspendUnmountManager
     : public PowerManagerClient::Observer {
  public:
   // The ownership of these raw pointers still remains with the caller.
diff --git a/chromeos/network/proxy/ui_proxy_config.cc b/chromeos/network/proxy/ui_proxy_config.cc
index 5621387..d13fe1ef 100644
--- a/chromeos/network/proxy/ui_proxy_config.cc
+++ b/chromeos/network/proxy/ui_proxy_config.cc
@@ -5,54 +5,17 @@
 #include "chromeos/network/proxy/ui_proxy_config.h"
 
 #include "base/logging.h"
-#include "base/values.h"
 #include "components/proxy_config/proxy_config_dictionary.h"
 #include "net/proxy_resolution/proxy_config.h"
 #include "url/url_constants.h"
 
-namespace {
-const char kSocksScheme[] = "socks";
-}
-
 namespace chromeos {
 
 UIProxyConfig::UIProxyConfig()
-    : mode(MODE_DIRECT),
-      state(ProxyPrefs::CONFIG_UNSET),
-      user_modifiable(true) {}
+    : mode(MODE_DIRECT), state(ProxyPrefs::CONFIG_UNSET) {}
 
 UIProxyConfig::~UIProxyConfig() = default;
 
-void UIProxyConfig::SetPacUrl(const GURL& pac_url) {
-  mode = UIProxyConfig::MODE_PAC_SCRIPT;
-  automatic_proxy.pac_url = pac_url;
-}
-
-void UIProxyConfig::SetSingleProxy(const net::ProxyServer& server) {
-  mode = UIProxyConfig::MODE_SINGLE_PROXY;
-  single_proxy.server = server;
-}
-
-void UIProxyConfig::SetProxyForScheme(const std::string& scheme,
-                                      const net::ProxyServer& server) {
-  ManualProxy* proxy = MapSchemeToProxy(scheme);
-  if (!proxy) {
-    NOTREACHED() << "Cannot set proxy: invalid scheme [" << scheme << "]";
-    return;
-  }
-  mode = UIProxyConfig::MODE_PROXY_PER_SCHEME;
-  proxy->server = server;
-}
-
-void UIProxyConfig::SetBypassRules(const net::ProxyBypassRules& rules) {
-  if (mode != UIProxyConfig::MODE_SINGLE_PROXY &&
-      mode != UIProxyConfig::MODE_PROXY_PER_SCHEME) {
-    NOTREACHED() << "Cannot set bypass rules for proxy mode [" << mode << "]";
-    return;
-  }
-  bypass_rules = rules;
-}
-
 bool UIProxyConfig::FromNetProxyConfig(const net::ProxyConfig& net_config) {
   *this = UIProxyConfig();  // Reset to default.
   const net::ProxyConfig::ProxyRules& rules = net_config.proxy_rules();
@@ -74,7 +37,6 @@
         return false;
       mode = MODE_SINGLE_PROXY;
       single_proxy.server = rules.single_proxies.Get();
-      bypass_rules = rules.bypass_rules;
       return true;
     case net::ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME:
       // Make sure we have valid server for at least one of the protocols.
@@ -92,7 +54,6 @@
         ftp_proxy.server = rules.proxies_for_ftp.Get();
       if (!rules.fallback_proxies.IsEmpty())
         socks_proxy.server = rules.fallback_proxies.Get();
-      bypass_rules = rules.bypass_rules;
       return true;
     default:
       NOTREACHED() << "Unrecognized proxy config mode";
@@ -101,57 +62,4 @@
   return false;
 }
 
-base::Value UIProxyConfig::ToPrefProxyConfig() const {
-  switch (mode) {
-    case MODE_DIRECT: {
-      return ProxyConfigDictionary::CreateDirect();
-    }
-    case MODE_AUTO_DETECT: {
-      return ProxyConfigDictionary::CreateAutoDetect();
-    }
-    case MODE_PAC_SCRIPT: {
-      return ProxyConfigDictionary::CreatePacScript(
-          automatic_proxy.pac_url.spec(), false);
-    }
-    case MODE_SINGLE_PROXY: {
-      std::string spec;
-      if (single_proxy.server.is_valid())
-        spec = single_proxy.server.ToURI();
-      return ProxyConfigDictionary::CreateFixedServers(spec,
-                                                       bypass_rules.ToString());
-    }
-    case MODE_PROXY_PER_SCHEME: {
-      std::string spec;
-      ProxyConfigDictionary::EncodeAndAppendProxyServer(
-          url::kHttpScheme, http_proxy.server, &spec);
-      ProxyConfigDictionary::EncodeAndAppendProxyServer(
-          url::kHttpsScheme, https_proxy.server, &spec);
-      ProxyConfigDictionary::EncodeAndAppendProxyServer(
-          url::kFtpScheme, ftp_proxy.server, &spec);
-      ProxyConfigDictionary::EncodeAndAppendProxyServer(
-          kSocksScheme, socks_proxy.server, &spec);
-      return ProxyConfigDictionary::CreateFixedServers(spec,
-                                                       bypass_rules.ToString());
-    }
-    default:
-      break;
-  }
-  NOTREACHED() << "Unrecognized proxy config mode for preference";
-  return base::Value();
-}
-
-UIProxyConfig::ManualProxy* UIProxyConfig::MapSchemeToProxy(
-    const std::string& scheme) {
-  if (scheme == url::kHttpScheme)
-    return &http_proxy;
-  if (scheme == url::kHttpsScheme)
-    return &https_proxy;
-  if (scheme == url::kFtpScheme)
-    return &ftp_proxy;
-  if (scheme == kSocksScheme)
-    return &socks_proxy;
-  NOTREACHED() << "Invalid scheme: " << scheme;
-  return NULL;
-}
-
 }  // namespace chromeos
diff --git a/chromeos/network/proxy/ui_proxy_config.h b/chromeos/network/proxy/ui_proxy_config.h
index a4dcc9b..46b661c 100644
--- a/chromeos/network/proxy/ui_proxy_config.h
+++ b/chromeos/network/proxy/ui_proxy_config.h
@@ -14,10 +14,6 @@
 #include "net/proxy_resolution/proxy_bypass_rules.h"
 #include "url/gurl.h"
 
-namespace base {
-class Value;
-}
-
 namespace net {
 class ProxyConfig;
 }
@@ -60,37 +56,13 @@
   UIProxyConfig();
   ~UIProxyConfig();
 
-  void SetPacUrl(const GURL& pac_url);
-  void SetSingleProxy(const net::ProxyServer& server);
-
-  // |scheme| is one of "http", "https", "ftp" or "socks".
-  void SetProxyForScheme(const std::string& scheme,
-                         const net::ProxyServer& server);
-
-  // Only valid for MODE_SINGLE_PROXY or MODE_PROXY_PER_SCHEME.
-  void SetBypassRules(const net::ProxyBypassRules& rules);
-
   // Converts net::ProxyConfig to |this|.
   bool FromNetProxyConfig(const net::ProxyConfig& net_config);
 
-  // Converts |this| to a dictionary Value of ProxyConfigDictionary format
-  // (which is the same format used by prefs).
-  base::Value ToPrefProxyConfig() const;
-
-  // Map |scheme| (one of "http", "https", "ftp" or "socks") to the correct
-  // ManualProxy.  Returns NULL if scheme is invalid.
-  ManualProxy* MapSchemeToProxy(const std::string& scheme);
-
   Mode mode;
 
   ProxyPrefs::ConfigState state;
 
-  // True if user can modify proxy settings via UI.
-  // If proxy is managed by policy or extension or other_precde or is for
-  // shared network but kUseSharedProxies is turned off, it can't be modified
-  // by user.
-  bool user_modifiable;
-
   // Set if mode is MODE_DIRECT or MODE_AUTO_DETECT or MODE_PAC_SCRIPT.
   AutomaticProxy automatic_proxy;
   // Set if mode is MODE_SINGLE_PROXY.
@@ -103,9 +75,6 @@
   ManualProxy ftp_proxy;
   // Set if mode is MODE_PROXY_PER_SCHEME and has socks proxy.
   ManualProxy socks_proxy;
-
-  // Exceptions for when not to use a proxy.
-  net::ProxyBypassRules bypass_rules;
 };
 
 }  // namespace chromeos
diff --git a/chromeos/network/proxy/ui_proxy_config_service.cc b/chromeos/network/proxy/ui_proxy_config_service.cc
index abe1604..f68f38f 100644
--- a/chromeos/network/proxy/ui_proxy_config_service.cc
+++ b/chromeos/network/proxy/ui_proxy_config_service.cc
@@ -115,8 +115,7 @@
   DetermineEffectiveConfig(*network);
   VLOG(1) << "Current ui network: " << network->name() << ", "
           << ModeToString(current_ui_config_.mode) << ", "
-          << ProxyPrefs::ConfigStateToDebugString(current_ui_config_.state)
-          << ", modifiable:" << current_ui_config_.user_modifiable;
+          << ProxyPrefs::ConfigStateToDebugString(current_ui_config_.state);
 }
 
 void UIProxyConfigService::GetProxyConfig(const std::string& network_guid,
@@ -126,33 +125,6 @@
   *config = current_ui_config_;
 }
 
-void UIProxyConfigService::SetProxyConfig(const std::string& network_guid,
-                                          const UIProxyConfig& config) {
-  current_ui_network_guid_ = network_guid;
-  current_ui_config_ = config;
-  if (current_ui_network_guid_.empty())
-    return;
-
-  const NetworkState* network =
-      NetworkHandler::Get()->network_state_handler()->GetNetworkStateFromGuid(
-          current_ui_network_guid_);
-  if (!network || !network->IsInProfile()) {
-    NET_LOG(ERROR) << "No configured NetworkState for guid: "
-                   << current_ui_network_guid_;
-    return;
-  }
-
-  // Store config for this network.
-  base::Value proxy_config_value(config.ToPrefProxyConfig());
-
-  VLOG(1) << "Set proxy for " << current_ui_network_guid_ << " to "
-          << proxy_config_value;
-
-  ProxyConfigDictionary proxy_config_dict(std::move(proxy_config_value));
-  proxy_config::SetProxyConfigForNetwork(proxy_config_dict, *network);
-  current_ui_config_.state = ProxyPrefs::CONFIG_SYSTEM;
-}
-
 bool UIProxyConfigService::HasDefaultNetworkProxyConfigured() {
   const NetworkState* network =
       NetworkHandler::Get()->network_state_handler()->DefaultNetwork();
@@ -203,14 +175,9 @@
   // Store effective proxy into |current_ui_config_|.
   current_ui_config_.FromNetProxyConfig(effective_config.value());
   current_ui_config_.state = effective_config_state;
-  if (ProxyConfigServiceImpl::PrefPrecedes(effective_config_state)) {
-    current_ui_config_.user_modifiable = false;
-  } else if (!IsNetworkProxySettingsEditable(onc_source)) {
+  if (!ProxyConfigServiceImpl::PrefPrecedes(effective_config_state) &&
+      !IsNetworkProxySettingsEditable(onc_source)) {
     current_ui_config_.state = ProxyPrefs::CONFIG_POLICY;
-    current_ui_config_.user_modifiable = false;
-  } else {
-    current_ui_config_.user_modifiable = !ProxyConfigServiceImpl::IgnoreProxy(
-        profile_prefs_, network.profile_path(), onc_source);
   }
 }
 
diff --git a/chromeos/network/proxy/ui_proxy_config_service.h b/chromeos/network/proxy/ui_proxy_config_service.h
index 2db29ff..b21fb28 100644
--- a/chromeos/network/proxy/ui_proxy_config_service.h
+++ b/chromeos/network/proxy/ui_proxy_config_service.h
@@ -45,11 +45,6 @@
   // * A user specified proxy associated with |network_guid|.
   void GetProxyConfig(const std::string& network_guid, UIProxyConfig* config);
 
-  // Called from the UI to update the user proxy configuration for
-  // |network_guid|. The proxy specified by |config| is stored by Shill.
-  void SetProxyConfig(const std::string& network_guid,
-                      const UIProxyConfig& config);
-
   // Returns true if there is a default network and it has a proxy configuration
   // with mode == MODE_FIXED_SERVERS.
   bool HasDefaultNetworkProxyConfigured();
diff --git a/components/arc/BUILD.gn b/components/arc/BUILD.gn
index 04ad3aa..2c2da12a 100644
--- a/components/arc/BUILD.gn
+++ b/components/arc/BUILD.gn
@@ -80,9 +80,11 @@
     "//ash/public/cpp",
     "//base",
     "//chromeos",
+    "//chromeos/audio",
     "//chromeos/cryptohome",
     "//chromeos/dbus:login_manager_proto",
     "//chromeos/dbus:power_manager_proto",
+    "//chromeos/disks",
     "//chromeos/login/login_state",
     "//components/account_id",
     "//components/exo",
@@ -327,6 +329,7 @@
     "//chromeos:test_support_without_gmock",
     "//chromeos/cryptohome",
     "//chromeos/dbus:power_manager_proto",
+    "//chromeos/disks:test_support",
     "//components/account_id",
     "//components/keyed_service/content",
     "//components/prefs:test_support",
diff --git a/components/autofill/core/browser/autofill_profile.cc b/components/autofill/core/browser/autofill_profile.cc
index 3fd9100..c21d60e 100644
--- a/components/autofill/core/browser/autofill_profile.cc
+++ b/components/autofill/core/browser/autofill_profile.cc
@@ -457,6 +457,16 @@
          EqualsSansGuid(profile);
 }
 
+bool AutofillProfile::EqualsForClientValidationPurpose(
+    const AutofillProfile& profile) const {
+  for (ServerFieldType type : kSupportedTypesByClientForValidation) {
+    if (GetRawInfo(type).compare(profile.GetRawInfo(type))) {
+      return false;
+    }
+  }
+  return true;
+}
+
 bool AutofillProfile::EqualsIncludingUsageStatsForTesting(
     const AutofillProfile& profile) const {
   return use_count() == profile.use_count() &&
diff --git a/components/autofill/core/browser/autofill_profile.h b/components/autofill/core/browser/autofill_profile.h
index 16d5eb3..1a4b56c 100644
--- a/components/autofill/core/browser/autofill_profile.h
+++ b/components/autofill/core/browser/autofill_profile.h
@@ -126,6 +126,9 @@
   // differences in usage stats.
   bool EqualsForSyncPurposes(const AutofillProfile& profile) const;
 
+  // Compares the values of kSupportedTypesByClientForValidation fields.
+  bool EqualsForClientValidationPurpose(const AutofillProfile& profile) const;
+
   // Same as operator==, but cares about differences in usage stats.
   bool EqualsIncludingUsageStatsForTesting(
       const AutofillProfile& profile) const;
diff --git a/components/autofill/core/browser/autofill_profile_unittest.cc b/components/autofill/core/browser/autofill_profile_unittest.cc
index b70b6f2..2a04523 100644
--- a/components/autofill/core/browser/autofill_profile_unittest.cc
+++ b/components/autofill/core/browser/autofill_profile_unittest.cc
@@ -1816,4 +1816,23 @@
   EXPECT_FALSE(profile.IsDeletable());
 }
 
+// Tests that the two profiles can be compared for validation purposes.
+TEST(AutofillProfileTest, EqualsForClientValidationPurpose) {
+  AutofillProfile profile = test::GetFullProfile();
+
+  AutofillProfile profile2(profile);
+  profile2.SetRawInfo(EMAIL_ADDRESS, base::ASCIIToUTF16("different@email.com"));
+
+  AutofillProfile profile3(profile);
+  profile3.SetRawInfo(NAME_FULL, base::ASCIIToUTF16("Alice Munro"));
+
+  // For client validation purposes,
+  // profile2 != profile, because they differ in the email, which is validated
+  // by the client.
+  // profile3 == profile, because they only differ in name, and name is not
+  // validated by the client.
+  EXPECT_FALSE(profile.EqualsForClientValidationPurpose(profile2));
+  EXPECT_TRUE(profile.EqualsForClientValidationPurpose(profile3));
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/browser/personal_data_manager.h b/components/autofill/core/browser/personal_data_manager.h
index 8e0c4dc..b842de04 100644
--- a/components/autofill/core/browser/personal_data_manager.h
+++ b/components/autofill/core/browser/personal_data_manager.h
@@ -127,17 +127,6 @@
   bool IsSyncFeatureEnabled() const override;
 
   // GaiaCookieManagerService::Observer:
-  void OnAddAccountToCookieCompleted(
-      const std::string& account_id,
-      const GoogleServiceAuthError& error) override {}
-  void OnSetAccountsInCookieCompleted(
-      const GoogleServiceAuthError& error) override {}
-  void OnLogOutAccountsFromCookieCompleted(
-      const GoogleServiceAuthError& error) override {}
-  void OnGaiaAccountsInCookieUpdated(
-      const std::vector<gaia::ListedAccount>& accounts,
-      const std::vector<gaia::ListedAccount>& signed_out_accounts,
-      const GoogleServiceAuthError& error) override {}
   void OnGaiaCookieDeletedByUserAction() override;
 
   // Returns the current sync status.
diff --git a/components/autofill/core/browser/webdata/autofill_sync_bridge_util.cc b/components/autofill/core/browser/webdata/autofill_sync_bridge_util.cc
index 3490ccb2..dc1ed281 100644
--- a/components/autofill/core/browser/webdata/autofill_sync_bridge_util.cc
+++ b/components/autofill/core/browser/webdata/autofill_sync_bridge_util.cc
@@ -175,16 +175,17 @@
   return PaymentsCustomerData{/*customer_id=*/customer_data.id()};
 }
 
-}  // namespace
-
-std::string GetBase64EncodedServerId(const std::string& server_id) {
+// Returns the specified |id| encoded in base 64.
+std::string GetBase64EncodedId(const std::string& id) {
   std::string encoded_id;
-  base::Base64Encode(server_id, &encoded_id);
+  base::Base64Encode(id, &encoded_id);
   return encoded_id;
 }
 
+}  // namespace
+
 std::string GetSpecificsIdForMetadataId(const std::string& metadata_id) {
-  return GetBase64EncodedServerId(metadata_id);
+  return GetBase64EncodedId(metadata_id);
 }
 
 std::string GetStorageKeyForWalletMetadataSpecificsId(
@@ -201,13 +202,19 @@
 
 void SetAutofillWalletSpecificsFromServerProfile(
     const AutofillProfile& address,
-    AutofillWalletSpecifics* wallet_specifics) {
+    AutofillWalletSpecifics* wallet_specifics,
+    bool enforce_utf8) {
   wallet_specifics->set_type(AutofillWalletSpecifics::POSTAL_ADDRESS);
 
   sync_pb::WalletPostalAddress* wallet_address =
       wallet_specifics->mutable_address();
 
-  wallet_address->set_id(address.server_id());
+  if (enforce_utf8) {
+    wallet_address->set_id(GetBase64EncodedId(address.server_id()));
+  } else {
+    wallet_address->set_id(address.server_id());
+  }
+
   wallet_address->set_language_code(TruncateUTF8(address.language_code()));
 
   if (address.HasRawInfo(NAME_FULL)) {
@@ -254,12 +261,28 @@
 
 void SetAutofillWalletSpecificsFromServerCard(
     const CreditCard& card,
-    AutofillWalletSpecifics* wallet_specifics) {
+    AutofillWalletSpecifics* wallet_specifics,
+    bool enforce_utf8) {
   wallet_specifics->set_type(AutofillWalletSpecifics::MASKED_CREDIT_CARD);
 
   sync_pb::WalletMaskedCreditCard* wallet_card =
       wallet_specifics->mutable_masked_card();
-  wallet_card->set_id(card.server_id());
+
+  if (enforce_utf8) {
+    wallet_card->set_id(GetBase64EncodedId(card.server_id()));
+    // The billing address id might refer to a local profile guid which doesn't
+    // need to be encoded.
+    if (base::IsStringUTF8(card.billing_address_id())) {
+      wallet_card->set_billing_address_id(card.billing_address_id());
+    } else {
+      wallet_card->set_billing_address_id(
+          GetBase64EncodedId(card.billing_address_id()));
+    }
+  } else {
+    wallet_card->set_id(card.server_id());
+    wallet_card->set_billing_address_id(card.billing_address_id());
+  }
+
   wallet_card->set_status(LocalToServerStatus(card));
   if (card.HasRawInfo(CREDIT_CARD_NAME_FULL)) {
     wallet_card->set_name_on_card(TruncateUTF8(
@@ -269,7 +292,6 @@
   wallet_card->set_last_four(base::UTF16ToUTF8(card.LastFourDigits()));
   wallet_card->set_exp_month(card.expiration_month());
   wallet_card->set_exp_year(card.expiration_year());
-  wallet_card->set_billing_address_id(card.billing_address_id());
   wallet_card->set_card_class(WalletCardClassFromCardType(card.card_type()));
   wallet_card->set_bank_name(card.bank_name());
 }
diff --git a/components/autofill/core/browser/webdata/autofill_sync_bridge_util.h b/components/autofill/core/browser/webdata/autofill_sync_bridge_util.h
index 3e09ff2..ef9a55a 100644
--- a/components/autofill/core/browser/webdata/autofill_sync_bridge_util.h
+++ b/components/autofill/core/browser/webdata/autofill_sync_bridge_util.h
@@ -18,9 +18,6 @@
 class CreditCard;
 struct PaymentsCustomerData;
 
-// Returns the specified |server_id| encoded in base 64.
-std::string GetBase64EncodedServerId(const std::string& server_id);
-
 // Returns the wallet metadata specifics id for the specified |metadata_id|.
 std::string GetSpecificsIdForMetadataId(const std::string& metadata_id);
 
@@ -34,15 +31,18 @@
 std::string GetStorageKeyForMetadataId(const std::string& metadata_id);
 
 // Sets the fields of the |wallet_specifics| based on the the specified
-// |address|.
+// |address|. If |enforce_utf8|, ids are encoded into UTF-8.
 void SetAutofillWalletSpecificsFromServerProfile(
     const AutofillProfile& address,
-    sync_pb::AutofillWalletSpecifics* wallet_specifics);
+    sync_pb::AutofillWalletSpecifics* wallet_specifics,
+    bool enforce_utf8 = false);
 
 // Sets the fields of the |wallet_specifics| based on the the specified |card|.
+// If |enforce_utf8|, ids are encoded into UTF-8.
 void SetAutofillWalletSpecificsFromServerCard(
     const CreditCard& card,
-    sync_pb::AutofillWalletSpecifics* wallet_specifics);
+    sync_pb::AutofillWalletSpecifics* wallet_specifics,
+    bool enforce_utf8 = false);
 
 // Sets the fields of the |wallet_specifics| based on the specified
 // |customer_data|.
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc b/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc
index a7f85ec..e421f5b 100644
--- a/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc
+++ b/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc
@@ -134,7 +134,7 @@
   DCHECK(web_data_backend_);
   scoped_observer_.Add(web_data_backend_);
 
-  LoadDataCacheAndMetadata();
+  LoadMetadata();
 }
 
 AutofillWalletMetadataSyncBridge::~AutofillWalletMetadataSyncBridge() {}
@@ -236,32 +236,14 @@
 
 void AutofillWalletMetadataSyncBridge::SyncUpUpdatedEntity(
     std::unique_ptr<EntityData> entity_after_change) {
-  std::string storage_key = GetStorageKey(*entity_after_change);
-  auto it = cache_.find(storage_key);
-
-  // This *changed* entity should already be in the cache, ignore otherwise.
-  if (it == cache_.end())
-    return;
-
-  const WalletMetadataSpecifics& specifics_before = it->second;
-  const WalletMetadataSpecifics& specifics_after =
-      entity_after_change->specifics.wallet_metadata();
-
-  if (specifics_before.use_count() < specifics_after.use_count() &&
-      specifics_before.use_date() < specifics_after.use_date()) {
-    std::unique_ptr<MetadataChangeList> metadata_change_list =
-        CreateMetadataChangeList();
-    cache_[storage_key] = specifics_after;
-    change_processor()->Put(storage_key, std::move(entity_after_change),
-                            metadata_change_list.get());
-  }
+  NOTIMPLEMENTED();
 }
 
 AutofillTable* AutofillWalletMetadataSyncBridge::GetAutofillTable() {
   return AutofillTable::FromWebDatabase(web_data_backend_->GetDatabase());
 }
 
-void AutofillWalletMetadataSyncBridge::LoadDataCacheAndMetadata() {
+void AutofillWalletMetadataSyncBridge::LoadMetadata() {
   if (!web_data_backend_ || !web_data_backend_->GetDatabase() ||
       !GetAutofillTable()) {
     change_processor()->ReportError(
@@ -269,25 +251,6 @@
     return;
   }
 
-  // Load the data cache.
-  std::vector<std::unique_ptr<AutofillProfile>> profiles;
-  std::vector<std::unique_ptr<CreditCard>> cards;
-  if (!GetAutofillTable()->GetServerProfiles(&profiles) ||
-      !GetAutofillTable()->GetServerCreditCards(&cards)) {
-    change_processor()->ReportError(
-        {FROM_HERE, "Failed reading autofill data from WebDatabase."});
-    return;
-  }
-  for (const std::unique_ptr<AutofillProfile>& entry : profiles) {
-    cache_[GetStorageKeyForMetadataId(entry->GetMetadata().id)] =
-        CreateMetadataEntityDataFromAutofillServerProfile(*entry)
-            ->specifics.wallet_metadata();
-  }
-  for (const std::unique_ptr<CreditCard>& entry : cards) {
-    cache_[GetStorageKeyForMetadataId(entry->GetMetadata().id)] =
-        CreateMetadataEntityDataFromCard(*entry)->specifics.wallet_metadata();
-  }
-
   // Load the metadata and send to the processor.
   auto batch = std::make_unique<syncer::MetadataBatch>();
   if (!GetAutofillTable()->GetAllSyncMetadata(syncer::AUTOFILL_WALLET_METADATA,
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h b/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h
index 59241199..b1461d8 100644
--- a/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h
+++ b/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h
@@ -88,9 +88,9 @@
   // Returns the table associated with the |web_data_backend_|.
   AutofillTable* GetAutofillTable();
 
-  // Synchronously load |cache_| and sync metadata from the autofill table
-  // and pass the latter to the processor so that it can start tracking changes.
-  void LoadDataCacheAndMetadata();
+  // Synchronously load sync metadata from the autofill table and pass it to the
+  // processor so that it can start tracking changes.
+  void LoadMetadata();
 
   // Reads local wallet metadata from the database and passes them into
   // |callback|. If |storage_keys_set| is not set, it returns all data entries.
@@ -106,11 +106,6 @@
   ScopedObserver<AutofillWebDataBackend, AutofillWalletMetadataSyncBridge>
       scoped_observer_;
 
-  // Cache of the data (local data + data that hasn't synced down yet); keyed by
-  // storage keys. Needed for figuring out what to sync up when larger changes
-  // happen in the local database.
-  std::unordered_map<std::string, sync_pb::WalletMetadataSpecifics> cache_;
-
   // Indicates whether we should rely on wallet data being actively synced. If
   // true, the bridge will prune metadata entries without corresponding wallet
   // data entry.
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc b/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc
index b60fbeb..7671c9dc 100644
--- a/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc
+++ b/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc
@@ -401,7 +401,7 @@
 // Verify that lower values of metadata are not sent to the sync server when
 // local metadata is updated.
 TEST_F(AutofillWalletMetadataSyncBridgeTest,
-       DontSendLowerValueToServerOnSingleChange) {
+       DISABLED_DontSendLowerValueToServerOnSingleChange) {
   table()->SetServerProfiles({CreateServerProfileWithUseStats(
       kAddr1ServerId, /*use_count=*/2, /*use_date=*/5)});
   table()->SetServerCreditCards({CreateServerCreditCardWithUseStats(
@@ -424,7 +424,8 @@
 // Verify that one-off addition of metadata is not sent to the sync
 // server. Metadata add and delete trigger multiple changes notification
 // instead.
-TEST_F(AutofillWalletMetadataSyncBridgeTest, DontAddToServerOnSingleChange) {
+TEST_F(AutofillWalletMetadataSyncBridgeTest,
+       DISABLED_DontAddToServerOnSingleChange) {
   table()->SetServerProfiles({CreateServerProfileWithUseStats(
       kAddr1ServerId, /*use_count=*/1, /*use_date=*/2)});
   table()->SetServerCreditCards({CreateServerCreditCardWithUseStats(
@@ -447,7 +448,7 @@
 // Verify that higher values of metadata are sent to the sync server when local
 // metadata is updated.
 TEST_F(AutofillWalletMetadataSyncBridgeTest,
-       SendHigherValuesToServerOnLocalSingleChange) {
+       DISABLED_SendHigherValuesToServerOnLocalSingleChange) {
   table()->SetServerProfiles({CreateServerProfileWithUseStats(
       kAddr1ServerId, /*use_count=*/1, /*use_date=*/2)});
   table()->SetServerCreditCards({CreateServerCreditCardWithUseStats(
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc b/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc
index bc53608..13b9056 100644
--- a/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc
+++ b/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc
@@ -88,7 +88,8 @@
 
 // Creates a EntityData object corresponding to the specified |address|.
 std::unique_ptr<EntityData> CreateEntityDataFromAutofillServerProfile(
-    const AutofillProfile& address) {
+    const AutofillProfile& address,
+    bool enforce_utf8) {
   auto entity_data = std::make_unique<EntityData>();
 
   std::string specifics_id = GetSpecificsIdFromAutofillProfile(address);
@@ -98,13 +99,15 @@
   AutofillWalletSpecifics* wallet_specifics =
       entity_data->specifics.mutable_autofill_wallet();
 
-  SetAutofillWalletSpecificsFromServerProfile(address, wallet_specifics);
+  SetAutofillWalletSpecificsFromServerProfile(address, wallet_specifics,
+                                              enforce_utf8);
 
   return entity_data;
 }
 
 // Creates a EntityData object corresponding to the specified |card|.
-std::unique_ptr<EntityData> CreateEntityDataFromCard(const CreditCard& card) {
+std::unique_ptr<EntityData> CreateEntityDataFromCard(const CreditCard& card,
+                                                     bool enforce_utf8) {
   std::string specifics_id = GetSpecificsIdFromCreditCard(card);
 
   auto entity_data = std::make_unique<EntityData>();
@@ -114,7 +117,8 @@
   AutofillWalletSpecifics* wallet_specifics =
       entity_data->specifics.mutable_autofill_wallet();
 
-  SetAutofillWalletSpecificsFromServerCard(card, wallet_specifics);
+  SetAutofillWalletSpecificsFromServerCard(card, wallet_specifics,
+                                           enforce_utf8);
 
   return entity_data;
 }
@@ -217,57 +221,7 @@
 }
 
 void AutofillWalletSyncBridge::GetAllDataForDebugging(DataCallback callback) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  std::vector<std::unique_ptr<AutofillProfile>> profiles;
-  std::vector<std::unique_ptr<CreditCard>> cards;
-  std::unique_ptr<PaymentsCustomerData> customer_data;
-  if (!GetAutofillTable()->GetServerProfiles(&profiles) ||
-      !GetAutofillTable()->GetServerCreditCards(&cards) ||
-      !GetAutofillTable()->GetPaymentsCustomerData(&customer_data)) {
-    change_processor()->ReportError(
-        {FROM_HERE, "Failed to load entries from table."});
-    return;
-  }
-
-  // Convert all non base 64 strings so that they can be displayed properly.
-  auto batch = std::make_unique<syncer::MutableDataBatch>();
-  for (const std::unique_ptr<AutofillProfile>& entry : profiles) {
-    std::unique_ptr<EntityData> entity_data =
-        CreateEntityDataFromAutofillServerProfile(*entry);
-    sync_pb::WalletPostalAddress* wallet_address =
-        entity_data->specifics.mutable_autofill_wallet()->mutable_address();
-
-    wallet_address->set_id(GetBase64EncodedServerId(wallet_address->id()));
-
-    batch->Put(GetStorageKeyForWalletDataSpecificsId(
-                   GetSpecificsIdFromAutofillProfile(*entry)),
-               std::move(entity_data));
-  }
-  for (const std::unique_ptr<CreditCard>& entry : cards) {
-    std::unique_ptr<EntityData> entity_data = CreateEntityDataFromCard(*entry);
-    sync_pb::WalletMaskedCreditCard* wallet_card =
-        entity_data->specifics.mutable_autofill_wallet()->mutable_masked_card();
-
-    wallet_card->set_id(GetBase64EncodedServerId(wallet_card->id()));
-    // The billing address id might refer to a local profile guid which doesn't
-    // need to be encoded.
-    if (!base::IsStringUTF8(wallet_card->billing_address_id())) {
-      wallet_card->set_billing_address_id(
-          GetBase64EncodedServerId(wallet_card->billing_address_id()));
-    }
-
-    batch->Put(GetStorageKeyForWalletDataSpecificsId(
-                   GetSpecificsIdFromCreditCard(*entry)),
-               std::move(entity_data));
-  }
-
-  if (customer_data) {
-    batch->Put(GetStorageKeyForWalletDataSpecificsId(
-                   GetSpecificsIdFromPaymentsCustomerData(*customer_data)),
-               CreateEntityDataFromPaymentsCustomerData(*customer_data));
-  }
-  std::move(callback).Run(std::move(batch));
+  GetAllDataImpl(std::move(callback), /*enforce_utf8=*/true);
 }
 
 std::string AutofillWalletSyncBridge::GetClientTag(
@@ -312,6 +266,11 @@
 }
 
 void AutofillWalletSyncBridge::GetAllDataForTesting(DataCallback callback) {
+  GetAllDataImpl(std::move(callback), /*enforce_utf8=*/false);
+}
+
+void AutofillWalletSyncBridge::GetAllDataImpl(DataCallback callback,
+                                              bool enforce_utf8) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   std::vector<std::unique_ptr<AutofillProfile>> profiles;
@@ -329,12 +288,12 @@
   for (const std::unique_ptr<AutofillProfile>& entry : profiles) {
     batch->Put(GetStorageKeyForWalletDataSpecificsId(
                    GetSpecificsIdFromAutofillProfile(*entry)),
-               CreateEntityDataFromAutofillServerProfile(*entry));
+               CreateEntityDataFromAutofillServerProfile(*entry, enforce_utf8));
   }
   for (const std::unique_ptr<CreditCard>& entry : cards) {
     batch->Put(GetStorageKeyForWalletDataSpecificsId(
                    GetSpecificsIdFromCreditCard(*entry)),
-               CreateEntityDataFromCard(*entry));
+               CreateEntityDataFromCard(*entry, enforce_utf8));
   }
 
   if (customer_data) {
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h b/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h
index 46d91c2..17ea21c9 100644
--- a/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h
+++ b/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h
@@ -71,7 +71,7 @@
       override;
 
   // Sends all Wallet Data to the |callback| and keeps all the strings in their
-  // original format.
+  // original format (whereas GetAllDataForDebugging() has to make them UTF-8).
   void GetAllDataForTesting(DataCallback callback);
 
  private:
@@ -84,6 +84,10 @@
     bool IsEmpty() const { return items_added == 0 && items_removed == 0; }
   };
 
+  // Sends all Wallet Data to the |callback|. If |enforce_utf8|, the string
+  // fields that are in non-UTF-8 get encoded so that they conform to UTF-8.
+  void GetAllDataImpl(DataCallback callback, bool enforce_utf8);
+
   // Sets the wallet data from |entity_data| to this client and records metrics
   // about added/deleted data.
   void SetSyncData(const syncer::EntityChangeList& entity_data);
diff --git a/components/autofill_assistant/browser/client.h b/components/autofill_assistant/browser/client.h
index e4b5b1a..1bb17d42 100644
--- a/components/autofill_assistant/browser/client.h
+++ b/components/autofill_assistant/browser/client.h
@@ -24,6 +24,10 @@
   // Returns the API key to be used for requests to the backend.
   virtual std::string GetApiKey() = 0;
 
+  // Returns the e-mail address that corresponds to the auth credentials. Might
+  // be empty.
+  virtual std::string GetAccountEmailAddress() = 0;
+
   // Returns the AccessTokenFetcher to use to get oauth credentials.
   virtual AccessTokenFetcher* GetAccessTokenFetcher() = 0;
 
@@ -36,6 +40,16 @@
   // Returns a UiController.
   virtual UiController* GetUiController() = 0;
 
+  // Returns the locale.
+  virtual std::string GetLocale() = 0;
+
+  // Returns the country code.
+  virtual std::string GetCountryCode() = 0;
+
+  // Stops autofill assistant for the current WebContents, both controller and
+  // UI.
+  virtual void Stop() = 0;
+
  protected:
   Client() = default;
 };
diff --git a/components/autofill_assistant/browser/controller.cc b/components/autofill_assistant/browser/controller.cc
index 1cdfb64..b7e282a 100644
--- a/components/autofill_assistant/browser/controller.cc
+++ b/components/autofill_assistant/browser/controller.cc
@@ -50,23 +50,34 @@
 
 }  // namespace
 
-// static
-void Controller::CreateForWebContents(
-    content::WebContents* web_contents,
-    std::unique_ptr<Client> client,
-    std::unique_ptr<std::map<std::string, std::string>> parameters,
-    const std::string& locale,
-    const std::string& country_code) {
-  // Get the key early since |client| will be invalidated when moved below.
-  GURL server_url(client->GetServerUrl());
-  DCHECK(server_url.is_valid());
+Controller::Controller(content::WebContents* web_contents,
+                       Client* client,
+                       std::unique_ptr<WebController> web_controller,
+                       std::unique_ptr<Service> service)
+    : content::WebContentsObserver(web_contents),
+      client_(client),
+      web_controller_(std::move(web_controller)),
+      service_(std::move(service)),
+      memory_(std::make_unique<ClientMemory>()),
+      touchable_element_area_(web_controller_.get()),
+      script_tracker_(std::make_unique<ScriptTracker>(/* delegate= */ this,
+                                                      /* listener= */ this)),
+      weak_ptr_factory_(this) {
+  // Only set the controller as the delegate if web_contents does not yet have
+  // one.
+  // TODO(crbug.com/806868): Find a better way to get a loading progress instead
+  // of using the controller as a web_contents delegate. It may interfere with
+  // an already existing delegate.
+  if (web_contents->GetDelegate() == nullptr) {
+    clear_web_contents_delegate_ = true;
+    web_contents->SetDelegate(this);
+  }
+}
 
-  std::unique_ptr<Service> service = std::make_unique<Service>(
-      client->GetApiKey(), server_url, web_contents->GetBrowserContext(),
-      client->GetAccessTokenFetcher(), locale, country_code);
-  new Controller(web_contents, std::move(client),
-                 WebController::CreateForWebContents(web_contents),
-                 std::move(service), std::move(parameters));
+Controller::~Controller() {
+  if (clear_web_contents_delegate_) {
+    web_contents()->SetDelegate(nullptr);
+  }
 }
 
 Service* Controller::GetService() {
@@ -86,7 +97,7 @@
 }
 
 const std::map<std::string, std::string>& Controller::GetParameters() {
-  return *parameters_;
+  return parameters_;
 }
 
 autofill::PersonalDataManager* Controller::GetPersonalDataManager() {
@@ -102,43 +113,6 @@
   touchable_element_area_.SetElements(elements);
 }
 
-Controller::Controller(
-    content::WebContents* web_contents,
-    std::unique_ptr<Client> client,
-    std::unique_ptr<WebController> web_controller,
-    std::unique_ptr<Service> service,
-    std::unique_ptr<std::map<std::string, std::string>> parameters)
-    : content::WebContentsObserver(web_contents),
-      client_(std::move(client)),
-      web_controller_(std::move(web_controller)),
-      service_(std::move(service)),
-      parameters_(std::move(parameters)),
-      memory_(std::make_unique<ClientMemory>()),
-      touchable_element_area_(web_controller_.get()),
-      script_tracker_(std::make_unique<ScriptTracker>(/* delegate= */ this,
-                                                      /* listener= */ this)),
-      weak_ptr_factory_(this) {
-  DCHECK(parameters_);
-
-  // Only set the controller as the delegate if web_contents does not yet have
-  // one.
-  // TODO(crbug.com/806868): Find a better way to get a loading progress instead
-  // of using the controller as a web_contents delegate. It may interfere with
-  // an already existing delegate.
-  if (web_contents->GetDelegate() == nullptr) {
-    clear_web_contents_delegate_ = true;
-    web_contents->SetDelegate(this);
-  }
-
-  GetUiController()->SetUiDelegate(this);
-}
-
-Controller::~Controller() {
-  if (clear_web_contents_delegate_) {
-    web_contents()->SetDelegate(nullptr);
-  }
-}
-
 void Controller::GetOrCheckScripts(const GURL& url) {
   if (!started_ || script_tracker_->running()) {
     return;
@@ -148,7 +122,7 @@
     StopPeriodicScriptChecks();
     script_domain_ = url.host();
     service_->GetScriptsForUrl(
-        url, *parameters_,
+        url, parameters_,
         base::BindOnce(&Controller::OnGetScripts, base::Unretained(this), url));
   } else {
     script_tracker_->CheckScripts(kPeriodicScriptCheckInterval);
@@ -342,7 +316,7 @@
 void Controller::OnGetCookie(const GURL& initial_url, bool has_cookie) {
   if (has_cookie) {
     // This code is only active with the experiment parameter.
-    parameters_->insert(
+    parameters_.insert(
         std::make_pair(kWebsiteVisitedBeforeParameterName, kTrueValue));
     OnSetCookie(initial_url, has_cookie);
     return;
@@ -377,8 +351,14 @@
       base::Unretained(GetUiController())));
 }
 
-void Controller::Start(const GURL& initialUrl) {
-  DCHECK(initialUrl.is_valid());
+void Controller::Start(const GURL& initialUrl,
+                       const std::map<std::string, std::string>& parameters) {
+  if (started_) {
+    NOTREACHED();
+    return;
+  }
+
+  parameters_ = parameters;
   if (IsCookieExperimentEnabled()) {
     GetWebController()->HasCookie(
         base::BindOnce(&Controller::OnGetCookie,
@@ -394,10 +374,6 @@
   // TODO(crbug.com/806868): Stop executing scripts.
 }
 
-void Controller::OnDestroy() {
-  delete this;
-}
-
 bool Controller::Terminate() {
   StopPeriodicScriptChecks();
   return script_tracker_->Terminate();
@@ -425,7 +401,7 @@
   base::Value dict(base::Value::Type::DICTIONARY);
 
   std::vector<base::Value> parameters_js;
-  for (const auto& entry : *parameters_) {
+  for (const auto& entry : parameters_) {
     base::Value parameter_js = base::Value(base::Value::Type::DICTIONARY);
     parameter_js.SetKey(entry.first, base::Value(entry.second));
     parameters_js.push_back(std::move(parameter_js));
@@ -543,10 +519,6 @@
   GetUiController()->Shutdown();
 }
 
-void Controller::WebContentsDestroyed() {
-  OnDestroy();
-}
-
 void Controller::LoadProgressChanged(content::WebContents* source,
                                      double progress) {
   int percent = 100 * progress;
@@ -565,8 +537,8 @@
 }
 
 bool Controller::IsCookieExperimentEnabled() const {
-  auto iter = parameters_->find(kCookieExperimentName);
-  return iter != parameters_->end() && iter->second == "1";
+  auto iter = parameters_.find(kCookieExperimentName);
+  return iter != parameters_.end() && iter->second == "1";
 }
 
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/controller.h b/components/autofill_assistant/browser/controller.h
index 923c421..b0d2b8d 100644
--- a/components/autofill_assistant/browser/controller.h
+++ b/components/autofill_assistant/browser/controller.h
@@ -40,12 +40,32 @@
                    private content::WebContentsObserver,
                    private content::WebContentsDelegate {
  public:
-  static void CreateForWebContents(
-      content::WebContents* web_contents,
-      std::unique_ptr<Client> client,
-      std::unique_ptr<std::map<std::string, std::string>> parameters,
-      const std::string& locale,
-      const std::string& country_code);
+  // |web_contents| and |client| must remain valid for the lifetime of the
+  // instance.
+  Controller(content::WebContents* web_contents,
+             Client* client,
+             std::unique_ptr<WebController> web_controller,
+             std::unique_ptr<Service> service);
+  ~Controller() override;
+
+  // Called when autofill assistant can start executing scripts.
+  void Start(const GURL& initialUrl,
+             const std::map<std::string, std::string>& parameters);
+
+  // Initiates a clean shutdown.
+  //
+  // This function returns false when it needs more time to properly shut down
+  // the script tracker. It usually means that it either has to wait for a
+  // script to find an appropriate moment to suspend execution or wait for a
+  // script checking round to complete.
+  //
+  // A caller is expected to try again later when this function returns false. A
+  // return value of true means that the scrip tracker can safely be destroyed.
+  //
+  // TODO(crbug.com/806868): Instead of this safety net, the proper fix is to
+  // switch to weak pointers everywhere so that dangling callbacks are not an
+  // issue.
+  bool Terminate();
 
   // Overrides ScriptExecutorDelegate:
   Service* GetService() override;
@@ -62,13 +82,6 @@
  private:
   friend ControllerTest;
 
-  Controller(content::WebContents* web_contents,
-             std::unique_ptr<Client> client,
-             std::unique_ptr<WebController> web_controller,
-             std::unique_ptr<Service> service,
-             std::unique_ptr<std::map<std::string, std::string>> parameters);
-  ~Controller() override;
-
   void GetOrCheckScripts(const GURL& url);
   void OnGetScripts(const GURL& url, bool result, const std::string& response);
   void ExecuteScript(const std::string& script_path);
@@ -100,14 +113,11 @@
   void FinishStart(const GURL& initial_url);
 
   // Overrides autofill_assistant::UiDelegate:
-  void Start(const GURL& initialUrl) override;
   void OnClickOverlay() override;
-  void OnDestroy() override;
   void UpdateTouchableArea() override;
   void OnUserInteractionInsideTouchableArea() override;
   void OnScriptSelected(const std::string& script_path) override;
   std::string GetDebugContext() override;
-  bool Terminate() override;
 
   // Overrides ScriptTracker::Listener:
   void OnNoRunnableScriptsAnymore() override;
@@ -122,16 +132,15 @@
       content::NavigationHandle* navigation_handle) override;
   void DocumentAvailableInMainFrame() override;
   void RenderProcessGone(base::TerminationStatus status) override;
-  void WebContentsDestroyed() override;
 
   // Overrides content::WebContentsDelegate:
   void LoadProgressChanged(content::WebContents* source,
                            double progress) override;
 
-  std::unique_ptr<Client> client_;
+  Client* const client_;
   std::unique_ptr<WebController> web_controller_;
   std::unique_ptr<Service> service_;
-  std::unique_ptr<std::map<std::string, std::string>> parameters_;
+  std::map<std::string, std::string> parameters_;
   std::unique_ptr<ClientMemory> memory_;
 
   // Domain of the last URL the controller requested scripts from.
diff --git a/components/autofill_assistant/browser/controller_unittest.cc b/components/autofill_assistant/browser/controller_unittest.cc
index ecffaed9..b019b569 100644
--- a/components/autofill_assistant/browser/controller_unittest.cc
+++ b/components/autofill_assistant/browser/controller_unittest.cc
@@ -39,8 +39,8 @@
 
 class FakeClient : public Client {
  public:
-  explicit FakeClient(std::unique_ptr<UiController> ui_controller)
-      : ui_controller_(std::move(ui_controller)) {}
+  explicit FakeClient(UiController* ui_controller)
+      : ui_controller_(ui_controller) {}
 
   // Implements Client
   std::string GetApiKey() override { return ""; }
@@ -49,52 +49,34 @@
     return nullptr;
   }
   std::string GetServerUrl() override { return ""; }
-  UiController* GetUiController() override { return ui_controller_.get(); }
+  UiController* GetUiController() override { return ui_controller_; }
+  std::string GetAccountEmailAddress() override { return ""; }
+  std::string GetLocale() override { return ""; }
+  std::string GetCountryCode() override { return ""; }
+  void Stop() override {}
 
  private:
-  std::unique_ptr<UiController> ui_controller_;
+  UiController* ui_controller_;
 };
 
 }  // namespace
 
 class ControllerTest : public content::RenderViewHostTestHarness {
  public:
-  ControllerTest() {}
+  ControllerTest() : fake_client_(&mock_ui_controller_) {}
   ~ControllerTest() override {}
 
-  static Controller* CreateController(
-      content::WebContents* web_contents,
-      std::unique_ptr<Client> client,
-      std::unique_ptr<WebController> web_controller,
-      std::unique_ptr<Service> service,
-      std::unique_ptr<std::map<std::string, std::string>> parameters) {
-    return new Controller(web_contents, std::move(client),
-                          std::move(web_controller), std::move(service),
-                          std::move(parameters));
-  }
-
-  static void DestroyController(Controller* controller) {
-    controller->OnDestroy();
-  }
-
   void SetUp() override {
     content::RenderViewHostTestHarness::SetUp();
 
-    auto ui_controller = std::make_unique<NiceMock<MockUiController>>();
-    mock_ui_controller_ = ui_controller.get();
     auto web_controller = std::make_unique<NiceMock<MockWebController>>();
     mock_web_controller_ = web_controller.get();
     auto service = std::make_unique<NiceMock<MockService>>();
     mock_service_ = service.get();
-    auto parameters = std::make_unique<std::map<std::string, std::string>>();
-    parameters->insert(std::make_pair("a", "b"));
-    GURL initialUrl("http://initialurl.com");
 
-    controller_ = new Controller(
-        web_contents(), std::make_unique<FakeClient>(std::move(ui_controller)),
-        std::move(web_controller), std::move(service), std::move(parameters));
-
-    GetUiDelegate()->Start(initialUrl);
+    controller_ = std::make_unique<Controller>(web_contents(), &fake_client_,
+                                               std::move(web_controller),
+                                               std::move(service));
 
     // Fetching scripts succeeds for all URLs, but return nothing.
     ON_CALL(*mock_service_, OnGetScriptsForUrl(_, _, _))
@@ -111,7 +93,10 @@
   }
 
   void TearDown() override {
-    DestroyController(controller_);  // deletes the controller and mocks
+    // Controller must be deleted before the WebContents, owned by
+    // RenderViewHostTestHarness. In production, this is guaranteed by
+    // autofill_assistant::ClientAndroid, which owns Controller.
+    controller_.reset();
     content::RenderViewHostTestHarness::TearDown();
   }
 
@@ -133,6 +118,11 @@
     run_once->set_status(SCRIPT_STATUS_NOT_RUN);
   }
 
+  void Start() {
+    GURL initialUrl("http://initialurl.com");
+    controller_->Start(initialUrl, /* parameters= */ {});
+  }
+
   void SetLastCommittedUrl(const GURL& url) {
     url_ = url;
     tester_->SetLastCommittedURL(url);
@@ -167,21 +157,21 @@
         .WillRepeatedly(RunOnceCallback<2>(true, response_str));
   }
 
-  UiDelegate* GetUiDelegate() { return controller_; }
+  UiDelegate* GetUiDelegate() { return controller_.get(); }
 
   GURL url_;
   MockService* mock_service_;
   MockWebController* mock_web_controller_;
-  MockUiController* mock_ui_controller_;
+  FakeClient fake_client_;
+  NiceMock<MockUiController> mock_ui_controller_;
   content::WebContentsTester* tester_;
 
-  // |controller_| deletes itself when OnDestroy is called from Setup. Outside
-  // of tests, the controller deletes itself when the web contents it observers
-  // is destroyed or when UiDelegate::OnDestroy is called.
-  Controller* controller_;
+  std::unique_ptr<Controller> controller_;
 };
 
 TEST_F(ControllerTest, FetchAndRunScripts) {
+  Start();
+
   // Going to the URL triggers a whole flow:
   // 1. loading scripts
   SupportsScriptResponseProto script_response;
@@ -192,7 +182,7 @@
   // 2. checking the scripts
   // 3. offering the choices: script1 and script2
   // 4. script1 is chosen
-  EXPECT_CALL(*mock_ui_controller_, UpdateScripts(SizeIs(2)))
+  EXPECT_CALL(mock_ui_controller_, UpdateScripts(SizeIs(2)))
       .WillOnce([this](const std::vector<ScriptHandle>& scripts) {
         std::vector<std::string> paths;
         for (const auto& script : scripts) {
@@ -202,11 +192,11 @@
 
         Sequence sequence;
         // Selecting a script should clean the bottom bar.
-        EXPECT_CALL(*mock_ui_controller_, UpdateScripts(SizeIs(0)))
+        EXPECT_CALL(mock_ui_controller_, UpdateScripts(SizeIs(0)))
             .InSequence(sequence);
         // After the script is done both scripts are again valid and should be
         // shown.
-        EXPECT_CALL(*mock_ui_controller_, UpdateScripts(SizeIs(2)))
+        EXPECT_CALL(mock_ui_controller_, UpdateScripts(SizeIs(2)))
             .InSequence(sequence);
 
         GetUiDelegate()->OnScriptSelected("script1");
@@ -223,6 +213,8 @@
 }
 
 TEST_F(ControllerTest, ShowFirstInitialPrompt) {
+  Start();
+
   SupportsScriptResponseProto script_response;
   AddRunnableScript(&script_response, "script1");
 
@@ -244,14 +236,16 @@
   SetNextScriptResponse(script_response);
 
   // Script3, with higher priority (lower number), wins.
-  EXPECT_CALL(*mock_ui_controller_, ShowStatusMessage("script3 prompt"));
-  EXPECT_CALL(*mock_ui_controller_, UpdateScripts(SizeIs(4)));
+  EXPECT_CALL(mock_ui_controller_, ShowStatusMessage("script3 prompt"));
+  EXPECT_CALL(mock_ui_controller_, UpdateScripts(SizeIs(4)));
 
   // Start the flow.
   SimulateNavigateToUrl(GURL("http://a.example.com/path"));
 }
 
 TEST_F(ControllerTest, Stop) {
+  Start();
+
   ActionsResponseProto actions_response;
   actions_response.add_actions()->mutable_stop();
   std::string actions_response_str;
@@ -261,11 +255,13 @@
   EXPECT_CALL(*mock_service_, OnGetNextActions(_, _, _, _))
       .WillOnce(RunOnceCallback<3>(true, ""));
 
-  EXPECT_CALL(*mock_ui_controller_, Shutdown());
+  EXPECT_CALL(mock_ui_controller_, Shutdown());
+
   GetUiDelegate()->OnScriptSelected("stop");
 }
 
 TEST_F(ControllerTest, Reset) {
+  Start();
   {
     InSequence sequence;
 
@@ -277,12 +273,12 @@
     EXPECT_CALL(*mock_service_, OnGetScriptsForUrl(_, _, _))
         .WillOnce(RunOnceCallback<2>(true, script_response_str));
 
-    EXPECT_CALL(*mock_ui_controller_, UpdateScripts(SizeIs(1)));
+    EXPECT_CALL(mock_ui_controller_, UpdateScripts(SizeIs(1)));
 
     // 2. Execute the "reset" script, which contains a reset action.
 
     // Selecting a script should clean the bottom bar.
-    EXPECT_CALL(*mock_ui_controller_, UpdateScripts(SizeIs(0)));
+    EXPECT_CALL(mock_ui_controller_, UpdateScripts(SizeIs(0)));
 
     ActionsResponseProto actions_response;
     actions_response.add_actions()->mutable_reset();
@@ -302,7 +298,7 @@
 
     // Reset forces the controller to fetch the scripts twice, even though the
     // URL doesn't change..
-    EXPECT_CALL(*mock_ui_controller_, UpdateScripts(SizeIs(1)));
+    EXPECT_CALL(mock_ui_controller_, UpdateScripts(SizeIs(1)));
   }
 
   // Resetting should clear the client memory
@@ -315,6 +311,8 @@
 }
 
 TEST_F(ControllerTest, RefreshScriptWhenDomainChanges) {
+  Start();
+
   EXPECT_CALL(*mock_service_,
               OnGetScriptsForUrl(Eq(GURL("http://a.example.com/path1")), _, _))
       .WillOnce(RunOnceCallback<2>(true, ""));
@@ -329,15 +327,19 @@
 }
 
 TEST_F(ControllerTest, ForwardParameters) {
-  // Parameter a=b is set in SetUp.
   EXPECT_CALL(*mock_service_,
               OnGetScriptsForUrl(_, Contains(Pair("a", "b")), _))
       .WillOnce(RunOnceCallback<2>(true, ""));
 
-  SimulateNavigateToUrl(GURL("http://example.com/"));
+  GURL initialUrl("http://example.com/");
+  std::map<std::string, std::string> parameters;
+  parameters["a"] = "b";
+  controller_->Start(initialUrl, parameters);
 }
 
 TEST_F(ControllerTest, Autostart) {
+  Start();
+
   SupportsScriptResponseProto script_response;
   AddRunnableScript(&script_response, "runnable");
   AddRunnableScript(&script_response, "autostart")
@@ -353,6 +355,8 @@
 }
 
 TEST_F(ControllerTest, AutostartFirstInterrupt) {
+  Start();
+
   SupportsScriptResponseProto script_response;
   AddRunnableScript(&script_response, "runnable");
 
@@ -380,6 +384,8 @@
 }
 
 TEST_F(ControllerTest, InterruptThenAutostart) {
+  Start();
+
   SupportsScriptResponseProto script_response;
   AddRunnableScript(&script_response, "runnable");
 
@@ -406,20 +412,26 @@
 }
 
 TEST_F(ControllerTest, AutostartIsNotPassedToTheUi) {
+  Start();
+
   SupportsScriptResponseProto script_response;
   auto* autostart = AddRunnableScript(&script_response, "runnable");
   autostart->mutable_presentation()->set_autostart(true);
   RunOnce(autostart);
   SetRepeatedScriptResponse(script_response);
 
-  EXPECT_CALL(*mock_ui_controller_, UpdateScripts(SizeIs(0))).Times(AtLeast(1));
+  EXPECT_CALL(mock_ui_controller_, UpdateScripts(SizeIs(0))).Times(AtLeast(1));
+
   SimulateNavigateToUrl(GURL("http://a.example.com/path"));
 }
 
 TEST_F(ControllerTest, LoadProgressChanged) {
+  Start();
+
   SetLastCommittedUrl(GURL("http://a.example.com/path"));
 
   EXPECT_CALL(*mock_service_, OnGetScriptsForUrl(_, _, _)).Times(0);
+
   SimulateProgressChanged(0.1);
   SimulateProgressChanged(0.3);
   SimulateProgressChanged(0.5);
@@ -430,75 +442,30 @@
   SimulateProgressChanged(0.4);
 }
 
-TEST_F(ControllerTest, InitialUrlLoadsDoesntStartByDefault) {
-  GURL initialUrl("http://a.example.com/path");
-  auto service = std::make_unique<NiceMock<MockService>>();
-
-  EXPECT_CALL(*service.get(), OnGetScriptsForUrl(Eq(initialUrl), _, _))
-      .Times(0);
-
-  Controller* controller = ControllerTest::CreateController(
-      web_contents(),
-      std::make_unique<FakeClient>(
-          std::make_unique<NiceMock<MockUiController>>()),
-      std::make_unique<NiceMock<MockWebController>>(), std::move(service),
-      std::make_unique<std::map<std::string, std::string>>());
-  ControllerTest::DestroyController(controller);
-}
-
 TEST_F(ControllerTest, InitialUrlLoads) {
   GURL initialUrl("http://a.example.com/path");
-  auto service = std::make_unique<NiceMock<MockService>>();
-
-  EXPECT_CALL(*service.get(), OnGetScriptsForUrl(Eq(initialUrl), _, _))
+  EXPECT_CALL(*mock_service_, OnGetScriptsForUrl(Eq(initialUrl), _, _))
       .WillOnce(RunOnceCallback<2>(true, ""));
 
-  Controller* controller = ControllerTest::CreateController(
-      web_contents(),
-      std::make_unique<FakeClient>(
-          std::make_unique<NiceMock<MockUiController>>()),
-      std::make_unique<NiceMock<MockWebController>>(), std::move(service),
-      std::make_unique<std::map<std::string, std::string>>());
-  dynamic_cast<UiDelegate*>(controller)->Start(initialUrl);
-  ControllerTest::DestroyController(controller);
+  controller_->Start(initialUrl, /* parameters= */ {});
 }
 
 TEST_F(ControllerTest, CookieExperimentEnabled) {
-  auto parameters = std::make_unique<std::map<std::string, std::string>>();
-  parameters->insert(std::make_pair("EXP_COOKIE", "1"));
+  GURL initialUrl("http://a.example.com/path");
 
-  Controller* controller = ControllerTest::CreateController(
-      web_contents(),
-      std::make_unique<FakeClient>(
-          std::make_unique<NiceMock<MockUiController>>()),
-      std::make_unique<NiceMock<MockWebController>>(),
-      std::make_unique<NiceMock<MockService>>(), std::move(parameters));
+  // TODO(crbug.com/806868): Extend this test once the cookie information is
+  // passed to the initial request. Currently the public controller API does not
+  // yet allow proper testing.
+  EXPECT_CALL(*mock_service_, OnGetScriptsForUrl(Eq(initialUrl), _, _))
+      .WillOnce(RunOnceCallback<2>(true, ""));
+
+  std::map<std::string, std::string> parameters;
+  parameters.insert(std::make_pair("EXP_COOKIE", "1"));
+  controller_->Start(initialUrl, parameters);
 
   // TODO(crbug.com): Make IsCookieExperimentEnabled private and remove this
   // test when we pass the cookie data along in the initial request so that it
   // can be tested.
-  EXPECT_TRUE(controller->IsCookieExperimentEnabled());
+  EXPECT_TRUE(controller_->IsCookieExperimentEnabled());
 }
-
-// TODO(crbug.com/806868): Extend this test once the cookie information is
-// passed to the initial request. Currently the public controller API does not
-// yet allow proper testing.
-TEST_F(ControllerTest, CookieExperimentSmokeTest) {
-  GURL initialUrl("http://a.example.com/path");
-
-  auto service = std::make_unique<NiceMock<MockService>>();
-  auto ui_controller = std::make_unique<NiceMock<MockUiController>>();
-  auto parameters = std::make_unique<std::map<std::string, std::string>>();
-  parameters->insert(std::make_pair("EXP_COOKIE", "1"));
-
-  EXPECT_CALL(*service.get(), OnGetScriptsForUrl(Eq(initialUrl), _, _))
-      .WillOnce(RunOnceCallback<2>(true, ""));
-
-  Controller* controller = ControllerTest::CreateController(
-      web_contents(), std::make_unique<FakeClient>(std::move(ui_controller)),
-      std::make_unique<NiceMock<MockWebController>>(), std::move(service),
-      std::move(parameters));
-  dynamic_cast<UiDelegate*>(controller)->Start(initialUrl);
-}
-
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/mock_ui_controller.h b/components/autofill_assistant/browser/mock_ui_controller.h
index 9d92746e..a9d209d 100644
--- a/components/autofill_assistant/browser/mock_ui_controller.h
+++ b/components/autofill_assistant/browser/mock_ui_controller.h
@@ -21,7 +21,6 @@
   MockUiController();
   ~MockUiController() override;
 
-  MOCK_METHOD1(SetUiDelegate, void(UiDelegate* ui_delegate));
   MOCK_METHOD1(ShowStatusMessage, void(const std::string& message));
   MOCK_METHOD0(GetStatusMessage, std::string());
   MOCK_METHOD0(ShowOverlay, void());
diff --git a/components/autofill_assistant/browser/service.cc b/components/autofill_assistant/browser/service.cc
index 6125cae..ec55dc1 100644
--- a/components/autofill_assistant/browser/service.cc
+++ b/components/autofill_assistant/browser/service.cc
@@ -12,6 +12,7 @@
 #include "base/metrics/field_trial.h"
 #include "base/strings/strcat.h"
 #include "base/strings/stringprintf.h"
+#include "components/autofill_assistant/browser/client.h"
 #include "components/autofill_assistant/browser/protocol_utils.h"
 #include "components/version_info/version_info.h"
 #include "content/public/browser/browser_context.h"
@@ -54,6 +55,17 @@
 
 namespace autofill_assistant {
 
+// static
+std::unique_ptr<Service> Service::Create(content::BrowserContext* context,
+                                         Client* client) {
+  GURL server_url(client->GetServerUrl());
+  DCHECK(server_url.is_valid());
+
+  return std::make_unique<Service>(
+      client->GetApiKey(), server_url, context, client->GetAccessTokenFetcher(),
+      client->GetLocale(), client->GetCountryCode());
+}
+
 Service::Service(const std::string& api_key,
                  const GURL& server_url,
                  content::BrowserContext* context,
diff --git a/components/autofill_assistant/browser/service.h b/components/autofill_assistant/browser/service.h
index b19f3bb..29f45d7 100644
--- a/components/autofill_assistant/browser/service.h
+++ b/components/autofill_assistant/browser/service.h
@@ -24,10 +24,17 @@
 }  // namespace content
 
 namespace autofill_assistant {
+class Client;
+
 // Autofill assistant service to communicate with the server to get scripts and
 // client actions.
 class Service {
  public:
+  // Convenience method for creating a service from a client.
+  // |client| must remain valid for the lifetime of the service instance.
+  static std::unique_ptr<Service> Create(content::BrowserContext* context,
+                                         Client* client);
+
   // |context| and |token_fetcher| must remain valid for the lifetime of the
   // service instance.
   Service(const std::string& api_key,
diff --git a/components/autofill_assistant/browser/ui_controller.h b/components/autofill_assistant/browser/ui_controller.h
index a850a92..e945fe7 100644
--- a/components/autofill_assistant/browser/ui_controller.h
+++ b/components/autofill_assistant/browser/ui_controller.h
@@ -36,9 +36,6 @@
 
   virtual ~UiController() = default;
 
-  // Set assistant UI delegate called by assistant UI controller.
-  virtual void SetUiDelegate(UiDelegate* ui_delegate) = 0;
-
   // Show status message on the bottom bar.
   virtual void ShowStatusMessage(const std::string& message) = 0;
 
diff --git a/components/autofill_assistant/browser/ui_delegate.h b/components/autofill_assistant/browser/ui_delegate.h
index dd34d7c..d801179 100644
--- a/components/autofill_assistant/browser/ui_delegate.h
+++ b/components/autofill_assistant/browser/ui_delegate.h
@@ -13,16 +13,9 @@
  public:
   virtual ~UiDelegate() = default;
 
-  // Called when autofill assistant can start executing scripts.
-  virtual void Start(const GURL& initialUrl) = 0;
-
   // Called when the overlay has been clicked.
   virtual void OnClickOverlay() = 0;
 
-  // Called when the Autofill Assistant should be destroyed, e.g. the tab
-  // detached from the associated activity.
-  virtual void OnDestroy() = 0;
-
   // Asks for updated coordinates for the touchable area. This is called to
   // speed up update of the touchable areas when there are good reasons to think
   // that the current coordinates are out of date, such as while scrolling.
@@ -39,21 +32,6 @@
   // when analyzing feedback forms and for debugging in general.
   virtual std::string GetDebugContext() = 0;
 
-  // Initiates a clean shutdown.
-  //
-  // This function returns false when it needs more time to properly shut down
-  // the script tracker. It usually means that it either has to wait for a
-  // script to find an appropriate moment to suspend execution or wait for a
-  // script checking round to complete.
-  //
-  // A caller is expected to try again later when this function returns false. A
-  // return value of true means that the scrip tracker can safely be destroyed.
-  //
-  // TODO(crbug.com/806868): Instead of this safety net, the proper fix is to
-  // switch to weak pointers everywhere so that dangling callbacks are not an
-  // issue.
-  virtual bool Terminate() = 0;
-
  protected:
   UiDelegate() = default;
 };
diff --git a/components/cronet/native/generated/cronet.idl_c.h b/components/cronet/native/generated/cronet.idl_c.h
index d927cde..ac45c1ac 100644
--- a/components/cronet/native/generated/cronet.idl_c.h
+++ b/components/cronet/native/generated/cronet.idl_c.h
@@ -644,35 +644,20 @@
 // app. The following concrete methods forward call to app implementation. The
 // app doesn't normally call them.
 CRONET_EXPORT
-Cronet_RESULT Cronet_RequestFinishedInfoListener_InitWithParams(
-    Cronet_RequestFinishedInfoListenerPtr self,
-    Cronet_ExecutorPtr executor);
-CRONET_EXPORT
 void Cronet_RequestFinishedInfoListener_OnRequestFinished(
     Cronet_RequestFinishedInfoListenerPtr self,
     Cronet_RequestFinishedInfoPtr request_info);
-CRONET_EXPORT
-Cronet_ExecutorPtr Cronet_RequestFinishedInfoListener_GetExecutor(
-    Cronet_RequestFinishedInfoListenerPtr self);
 // The app implements abstract interface Cronet_RequestFinishedInfoListener by
 // defining custom functions for each method.
-typedef Cronet_RESULT (*Cronet_RequestFinishedInfoListener_InitWithParamsFunc)(
-    Cronet_RequestFinishedInfoListenerPtr self,
-    Cronet_ExecutorPtr executor);
 typedef void (*Cronet_RequestFinishedInfoListener_OnRequestFinishedFunc)(
     Cronet_RequestFinishedInfoListenerPtr self,
     Cronet_RequestFinishedInfoPtr request_info);
-typedef Cronet_ExecutorPtr (
-    *Cronet_RequestFinishedInfoListener_GetExecutorFunc)(
-    Cronet_RequestFinishedInfoListenerPtr self);
 // The app creates an instance of Cronet_RequestFinishedInfoListener by
 // providing custom functions for each method.
 CRONET_EXPORT Cronet_RequestFinishedInfoListenerPtr
 Cronet_RequestFinishedInfoListener_CreateWith(
-    Cronet_RequestFinishedInfoListener_InitWithParamsFunc InitWithParamsFunc,
     Cronet_RequestFinishedInfoListener_OnRequestFinishedFunc
-        OnRequestFinishedFunc,
-    Cronet_RequestFinishedInfoListener_GetExecutorFunc GetExecutorFunc);
+        OnRequestFinishedFunc);
 
 ///////////////////////
 // Struct Cronet_Error.
diff --git a/components/cronet/native/generated/cronet.idl_impl_interface.cc b/components/cronet/native/generated/cronet.idl_impl_interface.cc
index 2d8ccac..ecdea48 100644
--- a/components/cronet/native/generated/cronet.idl_impl_interface.cc
+++ b/components/cronet/native/generated/cronet.idl_impl_interface.cc
@@ -895,13 +895,6 @@
   return self->client_context();
 }
 
-Cronet_RESULT Cronet_RequestFinishedInfoListener_InitWithParams(
-    Cronet_RequestFinishedInfoListenerPtr self,
-    Cronet_ExecutorPtr executor) {
-  DCHECK(self);
-  return self->InitWithParams(executor);
-}
-
 void Cronet_RequestFinishedInfoListener_OnRequestFinished(
     Cronet_RequestFinishedInfoListenerPtr self,
     Cronet_RequestFinishedInfoPtr request_info) {
@@ -909,55 +902,33 @@
   self->OnRequestFinished(request_info);
 }
 
-Cronet_ExecutorPtr Cronet_RequestFinishedInfoListener_GetExecutor(
-    Cronet_RequestFinishedInfoListenerPtr self) {
-  DCHECK(self);
-  return self->GetExecutor();
-}
-
 // Implementation of Cronet_RequestFinishedInfoListener that forwards calls to C
 // functions implemented by the app.
 class Cronet_RequestFinishedInfoListenerStub
     : public Cronet_RequestFinishedInfoListener {
  public:
-  Cronet_RequestFinishedInfoListenerStub(
-      Cronet_RequestFinishedInfoListener_InitWithParamsFunc InitWithParamsFunc,
+  explicit Cronet_RequestFinishedInfoListenerStub(
       Cronet_RequestFinishedInfoListener_OnRequestFinishedFunc
-          OnRequestFinishedFunc,
-      Cronet_RequestFinishedInfoListener_GetExecutorFunc GetExecutorFunc)
-      : InitWithParamsFunc_(InitWithParamsFunc),
-        OnRequestFinishedFunc_(OnRequestFinishedFunc),
-        GetExecutorFunc_(GetExecutorFunc) {}
+          OnRequestFinishedFunc)
+      : OnRequestFinishedFunc_(OnRequestFinishedFunc) {}
 
   ~Cronet_RequestFinishedInfoListenerStub() override {}
 
  protected:
-  Cronet_RESULT InitWithParams(Cronet_ExecutorPtr executor) override {
-    return InitWithParamsFunc_(this, executor);
-  }
-
   void OnRequestFinished(Cronet_RequestFinishedInfoPtr request_info) override {
     OnRequestFinishedFunc_(this, request_info);
   }
 
-  Cronet_ExecutorPtr GetExecutor() override { return GetExecutorFunc_(this); }
-
  private:
-  const Cronet_RequestFinishedInfoListener_InitWithParamsFunc
-      InitWithParamsFunc_;
   const Cronet_RequestFinishedInfoListener_OnRequestFinishedFunc
       OnRequestFinishedFunc_;
-  const Cronet_RequestFinishedInfoListener_GetExecutorFunc GetExecutorFunc_;
 
   DISALLOW_COPY_AND_ASSIGN(Cronet_RequestFinishedInfoListenerStub);
 };
 
 Cronet_RequestFinishedInfoListenerPtr
 Cronet_RequestFinishedInfoListener_CreateWith(
-    Cronet_RequestFinishedInfoListener_InitWithParamsFunc InitWithParamsFunc,
     Cronet_RequestFinishedInfoListener_OnRequestFinishedFunc
-        OnRequestFinishedFunc,
-    Cronet_RequestFinishedInfoListener_GetExecutorFunc GetExecutorFunc) {
-  return new Cronet_RequestFinishedInfoListenerStub(
-      InitWithParamsFunc, OnRequestFinishedFunc, GetExecutorFunc);
+        OnRequestFinishedFunc) {
+  return new Cronet_RequestFinishedInfoListenerStub(OnRequestFinishedFunc);
 }
diff --git a/components/cronet/native/generated/cronet.idl_impl_interface.h b/components/cronet/native/generated/cronet.idl_impl_interface.h
index 33294a53..38d7f901 100644
--- a/components/cronet/native/generated/cronet.idl_impl_interface.h
+++ b/components/cronet/native/generated/cronet.idl_impl_interface.h
@@ -234,10 +234,8 @@
   }
   Cronet_ClientContext client_context() const { return client_context_; }
 
-  virtual Cronet_RESULT InitWithParams(Cronet_ExecutorPtr executor) = 0;
   virtual void OnRequestFinished(
       Cronet_RequestFinishedInfoPtr request_info) = 0;
-  virtual Cronet_ExecutorPtr GetExecutor() = 0;
 
  private:
   Cronet_ClientContext client_context_ = nullptr;
diff --git a/components/cronet/native/generated/cronet.idl_impl_interface_unittest.cc b/components/cronet/native/generated/cronet.idl_impl_interface_unittest.cc
index 3287b6f8..7c96c97e 100644
--- a/components/cronet/native/generated/cronet.idl_impl_interface_unittest.cc
+++ b/components/cronet/native/generated/cronet.idl_impl_interface_unittest.cc
@@ -770,9 +770,7 @@
   ~Cronet_RequestFinishedInfoListenerTest() override = default;
 
  public:
-  bool InitWithParams_called_ = false;
   bool OnRequestFinished_called_ = false;
-  bool GetExecutor_called_ = false;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(Cronet_RequestFinishedInfoListenerTest);
@@ -780,19 +778,6 @@
 
 namespace {
 // Implementation of Cronet_RequestFinishedInfoListener methods for testing.
-Cronet_RESULT TestCronet_RequestFinishedInfoListener_InitWithParams(
-    Cronet_RequestFinishedInfoListenerPtr self,
-    Cronet_ExecutorPtr executor) {
-  CHECK(self);
-  Cronet_ClientContext client_context =
-      Cronet_RequestFinishedInfoListener_GetClientContext(self);
-  auto* test =
-      static_cast<Cronet_RequestFinishedInfoListenerTest*>(client_context);
-  CHECK(test);
-  test->InitWithParams_called_ = true;
-
-  return static_cast<Cronet_RESULT>(0);
-}
 void TestCronet_RequestFinishedInfoListener_OnRequestFinished(
     Cronet_RequestFinishedInfoListenerPtr self,
     Cronet_RequestFinishedInfoPtr request_info) {
@@ -804,18 +789,6 @@
   CHECK(test);
   test->OnRequestFinished_called_ = true;
 }
-Cronet_ExecutorPtr TestCronet_RequestFinishedInfoListener_GetExecutor(
-    Cronet_RequestFinishedInfoListenerPtr self) {
-  CHECK(self);
-  Cronet_ClientContext client_context =
-      Cronet_RequestFinishedInfoListener_GetClientContext(self);
-  auto* test =
-      static_cast<Cronet_RequestFinishedInfoListenerTest*>(client_context);
-  CHECK(test);
-  test->GetExecutor_called_ = true;
-
-  return static_cast<Cronet_ExecutorPtr>(0);
-}
 }  // namespace
 
 // Test that Cronet_RequestFinishedInfoListener stub forwards function calls as
@@ -823,15 +796,10 @@
 TEST_F(Cronet_RequestFinishedInfoListenerTest, TestCreate) {
   Cronet_RequestFinishedInfoListenerPtr test =
       Cronet_RequestFinishedInfoListener_CreateWith(
-          TestCronet_RequestFinishedInfoListener_InitWithParams,
-          TestCronet_RequestFinishedInfoListener_OnRequestFinished,
-          TestCronet_RequestFinishedInfoListener_GetExecutor);
+          TestCronet_RequestFinishedInfoListener_OnRequestFinished);
   CHECK(test);
   Cronet_RequestFinishedInfoListener_SetClientContext(test, this);
-  CHECK(!InitWithParams_called_);
   CHECK(!OnRequestFinished_called_);
-  Cronet_RequestFinishedInfoListener_GetExecutor(test);
-  CHECK(GetExecutor_called_);
 
   Cronet_RequestFinishedInfoListener_Destroy(test);
 }
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
index e69e079..e5ded414 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
@@ -412,7 +412,6 @@
   }
 
   DCHECK(data);
-  MaybeAddBrotliToAcceptEncodingHeader(proxy_info, headers, *request);
 
   data_reduction_proxy_request_options_->AddRequestHeader(headers, page_id);
 
@@ -666,63 +665,6 @@
                                            &data_reduction_proxy_info);
 }
 
-void DataReductionProxyNetworkDelegate::MaybeAddBrotliToAcceptEncodingHeader(
-    const net::ProxyInfo& proxy_info,
-    net::HttpRequestHeaders* request_headers,
-    const net::URLRequest& request) const {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  if (base::FeatureList::IsEnabled(
-          features::kDataReductionProxyBrotliHoldback)) {
-    return;
-  }
-
-  // This method should be called only when the resolved proxy was a data
-  // saver proxy.
-  DCHECK(data_reduction_proxy_config_->FindConfiguredDataReductionProxy(
-      proxy_info.proxy_server()));
-  DCHECK(request.url().is_valid());
-  DCHECK(!request.url().SchemeIsCryptographic());
-  DCHECK(request.url().SchemeIsHTTPOrHTTPS());
-
-  static const char kBrotli[] = "br";
-
-  if (!request.context()->enable_brotli()) {
-    // Verify that Brotli is enabled globally.
-    return;
-  }
-
-  if (!params::IsBrotliAcceptEncodingEnabled()) {
-    // Verify that Brotli is enabled for data reduction proxy.
-    return;
-  }
-
-  if (!proxy_info.proxy_server().is_https() &&
-      !proxy_info.proxy_server().is_quic()) {
-    // Brotli encoding can be used only when the proxy server is a secure proxy
-    // server.
-    return;
-  }
-
-  if (!request_headers->HasHeader(net::HttpRequestHeaders::kAcceptEncoding))
-    return;
-
-  std::string header_value;
-  request_headers->GetHeader(net::HttpRequestHeaders::kAcceptEncoding,
-                             &header_value);
-
-  // Only add Brotli to the header if it is not already present.
-  std::set<std::string> header_entry_set;
-  if (net::HttpUtil::ParseAcceptEncoding(header_value, &header_entry_set) &&
-      header_entry_set.find(kBrotli) == header_entry_set.end()) {
-    if (!header_value.empty())
-      header_value += ", ";
-    header_value += kBrotli;
-    request_headers->SetHeader(net::HttpRequestHeaders::kAcceptEncoding,
-                               header_value);
-  }
-}
-
 void DataReductionProxyNetworkDelegate::MaybeAddChromeProxyECTHeader(
     net::HttpRequestHeaders* request_headers,
     const net::URLRequest& request) const {
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h
index 12489dc2..47e6c6d 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h
@@ -152,13 +152,6 @@
       const net::ProxyInfo& proxy_info,
       const net::ProxyRetryInfoMap& proxy_retry_info) const;
 
-  // May add Brotli to Accept Encoding request header if |proxy_info| contains
-  // a proxy server that is expected to support Brotli encoding.
-  void MaybeAddBrotliToAcceptEncodingHeader(
-      const net::ProxyInfo& proxy_info,
-      net::HttpRequestHeaders* request_headers,
-      const net::URLRequest& request) const;
-
   // May add chrome-proxy-ect header to |request_headers| if adding of
   // chrome-proxy-ect is enabled via field trial and a valid estimate of
   // network quality is available. This method should be called only when the
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
index 4cfc161..1502f22 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
@@ -299,7 +299,7 @@
         net::GetTestCertsDirectory(), "unittest.selfsigned.der");
   }
 
-  void Init(ProxyTestConfig proxy_config, bool enable_brotli_globally) {
+  void Init(ProxyTestConfig proxy_config) {
     net::ProxyServer proxy_server;
     switch (proxy_config) {
       case BYPASS_PROXY:
@@ -346,7 +346,6 @@
     lofi_ui_service_ = lofi_ui_service.get();
     test_context_->io_data()->set_lofi_ui_service(std::move(lofi_ui_service));
 
-    context_->set_enable_brotli(enable_brotli_globally);
     context_->Init();
 
     test_context_->DisableWarmupURLFetch();
@@ -484,182 +483,6 @@
     return request;
   }
 
-  // Reads brotli encoded content to |encoded_brotli_buffer_|.
-  void ReadBrotliFile() {
-    // Get the path of data directory.
-    const size_t kDefaultBufferSize = 4096;
-    base::FilePath data_dir;
-    base::PathService::Get(base::DIR_SOURCE_ROOT, &data_dir);
-    data_dir = data_dir.AppendASCII("net");
-    data_dir = data_dir.AppendASCII("data");
-    data_dir = data_dir.AppendASCII("filter_unittests");
-
-    // Read data from the encoded file into buffer.
-    base::FilePath encoded_file_path;
-    encoded_file_path = data_dir.AppendASCII("google.br");
-    ASSERT_TRUE(
-        base::ReadFileToString(encoded_file_path, &encoded_brotli_buffer_));
-    ASSERT_GE(kDefaultBufferSize, encoded_brotli_buffer_.size());
-  }
-
-  // Fetches a single URL request, verifies the correctness of Accept-Encoding
-  // header, and verifies that the response is cached only if |expect_cached|
-  // is set to true. Each line in |response_headers| should end with "\r\n" and
-  // not '\0', and the last line should have a second "\r\n". An empty
-  // |response_headers| is allowed. It works by making this look like an
-  // HTTP/0.9 response, since HTTP/0.9 responses don't have headers.
-  void FetchURLRequestAndVerifyBrotli(net::HttpRequestHeaders* request_headers,
-                                      const std::string& response_headers,
-                                      bool expect_cached,
-                                      bool expect_brotli) {
-    test_network_quality_tracker()->ReportEffectiveConnectionTypeForTesting(
-        net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN);
-    base::RunLoop().RunUntilIdle();
-    GURL url(kTestURL);
-
-    int response_body_size = 140;
-    std::string response_body;
-    if (expect_brotli && !expect_cached) {
-      response_body = encoded_brotli_buffer_;
-      response_body_size = response_body.size();
-    } else {
-      response_body =
-          std::string(base::checked_cast<size_t>(response_body_size), ' ');
-    }
-
-    mock_socket_factory_->AddSSLSocketDataProvider(&ssl_socket_data_provider_);
-
-    net::MockRead reads[] = {net::MockRead(response_headers.c_str()),
-                             net::MockRead(response_body.c_str()),
-                             net::MockRead(net::SYNCHRONOUS, net::OK)};
-
-    if (io_data()->test_request_options()->GetHeaderValueForTesting().empty()) {
-      // Force regeneration of Chrome-Proxy header.
-      io_data()->test_request_options()->SetSecureSession("123");
-    }
-    EXPECT_FALSE(
-        io_data()->test_request_options()->GetHeaderValueForTesting().empty());
-
-    std::string host = GURL(kTestURL).host();
-    std::string prefix_headers = std::string("GET ")
-                                     .append(kTestURL)
-                                     .append(
-                                         " HTTP/1.1\r\n"
-                                         "Host: ")
-                                     .append(host)
-                                     .append(
-                                         "\r\n"
-                                         "Proxy-Connection: keep-alive\r\n");
-    std::string user_agent_header = "User-Agent: \r\n";
-
-    // Set the base Accept-Encoding header value; Brotli may be added to it.
-    std::string accept_encoding_header_value;
-    bool accept_encoding_header_value_includes_brotli = false;
-    bool has_accept_encoding_request_header =
-        request_headers &&
-        request_headers->HasHeader(net::HttpRequestHeaders::kAcceptEncoding);
-    if (has_accept_encoding_request_header) {
-      request_headers->GetHeader(net::HttpRequestHeaders::kAcceptEncoding,
-                                 &accept_encoding_header_value);
-      // Check for if the Accept-Encoding header value already includes Brotli.
-      std::set<std::string> accept_encoding_header_entry_set;
-      if (net::HttpUtil::ParseAcceptEncoding(
-              accept_encoding_header_value,
-              &accept_encoding_header_entry_set) &&
-          accept_encoding_header_entry_set.find("br") !=
-              accept_encoding_header_entry_set.end()) {
-        accept_encoding_header_value_includes_brotli = true;
-      }
-    } else {
-      accept_encoding_header_value = "gzip, deflate";
-    }
-
-    // Add Brotli to the Accept-Encoding header value if it is expected and not
-    // already included. Brotli is expected if the request went to the network
-    // (i.e., it was not a cached response), and it is a case where the data
-    // reduction proxy network delegate adds Brotli to the header.
-    if (expect_brotli && !expect_cached &&
-        !accept_encoding_header_value_includes_brotli) {
-      if (!accept_encoding_header_value.empty())
-        accept_encoding_header_value += ", ";
-      accept_encoding_header_value += "br";
-      accept_encoding_header_value_includes_brotli = true;
-    }
-
-    std::string accept_encoding_header =
-        "Accept-Encoding: " + accept_encoding_header_value + "\r\n";
-
-    std::string accept_language_header("Accept-Language: en-us,fr\r\n");
-    std::string ect_header = "chrome-proxy-ect: " +
-                             std::string(net::GetNameForEffectiveConnectionType(
-                                 net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN)) +
-                             "\r\n";
-
-    std::string suffix_headers =
-        std::string("chrome-proxy: ") +
-        io_data()->test_request_options()->GetHeaderValueForTesting() +
-        std::string("\r\n\r\n");
-
-    // If an Accept-Encoding header was provided, then Accept-Encoding appears
-    // before User-Agent; otherwise, it appears after it.
-    std::string mock_write;
-    if (has_accept_encoding_request_header) {
-      mock_write = prefix_headers + accept_encoding_header + user_agent_header +
-                   accept_language_header + ect_header + suffix_headers;
-    } else {
-      mock_write = prefix_headers + user_agent_header + accept_encoding_header +
-                   accept_language_header + ect_header + suffix_headers;
-    }
-
-    net::MockWrite writes[] = {net::MockWrite(mock_write.c_str())};
-    net::StaticSocketDataProvider socket(reads, writes);
-    mock_socket_factory_->AddSocketDataProvider(&socket);
-
-    net::TestDelegate delegate;
-    std::unique_ptr<net::URLRequest> request = context_->CreateRequest(
-        url, net::IDLE, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS);
-    if (request_headers)
-      request->SetExtraRequestHeaders(*request_headers);
-
-    request->Start();
-    base::RunLoop().RunUntilIdle();
-
-    EXPECT_EQ(0, request->status().ToNetError());
-
-    if (!expect_cached) {
-      EXPECT_EQ(response_body_size,
-                request->received_response_content_length());
-      VerifyBrotliPresent(request.get(),
-                          accept_encoding_header_value_includes_brotli,
-                          expect_brotli);
-    }
-    EXPECT_EQ(expect_cached, request->GetTotalSentBytes() == 0);
-    EXPECT_EQ(expect_cached, request->GetTotalReceivedBytes() == 0);
-    EXPECT_EQ(expect_cached, request->was_cached());
-  }
-
-  void VerifyBrotliPresent(net::URLRequest* request,
-                           bool expect_accept_encoding_brotli,
-                           bool expect_content_encoding_brotli) {
-    net::HttpRequestHeaders request_headers_sent;
-    EXPECT_TRUE(request->GetFullRequestHeaders(&request_headers_sent));
-    std::string accept_encoding_value;
-    EXPECT_TRUE(request_headers_sent.GetHeader("Accept-Encoding",
-                                               &accept_encoding_value));
-
-    std::set<std::string> accept_encoding_value_set;
-    net::HttpUtil::ParseAcceptEncoding(accept_encoding_value,
-                                       &accept_encoding_value_set);
-    EXPECT_EQ(expect_accept_encoding_brotli,
-              accept_encoding_value_set.find("br") !=
-                  accept_encoding_value_set.end());
-
-    std::string content_encoding_value;
-    request->GetResponseHeaderByName("Content-Encoding",
-                                     &content_encoding_value);
-    EXPECT_EQ(expect_content_encoding_brotli, content_encoding_value == "br");
-  }
-
   void FetchURLRequestAndVerifyPageIdDirective(base::Optional<uint64_t> page_id,
                                                bool redirect_once) {
     std::string response_headers =
@@ -876,13 +699,10 @@
   net::SSLSocketDataProvider ssl_socket_data_provider_;
 
   std::unique_ptr<net::StaticSocketDataProvider> socket_;
-
-  // Encoded Brotli content read from a file. May be empty.
-  std::string encoded_brotli_buffer_;
 };
 
 TEST_F(DataReductionProxyNetworkDelegateTest, AuthenticationTest) {
-  Init(USE_INSECURE_PROXY, false);
+  Init(USE_INSECURE_PROXY);
   std::unique_ptr<net::URLRequest> fake_request(
       FetchURLRequest(GURL(kTestURL), nullptr, std::string(), 0, 0));
 
@@ -908,7 +728,7 @@
 }
 
 TEST_F(DataReductionProxyNetworkDelegateTest, LoFiTransitions) {
-  Init(USE_INSECURE_PROXY, false);
+  Init(USE_INSECURE_PROXY);
 
   // Enable Lo-Fi.
   bool is_data_reduction_proxy_enabled[] = {false, true};
@@ -1026,7 +846,7 @@
 }
 
 TEST_F(DataReductionProxyNetworkDelegateTest, RequestDataConfigurations) {
-  Init(USE_INSECURE_PROXY, false);
+  Init(USE_INSECURE_PROXY);
   const struct {
     bool lofi_on;
     bool used_data_reduction_proxy;
@@ -1103,7 +923,7 @@
 
 TEST_F(DataReductionProxyNetworkDelegateTest,
        RequestDataHoldbackConfigurations) {
-  Init(USE_INSECURE_PROXY, false);
+  Init(USE_INSECURE_PROXY);
   const struct {
     bool data_reduction_proxy_enabled;
     bool used_direct;
@@ -1161,7 +981,7 @@
 }
 
 TEST_F(DataReductionProxyNetworkDelegateTest, RedirectRequestDataCleared) {
-  Init(USE_INSECURE_PROXY, false);
+  Init(USE_INSECURE_PROXY);
   net::ProxyInfo data_reduction_proxy_info;
   data_reduction_proxy_info.UseProxyServer(
       params()->proxies_for_http().front().proxy_server());
@@ -1230,7 +1050,7 @@
 }
 
 TEST_F(DataReductionProxyNetworkDelegateTest, NetHistograms) {
-  Init(USE_INSECURE_PROXY, false);
+  Init(USE_INSECURE_PROXY);
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitWithFeatures(
       {previews::features::kPreviews,
@@ -1278,7 +1098,7 @@
 }
 
 TEST_F(DataReductionProxyNetworkDelegateTest, NetVideoHistograms) {
-  Init(USE_INSECURE_PROXY, false);
+  Init(USE_INSECURE_PROXY);
 
   base::HistogramTester histogram_tester;
 
@@ -1453,7 +1273,7 @@
 
   for (const auto& test : tests) {
     LOG(INFO) << "NetHistograms: " << test.name;
-    Init(test.proxy_config, false);
+    Init(test.proxy_config);
     base::HistogramTester histogram_tester;
 
     GURL test_url = GURL(kTestURL);
@@ -1509,7 +1329,7 @@
 
 TEST_F(DataReductionProxyNetworkDelegateTest,
        NonServerLoFiResponseDoesNotTriggerInfobar) {
-  Init(USE_INSECURE_PROXY, false);
+  Init(USE_INSECURE_PROXY);
 
   ClearLoFiUIService();
   lofi_decider()->SetIsUsingClientLoFi(false);
@@ -1529,7 +1349,7 @@
 
 TEST_F(DataReductionProxyNetworkDelegateTest,
        ServerLoFiResponseDoesTriggerInfobar) {
-  Init(USE_INSECURE_PROXY, false);
+  Init(USE_INSECURE_PROXY);
 
   ClearLoFiUIService();
   lofi_decider()->SetIsUsingClientLoFi(false);
@@ -1550,7 +1370,7 @@
 
 TEST_F(DataReductionProxyNetworkDelegateTest,
        NonClientLoFiResponseDoesNotTriggerInfobar) {
-  Init(USE_INSECURE_PROXY, false);
+  Init(USE_INSECURE_PROXY);
 
   ClearLoFiUIService();
   lofi_decider()->SetIsUsingClientLoFi(false);
@@ -1568,7 +1388,7 @@
 
 TEST_F(DataReductionProxyNetworkDelegateTest,
        ClientLoFiCompleteResponseDoesNotTriggerInfobar) {
-  Init(USE_INSECURE_PROXY, false);
+  Init(USE_INSECURE_PROXY);
 
   const char* const test_response_headers[] = {
       "HTTP/1.1 200 OK\r\n"
@@ -1603,7 +1423,7 @@
 
 TEST_F(DataReductionProxyNetworkDelegateTest,
        ClientLoFiPartialRangeDoesTriggerInfobar) {
-  Init(USE_INSECURE_PROXY, false);
+  Init(USE_INSECURE_PROXY);
 
   const char* const test_response_headers[] = {
       "HTTP/1.1 206 Partial Content\r\n"
@@ -1637,7 +1457,7 @@
       "Cache-Control: max-age=0\r\n"
       "Vary: accept-encoding\r\n\r\n";
 
-  Init(USE_INSECURE_PROXY, false);
+  Init(USE_INSECURE_PROXY);
   const char kLoFiTransformationTypeHistogram[] =
       "DataReductionProxy.LoFi.TransformationType";
   base::HistogramTester histogram_tester;
@@ -1667,172 +1487,9 @@
                                      LITE_PAGE, 1);
 }
 
-// Test that Brotli is not added to the accept-encoding header when it is
-// disabled globally.
-TEST_F(DataReductionProxyNetworkDelegateTest,
-       BrotliAdvertisement_BrotliDisabled) {
-  Init(USE_SECURE_PROXY, false /* enable_brotli_globally */);
-
-  ReadBrotliFile();
-
-  std::string response_headers =
-      "HTTP/1.1 200 OK\r\n"
-      "Content-Length: 140\r\n"
-      "Via: 1.1 Chrome-Compression-Proxy\r\n"
-      "Chrome-Proxy: ofcl=200\r\n"
-      "Cache-Control: max-age=1200\r\n"
-      "Vary: accept-encoding\r\n";
-  response_headers += "\r\n";
-
-  // Use secure sockets when fetching the request since Brotli is only enabled
-  // for secure connections.
-  FetchURLRequestAndVerifyBrotli(nullptr, response_headers, false, false);
-}
-
-// Test that Brotli is not added to the accept-encoding header when
-// kDataReductionProxyBrotliHoldback feature is enabled.
-TEST_F(DataReductionProxyNetworkDelegateTest,
-       BrotliAdvertisement_BrotliHoldbackEnabled) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      data_reduction_proxy::features::kDataReductionProxyBrotliHoldback);
-
-  Init(USE_SECURE_PROXY, true /* enable_brotli_globally */);
-
-  ReadBrotliFile();
-
-  std::string response_headers =
-      "HTTP/1.1 200 OK\r\n"
-      "Content-Length: 140\r\n"
-      "Via: 1.1 Chrome-Compression-Proxy\r\n"
-      "Chrome-Proxy: ofcl=200\r\n"
-      "Cache-Control: max-age=1200\r\n"
-      "Vary: accept-encoding\r\n";
-  response_headers += "\r\n";
-
-  // Use secure sockets when fetching the request since Brotli is only enabled
-  // for secure connections.
-  FetchURLRequestAndVerifyBrotli(nullptr, response_headers, false, false);
-}
-
-// Test that Brotli is not added to the accept-encoding header when the request
-// is fetched from an insecure proxy.
-TEST_F(DataReductionProxyNetworkDelegateTest,
-       BrotliAdvertisementInsecureProxy) {
-  Init(USE_INSECURE_PROXY, true /* enable_brotli_globally */);
-  std::string response_headers =
-      "HTTP/1.1 200 OK\r\n"
-      "Content-Length: 140\r\n"
-      "Via: 1.1 Chrome-Compression-Proxy\r\n"
-      "Chrome-Proxy: ofcl=200\r\n"
-      "Cache-Control: max-age=1200\r\n"
-      "Vary: accept-encoding\r\n";
-  response_headers += "\r\n";
-
-  // Use secure sockets when fetching the request since Brotli is only enabled
-  // for secure connections.
-  std::unique_ptr<net::URLRequest> request(
-      FetchURLRequest(GURL(kTestURL), nullptr, response_headers, 140, 0));
-  EXPECT_EQ(140, request->received_response_content_length());
-  EXPECT_NE(0, request->GetTotalSentBytes());
-  EXPECT_NE(0, request->GetTotalReceivedBytes());
-  EXPECT_FALSE(request->was_cached());
-  // Brotli should be added to Accept Encoding header only if secure proxy is in
-  VerifyBrotliPresent(request.get(), false, false);
-}
-
-// Test that Brotli is not added to the accept-encoding header when it is
-// disabled via data reduction proxy field trial.
-TEST_F(DataReductionProxyNetworkDelegateTest,
-       BrotliAdvertisementDisabledViaFieldTrial) {
-  Init(USE_SECURE_PROXY, true /* enable_brotli_globally */);
-
-  base::FieldTrialList field_trial_list(nullptr);
-  ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
-      "DataReductionProxyBrotliAcceptEncoding", "Disabled"));
-
-  std::string response_headers =
-      "HTTP/1.1 200 OK\r\n"
-      "Content-Length: 140\r\n"
-      "Via: 1.1 Chrome-Compression-Proxy\r\n"
-      "Chrome-Proxy: ofcl=200\r\n"
-      "Cache-Control: max-age=1200\r\n"
-      "Vary: accept-encoding\r\n";
-  response_headers += "\r\n";
-
-  FetchURLRequestAndVerifyBrotli(nullptr, response_headers, false, false);
-  FetchURLRequestAndVerifyBrotli(nullptr, response_headers, true, false);
-}
-
-// Test that Brotli is correctly added to the accept-encoding header when it is
-// enabled globally.
-TEST_F(DataReductionProxyNetworkDelegateTest, BrotliAdvertisement) {
-  Init(USE_SECURE_PROXY, true /* enable_brotli_globally */);
-
-  std::string response_headers =
-      "HTTP/1.1 200 OK\r\n"
-      "Via: 1.1 Chrome-Compression-Proxy\r\n"
-      "chrome-proxy: ofcl=200\r\n"
-      "Cache-Control: max-age=1200\r\n"
-      "Content-Encoding: br\r\n"
-      "Vary: accept-encoding\r\n";
-  response_headers += "\r\n";
-
-  FetchURLRequestAndVerifyBrotli(nullptr, response_headers, false, true);
-  FetchURLRequestAndVerifyBrotli(nullptr, response_headers, true, true);
-}
-
-// Test that Brotli is not added a second time to the Accept-Encoding header
-// when it is enabled globally but already present in the pre-existing header.
-TEST_F(DataReductionProxyNetworkDelegateTest,
-       BrotliAdvertisementAcceptEncodingIncludesBr) {
-  Init(USE_SECURE_PROXY, true /* enable_brotli_globally */);
-
-  net::HttpRequestHeaders request_headers;
-  request_headers.SetHeader("Accept-Encoding", "gzip, deflate, br");
-
-  std::string response_headers =
-      "HTTP/1.1 200 OK\r\n"
-      "Via: 1.1 Chrome-Compression-Proxy\r\n"
-      "Chrome-Proxy: ofcl=200\r\n"
-      "Cache-Control: max-age=1200\r\n"
-      "Content-Encoding: br\r\n"
-      "Vary: accept-encoding\r\n";
-  response_headers += "\r\n";
-
-  FetchURLRequestAndVerifyBrotli(&request_headers, response_headers, false,
-                                 true);
-  FetchURLRequestAndVerifyBrotli(&request_headers, response_headers, true,
-                                 true);
-}
-
-// Test that Brotli is correctly added to the Accept-Encoding header when it is
-// enabled globally and the pre-existing header is empty.
-TEST_F(DataReductionProxyNetworkDelegateTest,
-       BrotliAdvertisementAcceptEncodingEmpty) {
-  Init(USE_SECURE_PROXY, true /* enable_brotli_globally */);
-
-  net::HttpRequestHeaders request_headers;
-  request_headers.SetHeader("Accept-Encoding", "");
-
-  std::string response_headers =
-      "HTTP/1.1 200 OK\r\n"
-      "Via: 1.1 Chrome-Compression-Proxy\r\n"
-      "Chrome-Proxy: ofcl=200\r\n"
-      "Cache-Control: max-age=1200\r\n"
-      "Content-Encoding: br\r\n"
-      "Vary: accept-encoding\r\n";
-  response_headers += "\r\n";
-
-  FetchURLRequestAndVerifyBrotli(&request_headers, response_headers, false,
-                                 true);
-  FetchURLRequestAndVerifyBrotli(&request_headers, response_headers, true,
-                                 true);
-}
 
 TEST_F(DataReductionProxyNetworkDelegateTest, IncrementingMainFramePageId) {
-  // This is unaffacted by brotil and insecure proxy.
-  Init(USE_SECURE_PROXY, false /* enable_brotli_globally */);
+  Init(USE_SECURE_PROXY);
 
   io_data()->request_options()->SetSecureSession("new-session");
   uint64_t page_id = io_data()->request_options()->GeneratePageId();
@@ -1845,8 +1502,7 @@
 }
 
 TEST_F(DataReductionProxyNetworkDelegateTest, ResetSessionResetsId) {
-  // This is unaffacted by brotil and insecure proxy.
-  Init(USE_SECURE_PROXY, false /* enable_brotli_globally */);
+  Init(USE_SECURE_PROXY);
 
   io_data()->request_options()->SetSecureSession("new-session");
   uint64_t page_id = io_data()->request_options()->GeneratePageId();
@@ -1860,8 +1516,7 @@
 }
 
 TEST_F(DataReductionProxyNetworkDelegateTest, SubResourceNoPageId) {
-  // This is unaffacted by brotil and insecure proxy.
-  Init(USE_SECURE_PROXY, false /* enable_brotli_globally */);
+  Init(USE_SECURE_PROXY);
   io_data()->request_options()->SetSecureSession("new-session");
   FetchURLRequestAndVerifyPageIdDirective(base::Optional<uint64_t>(), false);
 }
@@ -1870,8 +1525,7 @@
   // The test manually controls the fetch of warmup URL and the response.
   DisableWarmupURLFetchCallback();
 
-  // This is unaffacted by brotil and insecure proxy.
-  Init(USE_SECURE_PROXY, false /* enable_brotli_globally */);
+  Init(USE_SECURE_PROXY);
 
   io_data()->request_options()->SetSecureSession("new-session");
   uint64_t page_id = io_data()->request_options()->GeneratePageId();
@@ -1884,8 +1538,7 @@
   // This test calls directly into network delegate as it is difficult to mock
   // state changing in between redirects within an URLRequest's lifetime.
 
-  // This is unaffacted by brotil and insecure proxy.
-  Init(USE_INSECURE_PROXY, false /* enable_brotli_globally */);
+  Init(USE_INSECURE_PROXY);
   net::ProxyInfo data_reduction_proxy_info;
   data_reduction_proxy_info.UseProxyServer(
       params()->proxies_for_http().front().proxy_server());
@@ -1949,7 +1602,7 @@
 // headers when it is enabled using field trial. The server is varying on the
 // effective connection type (ECT).
 TEST_F(DataReductionProxyNetworkDelegateTest, ECTHeaderEnabledWithVary) {
-  Init(USE_SECURE_PROXY, false /* enable_brotli_globally */);
+  Init(USE_SECURE_PROXY);
 
   std::string response_headers =
       "HTTP/1.1 200 OK\r\n"
@@ -1991,7 +1644,7 @@
 // headers when it is enabled using field trial. The server is not varying on
 // the effective connection type (ECT).
 TEST_F(DataReductionProxyNetworkDelegateTest, ECTHeaderEnabledWithoutVary) {
-  Init(USE_SECURE_PROXY, false /* enable_brotli_globally */);
+  Init(USE_SECURE_PROXY);
 
   std::string response_headers =
       "HTTP/1.1 200 OK\r\n"
@@ -2226,7 +1879,7 @@
 }
 
 TEST_F(DataReductionProxyNetworkDelegateTest, TestAcceptTransformHistogram) {
-  Init(USE_INSECURE_PROXY, false);
+  Init(USE_INSECURE_PROXY);
   base::HistogramTester histogram_tester;
 
   const std::string regular_response_headers =
@@ -2361,7 +2014,7 @@
   scoped_feature_list.InitAndEnableFeature(
       data_reduction_proxy::features::
           kDataSaverSiteBreakdownUsingPageLoadMetrics);
-  Init(USE_INSECURE_PROXY, false);
+  Init(USE_INSECURE_PROXY);
   EnableDataUsageReporting();
   auto test_resource_type_provider =
       std::make_unique<TestResourceTypeProvider>();
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc
index 71dccd1..1834dee 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc
@@ -41,12 +41,6 @@
     "DataSaverSiteBreakdownUsingPageLoadMetrics",
     base::FEATURE_ENABLED_BY_DEFAULT};
 
-// If enabled, "br" is not added to the accept-encoding header. This effectively
-// disables the use of Brotli on the connection from Chrome to secure
-// HTTPS data saver proxies.
-const base::Feature kDataReductionProxyBrotliHoldback{
-    "DataReductionProxyBrotliHoldback", base::FEATURE_DISABLED_BY_DEFAULT};
-
 // Enables data reduction proxy when network service is enabled.
 const base::Feature kDataReductionProxyEnabledWithNetworkService{
     "DataReductionProxyEnabledWithNetworkService",
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h
index 0c70c4a..3347846 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h
@@ -15,7 +15,6 @@
 extern const base::Feature kDataReductionProxyRobustConnection;
 extern const base::Feature kDogfood;
 extern const base::Feature kDataSaverSiteBreakdownUsingPageLoadMetrics;
-extern const base::Feature kDataReductionProxyBrotliHoldback;
 extern const base::Feature kDataReductionProxyEnabledWithNetworkService;
 extern const base::Feature kDataSaverUseOnDeviceSafeBrowsing;
 
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
index d312cb66..b3c57b4 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
@@ -246,16 +246,6 @@
   return kQuicFieldTrial;
 }
 
-bool IsBrotliAcceptEncodingEnabled() {
-  // Brotli encoding is enabled by default since the data reduction proxy server
-  // controls when to serve Brotli encoded content. It can be disabled in
-  // Chromium only if Chromium belongs to a field trial group whose name starts
-  // with "Disabled".
-  return !base::StartsWith(base::FieldTrialList::FindFullName(
-                               "DataReductionProxyBrotliAcceptEncoding"),
-                           kDisabled, base::CompareCase::SENSITIVE);
-}
-
 GURL GetConfigServiceURL() {
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   std::string url;
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
index 43bec956..ac2e07eb 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
@@ -86,9 +86,6 @@
 
 const char* GetQuicFieldTrialName();
 
-// Returns true if Brotli should be added to the accept-encoding header.
-bool IsBrotliAcceptEncodingEnabled();
-
 // If the Data Reduction Proxy is used for a page load, the URL for the
 // Data Reduction Proxy Pageload Metrics service.
 GURL GetPingbackURL();
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc
index dc9c6ffc3..8bba340 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc
@@ -112,46 +112,6 @@
   EXPECT_EQ(1U, second_info->proxy_index);
 }
 
-TEST_F(DataReductionProxyParamsTest, IsBrotliAcceptEncodingEnabled) {
-  const struct {
-    std::string test_case;
-    std::string trial_group_value;
-    bool expected;
-  } tests[] = {
-      {
-          "Nothing set", "", true,
-      },
-      {
-          "Enabled in experiment", "Enabled", true,
-      },
-      {
-          "Alternate enabled in experiment", "Enabled_Other", true,
-      },
-      {
-          "Control in experiment", "Control", true,
-      },
-      {
-          "Disabled in experiment", "Disabled", false,
-      },
-      {
-          "Disabled in experiment", "Disabled_Other", false,
-      },
-      {
-          "disabled in experiment lower case", "disabled", true,
-      },
-  };
-
-  for (const auto& test : tests) {
-    base::FieldTrialList field_trial_list(nullptr);
-    if (!test.trial_group_value.empty()) {
-      ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
-          "DataReductionProxyBrotliAcceptEncoding", test.trial_group_value));
-    }
-    EXPECT_EQ(test.expected, params::IsBrotliAcceptEncodingEnabled())
-        << test.test_case;
-  }
-}
-
 TEST_F(DataReductionProxyParamsTest, AreServerExperimentsEnabled) {
   const struct {
     std::string test_case;
diff --git a/components/gwp_asan/client/sampling_allocator_shims.cc b/components/gwp_asan/client/sampling_allocator_shims.cc
index cc291ad..26cbc4bd 100644
--- a/components/gwp_asan/client/sampling_allocator_shims.cc
+++ b/components/gwp_asan/client/sampling_allocator_shims.cc
@@ -4,9 +4,6 @@
 
 #include "components/gwp_asan/client/sampling_allocator_shims.h"
 
-#include <limits>
-#include <random>
-
 #include "base/allocator/allocator_shim.h"
 #include "base/allocator/buildflags.h"
 #include "base/compiler_specific.h"
@@ -36,8 +33,7 @@
 using base::allocator::AllocatorDispatch;
 
 // Class that encapsulates the current sampling state. Sampling is performed
-// using a poisson distribution and the sampling counter is stored in thread-
-// local storage.
+// using a counter stored in thread-local storage.
 class SamplingState {
  public:
   constexpr SamplingState() {}
@@ -49,30 +45,41 @@
     sampling_frequency_ = sampling_frequency;
   }
 
-  // Count down the number of samples remaining until it reaches zero, and then
-  // get new sample count. Returns true when an allocation should be sampled.
+  // Return true if this allocation should be sampled.
   bool Sample() {
+    // For a new thread the initial TLS value will be zero, we do not want to
+    // sample on zero as it will always sample the first allocation on thread
+    // creation and heavily bias allocations towards that particular call site.
+    //
+    // Instead, use zero to mean 'get a new counter value' and one to mean
+    // that this allocation should be sampled.
     size_t samples_left = TLSGetValue(tls_key_);
-    if (UNLIKELY(!samples_left)) {
-      TLSSetValue(tls_key_, NextSample());
-      return true;
-    }
+    if (UNLIKELY(!samples_left))
+      samples_left = NextSample();
 
     TLSSetValue(tls_key_, samples_left - 1);
-    return false;
+    return (samples_left == 1);
   }
 
  private:
-  size_t NextSample() const {
-    // Sample from a poisson distribution with a mean of the sampling frequency.
-    std::poisson_distribution<size_t> distribution(sampling_frequency_);
-    base::RandomBitGenerator generator;
-    // Clamp return values to [1, SIZE_MAX].
-    return std::max<size_t>(1, distribution(generator));
+  // Sample a single allocations in every chunk of |sampling_frequency_|
+  // allocations.
+  //
+  // TODO(https://crbug.com/919207): Replace with std::geometric_distribution
+  // once the LLVM floating point codegen issue in the linked bug is fixed.
+  size_t NextSample() {
+    size_t random = base::RandInt(1, sampling_frequency_ + 1);
+    size_t next_sample = increment_ + random;
+    increment_ = sampling_frequency_ + 1 - random;
+    return next_sample;
   }
 
   TLSKey tls_key_ = 0;
-  size_t sampling_frequency_ = std::numeric_limits<size_t>::max();
+  size_t sampling_frequency_ = 0;
+
+  // Stores the number of allocations we need to skip to reach the end of the
+  // current chunk of |sampling_frequency_| allocations.
+  size_t increment_ = 0;
 };
 
 // By being implemented as a global with inline method definitions, method calls
diff --git a/components/gwp_asan/client/sampling_allocator_shims_unittest.cc b/components/gwp_asan/client/sampling_allocator_shims_unittest.cc
index 4353209..576cec3 100644
--- a/components/gwp_asan/client/sampling_allocator_shims_unittest.cc
+++ b/components/gwp_asan/client/sampling_allocator_shims_unittest.cc
@@ -49,9 +49,8 @@
 
 constexpr size_t kSamplingFrequency = 10;
 
-// The likelihood of iterating this many times and not getting a sampled
-// allocation is less than one in a trillion [1 / exp(32)].
-constexpr size_t kLoopIterations = kSamplingFrequency * 32;
+// Number of loop iterations required to definitely hit a sampled allocation.
+constexpr size_t kLoopIterations = kSamplingFrequency * 4;
 
 constexpr int kSuccess = 0;
 constexpr int kFailure = 1;
diff --git a/components/leveldb_proto/leveldb_database.cc b/components/leveldb_proto/leveldb_database.cc
index 2bbd0040..b5ab97f 100644
--- a/components/leveldb_proto/leveldb_database.cc
+++ b/components/leveldb_proto/leveldb_database.cc
@@ -8,11 +8,13 @@
 #include <string>
 #include <vector>
 
+#include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/metrics/histogram.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
 #include "base/threading/thread_checker.h"
 #include "third_party/leveldatabase/env_chromium.h"
 #include "third_party/leveldatabase/leveldb_chrome.h"
@@ -33,6 +35,10 @@
 
 }  // namespace
 
+bool PrefixStopCallback(const std::string& prefix, const std::string& key) {
+  return base::StartsWith(key, prefix, base::CompareCase::SENSITIVE);
+}
+
 LevelDB::LevelDB(const char* client_name)
     : open_histogram_(nullptr), destroy_histogram_(nullptr) {
   // Used in lieu of UMA_HISTOGRAM_ENUMERATION because the histogram name is
@@ -222,14 +228,26 @@
     std::map<std::string, std::string>* keys_entries,
     const leveldb::ReadOptions& options,
     const std::string& target_prefix) {
+  return LoadKeysAndEntriesWhile(
+      filter, keys_entries, options, target_prefix,
+      base::BindRepeating(&PrefixStopCallback, target_prefix));
+}
+
+bool LevelDB::LoadKeysAndEntriesWhile(
+    const KeyFilter& filter,
+    std::map<std::string, std::string>* keys_entries,
+    const leveldb::ReadOptions& options,
+    const std::string& start_key,
+    const KeyFilter& while_callback) {
   DFAKE_SCOPED_LOCK(thread_checker_);
   if (!db_)
     return false;
 
   std::unique_ptr<leveldb::Iterator> db_iterator(db_->NewIterator(options));
-  leveldb::Slice target(target_prefix);
-  for (db_iterator->Seek(target);
-       db_iterator->Valid() && db_iterator->key().starts_with(target);
+  leveldb::Slice start(start_key);
+  for (db_iterator->Seek(start);
+       db_iterator->Valid() &&
+       while_callback.Run(db_iterator->key().ToString());
        db_iterator->Next()) {
     leveldb::Slice key_slice = db_iterator->key();
     std::string key_slice_str(key_slice.data(), key_slice.size());
diff --git a/components/leveldb_proto/leveldb_database.h b/components/leveldb_proto/leveldb_database.h
index f5bfc60..7d9deeec 100644
--- a/components/leveldb_proto/leveldb_database.h
+++ b/components/leveldb_proto/leveldb_database.h
@@ -79,6 +79,15 @@
       const leveldb::ReadOptions& options,
       const std::string& target_prefix);
 
+  // Retrieves keys and values, starting at key |start_key|, includes keys when
+  // |filter| return true and stops when |while_callback| returns false.
+  virtual bool LoadKeysAndEntriesWhile(
+      const KeyFilter& filter,
+      std::map<std::string, std::string>* keys_entries,
+      const leveldb::ReadOptions& options,
+      const std::string& start_key,
+      const KeyFilter& while_callback);
+
   virtual bool LoadKeys(std::vector<std::string>* keys);
   virtual bool LoadKeys(const std::string& target_prefix,
                         std::vector<std::string>* keys);
diff --git a/components/leveldb_proto/proto_database.h b/components/leveldb_proto/proto_database.h
index b6675b9..7fda2d7b 100644
--- a/components/leveldb_proto/proto_database.h
+++ b/components/leveldb_proto/proto_database.h
@@ -141,6 +141,15 @@
       const leveldb::ReadOptions& options,
       const std::string& target_prefix,
       typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) = 0;
+  // Asynchronously loads entries and their keys for keys in range [start, end]
+  // (both inclusive) and invokes |callback| when complete.
+  // Range is defined as |start| <= returned keys <= |end|.
+  // When |start| = 'bar' and |end| = 'foo' then the keys within brackets are
+  // returned: baa, [bar, bara, barb, foa, foo], fooa, fooz, fop.
+  virtual void LoadKeysAndEntriesInRange(
+      const std::string& start,
+      const std::string& end,
+      typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) = 0;
 
   // Asynchronously loads all keys from the database and invokes |callback| with
   // those keys when complete.
diff --git a/components/leveldb_proto/proto_database_wrapper.h b/components/leveldb_proto/proto_database_wrapper.h
index f99f7071..523eace 100644
--- a/components/leveldb_proto/proto_database_wrapper.h
+++ b/components/leveldb_proto/proto_database_wrapper.h
@@ -104,6 +104,11 @@
       const std::string& target_prefix,
       typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback)
       override;
+  void LoadKeysAndEntriesInRange(
+      const std::string& start,
+      const std::string& end,
+      typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback)
+      override;
 
   void LoadKeys(Callbacks::LoadKeysCallback callback) override;
   void LoadKeys(const std::string& target_prefix,
@@ -534,6 +539,21 @@
 }
 
 template <typename T>
+void ProtoDatabaseWrapper<T>::LoadKeysAndEntriesInRange(
+    const std::string& start,
+    const std::string& end,
+    typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
+  if (!db_) {
+    RunCallbackOnCallingSequence(
+        base::BindOnce(std::move(callback), false,
+                       std::make_unique<std::map<std::string, T>>()));
+    return;
+  }
+
+  db_->LoadKeysAndEntriesInRange(start, end, std::move(callback));
+}
+
+template <typename T>
 void ProtoDatabaseWrapper<T>::LoadKeys(Callbacks::LoadKeysCallback callback) {
   if (!db_) {
     RunCallbackOnCallingSequence(
diff --git a/components/leveldb_proto/proto_leveldb_wrapper.h b/components/leveldb_proto/proto_leveldb_wrapper.h
index 444451d..f4d2c493 100644
--- a/components/leveldb_proto/proto_leveldb_wrapper.h
+++ b/components/leveldb_proto/proto_leveldb_wrapper.h
@@ -13,6 +13,7 @@
 #include "base/callback.h"
 #include "base/memory/ptr_util.h"
 #include "base/sequenced_task_runner.h"
+#include "base/strings/string_util.h"
 #include "base/task_runner_util.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/threading/thread_checker.h"
@@ -98,6 +99,20 @@
       const std::string& target_prefix,
       typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback);
 
+  template <typename T>
+  void LoadKeysAndEntriesWhile(
+      const LevelDB::KeyFilter& while_callback,
+      const LevelDB::KeyFilter& filter,
+      const leveldb::ReadOptions& options,
+      const std::string& target_prefix,
+      typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback);
+
+  template <typename T>
+  void LoadKeysAndEntriesInRange(
+      const std::string& start,
+      const std::string& end,
+      typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback);
+
   void LoadKeys(Callbacks::LoadKeysCallback callback);
   void LoadKeys(const std::string& target_prefix,
                 Callbacks::LoadKeysCallback callback);
@@ -212,6 +227,7 @@
 
 template <typename T>
 void LoadKeysAndEntriesFromTaskRunner(LevelDB* database,
+                                      const LevelDB::KeyFilter& while_callback,
                                       const LevelDB::KeyFilter& filter,
                                       const leveldb::ReadOptions& options,
                                       const std::string& target_prefix,
@@ -223,8 +239,8 @@
   keys_entries->clear();
 
   std::map<std::string, std::string> loaded_entries;
-  *success = database->LoadKeysAndEntriesWithFilter(filter, &loaded_entries,
-                                                    options, target_prefix);
+  *success = database->LoadKeysAndEntriesWhile(filter, &loaded_entries, options,
+                                               target_prefix, while_callback);
 
   for (const auto& pair : loaded_entries) {
     T entry;
@@ -379,6 +395,36 @@
     const leveldb::ReadOptions& options,
     const std::string& target_prefix,
     typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
+  LoadKeysAndEntriesWhile<T>(
+      base::BindRepeating(
+          [](const std::string& prefix, const std::string& key) {
+            return base::StartsWith(key, prefix, base::CompareCase::SENSITIVE);
+          },
+          target_prefix),
+      key_filter, options, target_prefix, std::move(callback));
+}
+
+template <typename T>
+void ProtoLevelDBWrapper::LoadKeysAndEntriesInRange(
+    const std::string& start,
+    const std::string& end,
+    typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
+  LoadKeysAndEntriesWhile<T>(
+      base::BindRepeating(
+          [](const std::string& range_end, const std::string& key) {
+            return key.compare(range_end) <= 0;
+          },
+          end),
+      LevelDB::KeyFilter(), leveldb::ReadOptions(), start, std::move(callback));
+}
+
+template <typename T>
+void ProtoLevelDBWrapper::LoadKeysAndEntriesWhile(
+    const LevelDB::KeyFilter& while_callback,
+    const LevelDB::KeyFilter& filter,
+    const leveldb::ReadOptions& options,
+    const std::string& target_prefix,
+    typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   bool* success = new bool(false);
   auto keys_entries = std::make_unique<std::map<std::string, T>>();
@@ -388,8 +434,8 @@
   task_runner_->PostTaskAndReply(
       FROM_HERE,
       base::BindOnce(LoadKeysAndEntriesFromTaskRunner<T>, base::Unretained(db_),
-                     key_filter, options, target_prefix, metrics_id_, success,
-                     keys_entries_ptr),
+                     while_callback, filter, options, target_prefix,
+                     metrics_id_, success, keys_entries_ptr),
       base::BindOnce(RunLoadKeysAndEntriesCallback<T>, std::move(callback),
                      base::Owned(success), std::move(keys_entries)));
 }
diff --git a/components/leveldb_proto/shared_proto_database_client.h b/components/leveldb_proto/shared_proto_database_client.h
index fd11d224..6d6e294e 100644
--- a/components/leveldb_proto/shared_proto_database_client.h
+++ b/components/leveldb_proto/shared_proto_database_client.h
@@ -118,6 +118,11 @@
       const std::string& target_prefix,
       typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback)
       override;
+  void LoadKeysAndEntriesInRange(
+      const std::string& start,
+      const std::string& end,
+      typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback)
+      override;
 
   void GetEntry(const std::string& key,
                 typename Callbacks::Internal<T>::GetCallback callback) override;
@@ -328,6 +333,19 @@
 }
 
 template <typename T>
+void SharedProtoDatabaseClient<T>::LoadKeysAndEntriesInRange(
+    const std::string& start,
+    const std::string& end,
+    typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  unique_db_->LoadKeysAndEntriesInRange(
+      prefix_ + start, prefix_ + end,
+      base::BindOnce(
+          &SharedProtoDatabaseClient<T>::StripPrefixLoadKeysAndEntriesCallback,
+          std::move(callback), prefix_));
+}
+
+template <typename T>
 void SharedProtoDatabaseClient<T>::GetEntry(
     const std::string& key,
     typename Callbacks::Internal<T>::GetCallback callback) {
diff --git a/components/leveldb_proto/shared_proto_database_client_unittest.cc b/components/leveldb_proto/shared_proto_database_client_unittest.cc
index 267f70e..35e9516b 100644
--- a/components/leveldb_proto/shared_proto_database_client_unittest.cc
+++ b/components/leveldb_proto/shared_proto_database_client_unittest.cc
@@ -189,6 +189,27 @@
     load_entries_loop.Run();
   }
 
+  void LoadKeysAndEntriesInRange(
+      SharedProtoDatabaseClient<TestProto>* client,
+      const std::string& start,
+      const std::string& end,
+      bool expect_success,
+      std::unique_ptr<std::map<std::string, TestProto>>* entries) {
+    base::RunLoop load_entries_in_range_loop;
+    client->LoadKeysAndEntriesInRange(
+        start, end,
+        base::BindOnce(
+            [](std::unique_ptr<std::map<std::string, TestProto>>* entries_ptr,
+               base::OnceClosure signal, bool expect_success, bool success,
+               std::unique_ptr<std::map<std::string, TestProto>> entries) {
+              ASSERT_EQ(success, expect_success);
+              *entries_ptr = std::move(entries);
+              std::move(signal).Run();
+            },
+            entries, load_entries_in_range_loop.QuitClosure(), expect_success));
+    load_entries_in_range_loop.Run();
+  }
+
   void LoadKeys(SharedProtoDatabaseClient<TestProto>* client,
                 bool expect_success,
                 std::unique_ptr<std::vector<std::string>>* keys) {
@@ -428,6 +449,44 @@
                               kDefaultTypePrefix));
 }
 
+TEST_F(SharedProtoDatabaseClientTest, LoadKeysAndEntriesInRange) {
+  auto status = Enums::InitStatus::kError;
+  auto client_a =
+      GetClientAndWait<TestProto>(kDefaultNamespace, kDefaultTypePrefix,
+                                  true /* create_if_missing */, &status);
+  ASSERT_EQ(status, Enums::InitStatus::kOK);
+  auto client_b =
+      GetClientAndWait<TestProto>(kDefaultNamespace2, kDefaultTypePrefix,
+                                  true /* create_if_missing */, &status);
+  ASSERT_EQ(status, Enums::InitStatus::kOK);
+
+  std::vector<std::string> key_list_a = {"entry0", "entry1",           "entry2",
+                                         "entry3", "entry3notinrange", "entry4",
+                                         "entry5"};
+  UpdateEntries(client_a.get(), key_list_a, leveldb_proto::KeyVector(), true);
+  std::vector<std::string> key_list_b = {"entry2", "entry3", "entry4"};
+  UpdateEntries(client_b.get(), key_list_b, leveldb_proto::KeyVector(), true);
+
+  std::unique_ptr<std::map<std::string, TestProto>> keys_and_entries_a;
+  LoadKeysAndEntriesInRange(client_a.get(), "entry1", "entry3", true,
+                            &keys_and_entries_a);
+
+  std::unique_ptr<std::map<std::string, TestProto>> keys_and_entries_b;
+  LoadKeysAndEntriesInRange(client_b.get(), "entry0", "entry1", true,
+                            &keys_and_entries_b);
+
+  std::vector<TestProto> entries;
+
+  for (auto& pair : *keys_and_entries_a) {
+    entries.push_back(pair.second);
+  }
+
+  ASSERT_EQ(keys_and_entries_a->size(), 3U);
+  ASSERT_EQ(keys_and_entries_b->size(), 0U);
+  ASSERT_TRUE(ContainsEntries({"entry1", "entry2", "entry3"}, entries,
+                              kDefaultNamespace, kDefaultTypePrefix));
+}
+
 TEST_F(SharedProtoDatabaseClientTest, LoadKeys) {
   auto status = Enums::InitStatus::kError;
   auto client_a =
diff --git a/components/leveldb_proto/unique_proto_database.h b/components/leveldb_proto/unique_proto_database.h
index 85c0b09..8720b302 100644
--- a/components/leveldb_proto/unique_proto_database.h
+++ b/components/leveldb_proto/unique_proto_database.h
@@ -86,6 +86,11 @@
       const std::string& target_prefix,
       typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback)
       override;
+  void LoadKeysAndEntriesInRange(
+      const std::string& start,
+      const std::string& end,
+      typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback)
+      override;
 
   void LoadKeys(Callbacks::LoadKeysCallback callback) override;
   void LoadKeys(const std::string& target_prefix,
@@ -263,6 +268,15 @@
 }
 
 template <typename T>
+void UniqueProtoDatabase<T>::LoadKeysAndEntriesInRange(
+    const std::string& start,
+    const std::string& end,
+    typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
+  db_wrapper_->template LoadKeysAndEntriesInRange<T>(start, end,
+                                                     std::move(callback));
+}
+
+template <typename T>
 void UniqueProtoDatabase<T>::LoadKeys(Callbacks::LoadKeysCallback callback) {
   db_wrapper_->LoadKeys(std::move(callback));
 }
diff --git a/components/leveldb_proto/unique_proto_database_unittest.cc b/components/leveldb_proto/unique_proto_database_unittest.cc
index 7c755f1e..877ee5a 100644
--- a/components/leveldb_proto/unique_proto_database_unittest.cc
+++ b/components/leveldb_proto/unique_proto_database_unittest.cc
@@ -80,6 +80,13 @@
                     std::map<std::string, std::string>*,
                     const leveldb::ReadOptions&,
                     const std::string&));
+  MOCK_METHOD5(LoadKeysAndEntriesWhile,
+               bool(const KeyFilter&,
+                    std::map<std::string, std::string>*,
+                    const leveldb::ReadOptions&,
+                    const std::string&,
+                    const KeyFilter&));
+
   MOCK_METHOD4(Get,
                bool(const std::string&, bool*, std::string*, leveldb::Status*));
   MOCK_METHOD0(Destroy, leveldb::Status());
@@ -171,6 +178,27 @@
   return model;
 }
 
+EntryMap GetRangeTestModel() {
+  EntryMap model;
+
+  model["a"].set_id("a");
+  model["a"].set_data("entry_a");
+
+  model["b"].set_id("b");
+  model["b"].set_data("entry_b");
+
+  model["c"].set_id("c");
+  model["c"].set_data("entry_c");
+
+  model["d"].set_id("d");
+  model["d"].set_data("entry_d");
+
+  model["e"].set_id("e");
+  model["e"].set_data("entry_e");
+
+  return model;
+}
+
 }  // namespace
 
 void ExpectEntryPointersEquals(EntryMap expected,
@@ -336,7 +364,7 @@
                         base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
                                        base::Unretained(&caller)));
 
-  EXPECT_CALL(*mock_db, LoadKeysAndEntriesWithFilter(_, _, _, _))
+  EXPECT_CALL(*mock_db, LoadKeysAndEntriesWhile(_, _, _, _, _))
       .WillOnce(AppendLoadKeysAndEntries(model));
   EXPECT_CALL(caller, LoadKeysAndEntriesCallback1(true, _))
       .WillOnce(VerifyLoadKeysAndEntries(testing::ByRef(model)));
@@ -367,6 +395,88 @@
   base::RunLoop().RunUntilIdle();
 }
 
+TEST_F(UniqueProtoDatabaseTest, TestDBLoadInRangeSuccess) {
+  ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
+  std::unique_ptr<LevelDB> db(new LevelDB(kTestLevelDBClientName));
+  MockDatabaseCaller caller;
+  EntryMap model = GetRangeTestModel();
+  EntryMap expected;
+  expected["b"] = model["b"];
+  expected["c"] = model["c"];
+  expected["d"] = model["d"];
+
+  EXPECT_CALL(caller, InitStatusCallback(_));
+  db_->InitWithDatabase(db.get(), temp_dir.GetPath(), CreateSimpleOptions(),
+                        base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
+                                       base::Unretained(&caller)));
+
+  auto save_entries =
+      std::make_unique<ProtoDatabase<TestProto>::KeyEntryVector>();
+  std::map<std::string, TestProto> load_keys_entries;
+  std::unique_ptr<KeyVector> remove_keys(new KeyVector());
+
+  for (const auto& pair : model)
+    save_entries->push_back(std::make_pair(pair.second.id(), pair.second));
+
+  leveldb::Status status;
+  EXPECT_CALL(caller, SaveCallback(true));
+  db_->UpdateEntries(std::move(save_entries), std::move(remove_keys),
+                     base::BindOnce(&MockDatabaseCaller::SaveCallback,
+                                    base::Unretained(&caller)));
+
+  EXPECT_CALL(caller, LoadKeysAndEntriesCallback1(true, _))
+      .WillOnce(VerifyLoadKeysAndEntries(testing::ByRef(expected)));
+  db_->LoadKeysAndEntriesInRange(
+      "b", "d",
+      base::BindOnce(&MockDatabaseCaller::LoadKeysAndEntriesCallback,
+                     base::Unretained(&caller)));
+
+  base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(UniqueProtoDatabaseTest, TestDBLoadInRangeSuccessSameKey) {
+  ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
+  std::unique_ptr<LevelDB> db(new LevelDB(kTestLevelDBClientName));
+  MockDatabaseCaller caller;
+  EntryMap model = GetRangeTestModel();
+  EntryMap expected;
+
+  expected["d"] = model["d"];
+
+  EXPECT_CALL(caller, InitStatusCallback(_));
+  db_->InitWithDatabase(db.get(), temp_dir.GetPath(), CreateSimpleOptions(),
+                        base::BindOnce(&MockDatabaseCaller::InitStatusCallback,
+                                       base::Unretained(&caller)));
+
+  auto save_entries =
+      std::make_unique<ProtoDatabase<TestProto>::KeyEntryVector>();
+  std::map<std::string, TestProto> load_keys_entries;
+  std::unique_ptr<KeyVector> remove_keys(new KeyVector());
+
+  for (const auto& pair : model) {
+    save_entries->push_back(std::make_pair(pair.second.id(), pair.second));
+  }
+
+  leveldb::Status status;
+  EXPECT_CALL(caller, SaveCallback(true));
+  db_->UpdateEntries(std::move(save_entries), std::move(remove_keys),
+                     base::BindOnce(&MockDatabaseCaller::SaveCallback,
+                                    base::Unretained(&caller)));
+
+  EXPECT_CALL(caller, LoadKeysAndEntriesCallback1(true, _))
+      .WillOnce(VerifyLoadKeysAndEntries(testing::ByRef(expected)));
+  db_->LoadKeysAndEntriesInRange(
+      "d", "d",
+      base::BindOnce(&MockDatabaseCaller::LoadKeysAndEntriesCallback,
+                     base::Unretained(&caller)));
+
+  base::RunLoop().RunUntilIdle();
+}
+
 ACTION_P(SetGetEntry, model) {
   const std::string& key = arg0;
   bool* found = arg1;
@@ -856,6 +966,47 @@
   }
 }
 
+TEST_F(UniqueProtoDatabaseLevelDBTest, TestDBLoadKeysAndEntriesWhile) {
+  ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
+  EntryMap model = GetRangeTestModel();
+  EntryMap expected;
+  expected["b"] = model["b"];
+  expected["c"] = model["c"];
+  expected["d"] = model["d"];
+
+  KeyValueVector save_entries;
+  std::map<std::string, std::string> load_keys_entries;
+  KeyVector remove_keys;
+
+  for (const auto& pair : model) {
+    save_entries.push_back(
+        std::make_pair(pair.second.id(), pair.second.SerializeAsString()));
+  }
+
+  std::unique_ptr<LevelDB> db(new LevelDB(kTestLevelDBClientName));
+  EXPECT_TRUE(db->Init(temp_dir.GetPath(), CreateSimpleOptions()));
+  leveldb::Status status;
+  EXPECT_TRUE(db->Save(save_entries, remove_keys, &status));
+
+  EXPECT_TRUE(db->LoadKeysAndEntriesWhile(
+      LevelDB::KeyFilter(), &load_keys_entries, leveldb::ReadOptions(), "b",
+      base::BindRepeating(
+          [](const std::string& range_end, const std::string& key) {
+            return key.compare(range_end) <= 0;
+          },
+          "d")));
+
+  EXPECT_EQ(load_keys_entries.size(), expected.size());
+  for (const auto& pair : load_keys_entries) {
+    TestProto entry;
+    ASSERT_TRUE(entry.ParseFromString(pair.second));
+    EXPECT_EQ(entry.SerializeAsString(),
+              expected[pair.first].SerializeAsString());
+  }
+}
+
 TEST_F(UniqueProtoDatabaseLevelDBTest, TestDBInitFail) {
   ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
diff --git a/components/management_strings.grdp b/components/management_strings.grdp
index 0b311e48..eb0d118 100644
--- a/components/management_strings.grdp
+++ b/components/management_strings.grdp
@@ -4,6 +4,10 @@
     Management overview
   </message>
 
+  <message name="IDS_MANAGEMENT_TITLE_BY" desc="Title of chrome://management page, shows when device managed by known organization" translateable="false">
+    Device managed by <ph name="ENROLLMENT_DOMAIN">$1<ex>example.com</ex></ph>
+  </message>
+
   <message name="IDS_MANAGEMENT_DEVICE_NOT_MANAGED" desc="Message indicating that the device is not managed" translateable="false">
     Your device is not managed by an administrator
   </message>
diff --git a/components/password_manager/core/browser/password_autofill_manager.cc b/components/password_manager/core/browser/password_autofill_manager.cc
index 4b78224..fffc97a 100644
--- a/components/password_manager/core/browser/password_autofill_manager.cc
+++ b/components/password_manager/core/browser/password_autofill_manager.cc
@@ -153,10 +153,9 @@
 
 bool ShouldShowManualFallbackForPreLollipop(syncer::SyncService* sync_service) {
 #if defined(OS_ANDROID)
-  return ((base::android::BuildInfo::GetInstance()->sdk_int() >=
-           base::android::SDK_VERSION_LOLLIPOP) ||
-          (password_manager_util::GetPasswordSyncState(sync_service) ==
-           SYNCING_NORMAL_ENCRYPTION));
+  return base::android::BuildInfo::GetInstance()->sdk_int() >=
+             base::android::SDK_VERSION_LOLLIPOP ||
+         password_manager_util::IsSyncingWithNormalEncryption(sync_service);
 #else
   return true;
 #endif
diff --git a/components/password_manager/core/browser/password_manager_util.cc b/components/password_manager/core/browser/password_manager_util.cc
index 8bec633..8b6725e 100644
--- a/components/password_manager/core/browser/password_manager_util.cc
+++ b/components/password_manager/core/browser/password_manager_util.cc
@@ -69,6 +69,11 @@
   return password_manager::NOT_SYNCING;
 }
 
+bool IsSyncingWithNormalEncryption(const syncer::SyncService* sync_service) {
+  return GetPasswordSyncState(sync_service) ==
+         password_manager::SYNCING_NORMAL_ENCRYPTION;
+}
+
 void FindDuplicates(std::vector<std::unique_ptr<PasswordForm>>* forms,
                     std::vector<std::unique_ptr<PasswordForm>>* duplicates,
                     std::vector<std::vector<PasswordForm*>>* tag_groups) {
diff --git a/components/password_manager/core/browser/password_manager_util.h b/components/password_manager/core/browser/password_manager_util.h
index cf5490b5..a2d96579a 100644
--- a/components/password_manager/core/browser/password_manager_util.h
+++ b/components/password_manager/core/browser/password_manager_util.h
@@ -46,6 +46,10 @@
 password_manager::SyncState GetPasswordSyncState(
     const syncer::SyncService* sync_service);
 
+// Reports whether passwords are synced with normal encryption, i.e. without a
+// custom passphrase.
+bool IsSyncingWithNormalEncryption(const syncer::SyncService* sync_service);
+
 // Finds the forms with a duplicate sync tags in |forms|. The first one of
 // the duplicated entries stays in |forms|, the others are moved to
 // |duplicates|.
diff --git a/components/previews/content/previews_content_util.cc b/components/previews/content/previews_content_util.cc
index c851c0a1..d52ea5e 100644
--- a/components/previews/content/previews_content_util.cc
+++ b/components/previews/content/previews_content_util.cc
@@ -4,7 +4,9 @@
 
 #include "components/previews/content/previews_content_util.h"
 
+#include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/strings/stringprintf.h"
 #include "components/previews/content/previews_user_data.h"
 #include "components/previews/core/previews_lite_page_redirect.h"
 
@@ -93,6 +95,18 @@
   return previews_state;
 }
 
+void LogCommittedPreview(previews::PreviewsUserData* previews_data,
+                         PreviewsType type) {
+  net::EffectiveConnectionType navigation_ect = previews_data->navigation_ect();
+  UMA_HISTOGRAM_ENUMERATION("Previews.Triggered.EffectiveConnectionType2",
+                            navigation_ect,
+                            net::EFFECTIVE_CONNECTION_TYPE_LAST);
+  base::UmaHistogramEnumeration(
+      base::StringPrintf("Previews.Triggered.EffectiveConnectionType2.%s",
+                         GetStringNameForType(type).c_str()),
+      navigation_ect, net::EFFECTIVE_CONNECTION_TYPE_LAST);
+}
+
 content::PreviewsState DetermineCommittedClientPreviewsState(
     previews::PreviewsUserData* previews_data,
     const GURL& url,
@@ -106,6 +120,7 @@
   // Check if an offline preview was actually served.
   if (previews_data && previews_data->offline_preview_used()) {
     DCHECK(previews_state & content::OFFLINE_PAGE_ON);
+    LogCommittedPreview(previews_data, PreviewsType::OFFLINE);
     return content::OFFLINE_PAGE_ON;
   }
   previews_state &= ~content::OFFLINE_PAGE_ON;
@@ -117,6 +132,7 @@
   // Client LoFi bit on so that it is applied to both HTTP and HTTPS images.
   if (previews_state &
       (content::SERVER_LITE_PAGE_ON | content::SERVER_LOFI_ON)) {
+    LogCommittedPreview(previews_data, PreviewsType::LITE_PAGE);
     return previews_state & (content::SERVER_LITE_PAGE_ON |
                              content::SERVER_LOFI_ON | content::CLIENT_LOFI_ON);
   }
@@ -133,8 +149,10 @@
 
   // Check if a LITE_PAGE_REDIRECT preview was actually served.
   if (previews_state & content::LITE_PAGE_REDIRECT_ON) {
-    if (IsLitePageRedirectPreviewURL(url))
+    if (IsLitePageRedirectPreviewURL(url)) {
+      LogCommittedPreview(previews_data, PreviewsType::LITE_PAGE_REDIRECT);
       return content::LITE_PAGE_REDIRECT_ON;
+    }
     previews_state &= ~content::LITE_PAGE_REDIRECT_ON;
   }
   DCHECK(!IsLitePageRedirectPreviewURL(url));
@@ -148,6 +166,7 @@
         previews_decider->ShouldCommitPreview(
             previews_data, url,
             previews::PreviewsType::RESOURCE_LOADING_HINTS)) {
+      LogCommittedPreview(previews_data, PreviewsType::RESOURCE_LOADING_HINTS);
       return content::RESOURCE_LOADING_HINTS_ON;
     }
     // Remove RESOURCE_LOADING_HINTS_ON from |previews_state| since we decided
@@ -161,11 +180,13 @@
     if (is_https && previews_decider &&
         previews_decider->ShouldCommitPreview(
             previews_data, url, previews::PreviewsType::NOSCRIPT)) {
+      LogCommittedPreview(previews_data, PreviewsType::NOSCRIPT);
       return content::NOSCRIPT_ON;
     }
     return content::PREVIEWS_OFF;
   }
   if (previews_state & content::CLIENT_LOFI_ON) {
+    LogCommittedPreview(previews_data, PreviewsType::LOFI);
     return content::CLIENT_LOFI_ON;
   }
 
diff --git a/components/previews/content/previews_content_util_unittest.cc b/components/previews/content/previews_content_util_unittest.cc
index 2180f4e..1651967 100644
--- a/components/previews/content/previews_content_util_unittest.cc
+++ b/components/previews/content/previews_content_util_unittest.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <vector>
 
+#include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/scoped_task_environment.h"
 #include "components/previews/content/previews_user_data.h"
@@ -316,6 +317,9 @@
       "Previews,ClientLoFi,NoScriptPreviews,ResourceLoadingHints",
       std::string());
   PreviewsUserData user_data(1);
+  user_data.set_navigation_ect(net::EFFECTIVE_CONNECTION_TYPE_2G);
+  base::HistogramTester histogram_tester;
+
   // Server bits take precedence over NoScript:
   EXPECT_EQ(content::SERVER_LITE_PAGE_ON | content::SERVER_LOFI_ON |
                 content::CLIENT_LOFI_ON,
@@ -324,6 +328,11 @@
                 content::SERVER_LITE_PAGE_ON | content::SERVER_LOFI_ON |
                     content::CLIENT_LOFI_ON | content::NOSCRIPT_ON,
                 enabled_previews_decider()));
+  histogram_tester.ExpectUniqueSample(
+      "Previews.Triggered.EffectiveConnectionType2.LitePage",
+      static_cast<int>(net::EFFECTIVE_CONNECTION_TYPE_2G), 1);
+  histogram_tester.ExpectTotalCount(
+      "Previews.Triggered.EffectiveConnectionType2", 1);
 
   content::PreviewsState lite_page_redirect_enabled =
       content::CLIENT_LOFI_ON | content::NOSCRIPT_ON |
@@ -337,12 +346,22 @@
       previews::DetermineCommittedClientPreviewsState(
           &user_data, GURL("https://litepages.googlezip.net/?u=google.com"),
           lite_page_redirect_enabled, enabled_previews_decider()));
+  histogram_tester.ExpectUniqueSample(
+      "Previews.Triggered.EffectiveConnectionType2.LitePageRedirect",
+      static_cast<int>(net::EFFECTIVE_CONNECTION_TYPE_2G), 1);
+  histogram_tester.ExpectTotalCount(
+      "Previews.Triggered.EffectiveConnectionType2", 2);
 
   // Verify LITE_PAGE_REDIRECT_ON not committed for non-lite-page-sever URL.
   EXPECT_NE(content::LITE_PAGE_REDIRECT_ON,
             previews::DetermineCommittedClientPreviewsState(
                 &user_data, GURL("https://www.google.com"),
                 lite_page_redirect_enabled, enabled_previews_decider()));
+  histogram_tester.ExpectUniqueSample(
+      "Previews.Triggered.EffectiveConnectionType2.ResourceLoadingHints",
+      static_cast<int>(net::EFFECTIVE_CONNECTION_TYPE_2G), 1);
+  histogram_tester.ExpectTotalCount(
+      "Previews.Triggered.EffectiveConnectionType2", 3);
 
   // NoScript has precedence over Client LoFi - kept for committed HTTPS:
   EXPECT_EQ(content::NOSCRIPT_ON,
@@ -350,6 +369,14 @@
                 &user_data, GURL("https://www.google.com"),
                 content::CLIENT_LOFI_ON | content::NOSCRIPT_ON,
                 enabled_previews_decider()));
+  histogram_tester.ExpectUniqueSample(
+      "Previews.Triggered.EffectiveConnectionType2.NoScript",
+      static_cast<int>(net::EFFECTIVE_CONNECTION_TYPE_2G), 1);
+  histogram_tester.ExpectTotalCount(
+      "Previews.Triggered.EffectiveConnectionType2", 4);
+
+  // Try different navigation ECT value.
+  user_data.set_navigation_ect(net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
 
   // RESOURCE_LOADING_HINTS has precedence over Client LoFi and NoScript.
   EXPECT_EQ(content::RESOURCE_LOADING_HINTS_ON,
@@ -358,6 +385,11 @@
                 content::CLIENT_LOFI_ON | content::NOSCRIPT_ON |
                     content::RESOURCE_LOADING_HINTS_ON,
                 enabled_previews_decider()));
+  histogram_tester.ExpectBucketCount(
+      "Previews.Triggered.EffectiveConnectionType2.ResourceLoadingHints",
+      static_cast<int>(net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G), 1);
+  histogram_tester.ExpectTotalCount(
+      "Previews.Triggered.EffectiveConnectionType2", 5);
 
   // NoScript has precedence over Client LoFi - dropped for committed HTTP:
   EXPECT_EQ(content::PREVIEWS_OFF,
@@ -372,6 +404,11 @@
             previews::DetermineCommittedClientPreviewsState(
                 &user_data, GURL("https://www.google.com"),
                 content::CLIENT_LOFI_ON, enabled_previews_decider()));
+  histogram_tester.ExpectUniqueSample(
+      "Previews.Triggered.EffectiveConnectionType2.LoFi",
+      static_cast<int>(net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G), 1);
+  histogram_tester.ExpectTotalCount(
+      "Previews.Triggered.EffectiveConnectionType2", 6);
 
   // Only NoScript:
   EXPECT_EQ(content::NOSCRIPT_ON,
diff --git a/components/previews/content/previews_decider_impl.cc b/components/previews/content/previews_decider_impl.cc
index 72da57c7..541f87d 100644
--- a/components/previews/content/previews_decider_impl.cc
+++ b/components/previews/content/previews_decider_impl.cc
@@ -45,21 +45,6 @@
       ->Add(static_cast<int>(status));
 }
 
-void LogTriggeredPreviewEffectiveConnectionType(
-    net::EffectiveConnectionType navigation_ect,
-    PreviewsType type) {
-  UMA_HISTOGRAM_ENUMERATION("Previews.Triggered.EffectiveConnectionType",
-                            navigation_ect,
-                            net::EFFECTIVE_CONNECTION_TYPE_LAST);
-  int32_t max_limit = static_cast<int32_t>(net::EFFECTIVE_CONNECTION_TYPE_LAST);
-  base::LinearHistogram::FactoryGet(
-      base::StringPrintf("Previews.Triggered.EffectiveConnectionType.%s",
-                         GetStringNameForType(type).c_str()),
-      1, max_limit, max_limit + 1,
-      base::HistogramBase::kUmaTargetedHistogramFlag)
-      ->Add(static_cast<int>(navigation_ect));
-}
-
 bool AllowedOnReload(PreviewsType type) {
   if (base::FeatureList::IsEnabled(features::kPreviewsDisallowedOnReloads))
     return false;
@@ -401,8 +386,6 @@
     }
   }
 
-  LogTriggeredPreviewEffectiveConnectionType(previews_data->navigation_ect(),
-                                             type);
   return true;
 }
 
diff --git a/components/previews/content/previews_decider_impl_unittest.cc b/components/previews/content/previews_decider_impl_unittest.cc
index d6fed74..4b2ba32 100644
--- a/components/previews/content/previews_decider_impl_unittest.cc
+++ b/components/previews/content/previews_decider_impl_unittest.cc
@@ -917,10 +917,6 @@
         static_cast<int>(
             PreviewsEligibilityReason::HOST_NOT_WHITELISTED_BY_SERVER),
         1);
-
-    // Expect no triggered ECT logged.
-    histogram_tester.ExpectTotalCount(
-        "Previews.Triggered.EffectiveConnectionType.NoScript", 0);
   }
 
   // Now verify preview for whitelisted url.
@@ -934,14 +930,6 @@
 
     // Expect no eligibility logging.
     histogram_tester.ExpectTotalCount("Previews.EligibilityReason.NoScript", 0);
-
-    // Triggered ECT logged.
-    histogram_tester.ExpectUniqueSample(
-        "Previews.Triggered.EffectiveConnectionType",
-        static_cast<int>(net::EFFECTIVE_CONNECTION_TYPE_2G), 1);
-    histogram_tester.ExpectUniqueSample(
-        "Previews.Triggered.EffectiveConnectionType.NoScript",
-        static_cast<int>(net::EFFECTIVE_CONNECTION_TYPE_2G), 1);
   }
 
   // Verify preview not allowed for whitelisted url when network is not slow.
@@ -956,10 +944,6 @@
     histogram_tester.ExpectUniqueSample(
         "Previews.EligibilityReason.NoScript",
         static_cast<int>(PreviewsEligibilityReason::NETWORK_NOT_SLOW), 1);
-
-    // Expect no triggered ECT logged.
-    histogram_tester.ExpectTotalCount(
-        "Previews.Triggered.EffectiveConnectionType.NoScript", 0);
   }
 
   // Verify preview not allowed for whitelisted url for unknown network quality.
@@ -976,10 +960,6 @@
         static_cast<int>(
             PreviewsEligibilityReason::NETWORK_QUALITY_UNAVAILABLE),
         1);
-
-    // Expect no triggered ECT logged.
-    histogram_tester.ExpectTotalCount(
-        "Previews.Triggered.EffectiveConnectionType.NoScript", 0);
   }
 
   // Verify preview not allowed for session limited ECT threshold.
@@ -1000,10 +980,6 @@
         static_cast<int>(
             PreviewsEligibilityReason::NETWORK_NOT_SLOW_FOR_SESSION),
         1);
-
-    // Expect no triggered ECT logged.
-    histogram_tester.ExpectTotalCount(
-        "Previews.Triggered.EffectiveConnectionType.NoScript", 0);
   }
 }
 
@@ -1174,10 +1150,6 @@
         static_cast<int>(
             PreviewsEligibilityReason::HOST_NOT_WHITELISTED_BY_SERVER),
         1);
-
-    // Expect no triggered ECT logged.
-    histogram_tester.ExpectTotalCount(
-        "Previews.Triggered.EffectiveConnectionType.ResourceLoadingHints", 0);
   }
 
   // Now verify preview for whitelisted url.
@@ -1192,14 +1164,6 @@
     // Expect no eligibility logging.
     histogram_tester.ExpectTotalCount(
         "Previews.EligibilityReason.ResourceLoadingHints", 0);
-
-    // Triggered ECT logged.
-    histogram_tester.ExpectUniqueSample(
-        "Previews.Triggered.EffectiveConnectionType",
-        static_cast<int>(net::EFFECTIVE_CONNECTION_TYPE_2G), 1);
-    histogram_tester.ExpectUniqueSample(
-        "Previews.Triggered.EffectiveConnectionType.ResourceLoadingHints",
-        static_cast<int>(net::EFFECTIVE_CONNECTION_TYPE_2G), 1);
   }
 
   // Verify preview not allowed for whitelisted url when network is not slow.
@@ -1214,10 +1178,6 @@
     histogram_tester.ExpectUniqueSample(
         "Previews.EligibilityReason.ResourceLoadingHints",
         static_cast<int>(PreviewsEligibilityReason::NETWORK_NOT_SLOW), 1);
-
-    // Expect no triggered ECT logged.
-    histogram_tester.ExpectTotalCount(
-        "Previews.Triggered.EffectiveConnectionType.ResourceLoadingHints", 0);
   }
 
   // Verify preview not allowed for whitelisted url for unknown network quality.
@@ -1232,10 +1192,6 @@
     histogram_tester.ExpectUniqueSample(
         "Previews.EligibilityReason.ResourceLoadingHints",
         static_cast<int>(PreviewsEligibilityReason::DEVICE_OFFLINE), 1);
-
-    // Expect no triggered ECT logged.
-    histogram_tester.ExpectTotalCount(
-        "Previews.Triggered.EffectiveConnectionType.ResourceLoadingHints", 0);
   }
 
   // Verify preview not allowed for session limited ECT threshold.
@@ -1256,10 +1212,6 @@
         static_cast<int>(
             PreviewsEligibilityReason::NETWORK_NOT_SLOW_FOR_SESSION),
         1);
-
-    // Expect no triggered ECT logged.
-    histogram_tester.ExpectTotalCount(
-        "Previews.Triggered.EffectiveConnectionType.ResourceLoadingHints", 0);
   }
 }
 
diff --git a/components/previews/content/previews_hints.cc b/components/previews/content/previews_hints.cc
index 07b77dd..627c16c 100644
--- a/components/previews/content/previews_hints.cc
+++ b/components/previews/content/previews_hints.cc
@@ -312,6 +312,16 @@
     return nullptr;
   }
 
+  std::unique_ptr<PreviewsHints> hints = CreateFromHintsConfiguration(*config);
+
+  // Completed processing hints data without crashing so clear sentinel.
+  DeleteSentinelFile(sentinel_path);
+  return hints;
+}
+
+// static
+std::unique_ptr<PreviewsHints> PreviewsHints::CreateFromHintsConfiguration(
+    const optimization_guide::proto::Configuration& config) {
   std::unique_ptr<PreviewsHints> hints(new PreviewsHints());
   HintCache::Data hint_cache_data;
 
@@ -320,7 +330,7 @@
   size_t total_page_patterns_with_resource_loading_hints_received = 0;
   size_t total_resource_loading_hints_received = 0;
   // Process hint configuration.
-  for (const auto& hint : config->hints()) {
+  for (const auto& hint : config.hints()) {
     // We only support host suffixes at the moment. Skip anything else.
     // One |hint| applies to one host URL suffix.
     if (hint.key_representation() != optimization_guide::proto::HOST_SUFFIX) {
@@ -368,10 +378,8 @@
   }
 
   // Extract any supported large scale blacklists from the configuration.
-  hints->ParseOptimizationFilters(*config);
+  hints->ParseOptimizationFilters(config);
 
-  // Completed processing hints data without crashing so clear sentinel.
-  DeleteSentinelFile(sentinel_path);
   RecordProcessHintsResult(
       !hints->hint_cache_
           ? PreviewsProcessHintsResult::kProcessedNoPreviewsHints
diff --git a/components/previews/content/previews_hints.h b/components/previews/content/previews_hints.h
index c84d630..4b28e16 100644
--- a/components/previews/content/previews_hints.h
+++ b/components/previews/content/previews_hints.h
@@ -38,6 +38,12 @@
   static std::unique_ptr<PreviewsHints> CreateFromHintsComponent(
       const optimization_guide::HintsComponentInfo& info);
 
+  // Creates a Hints instance from the provided hints configuration. This must
+  // be called using a background task runner as it requires a significant
+  // amount of processing.
+  static std::unique_ptr<PreviewsHints> CreateFromHintsConfiguration(
+      const optimization_guide::proto::Configuration& config);
+
   // Returns the matching PageHint for |document_url| if found in |hint|.
   // TODO(dougarnett): Consider moving to some hint_util file.
   static const optimization_guide::proto::PageHint* FindPageHint(
diff --git a/components/previews/content/previews_optimization_guide.cc b/components/previews/content/previews_optimization_guide.cc
index bd697e2..836093bc 100644
--- a/components/previews/content/previews_optimization_guide.cc
+++ b/components/previews/content/previews_optimization_guide.cc
@@ -4,7 +4,9 @@
 
 #include "components/previews/content/previews_optimization_guide.h"
 
+#include "base/base64.h"
 #include "base/bind.h"
+#include "base/command_line.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/task/post_task.h"
 #include "base/task_runner_util.h"
@@ -14,10 +16,44 @@
 #include "components/previews/content/previews_hints.h"
 #include "components/previews/content/previews_user_data.h"
 #include "components/previews/core/previews_constants.h"
+#include "components/previews/core/previews_switches.h"
 #include "url/gurl.h"
 
 namespace previews {
 
+namespace {
+
+// Attempts to parse a base64 encoded Optimization Guide Configuration proto
+// from the command line. If no proto is given or if it is encoded incorrectly,
+// nullptr is returned.
+std::unique_ptr<optimization_guide::proto::Configuration>
+ParseHintsProtoFromCommandLine() {
+  base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
+  if (!cmd_line->HasSwitch(switches::kHintsProtoOverride))
+    return nullptr;
+
+  std::string b64_pb =
+      cmd_line->GetSwitchValueASCII(switches::kHintsProtoOverride);
+
+  std::string binary_pb;
+  if (!base::Base64Decode(b64_pb, &binary_pb)) {
+    LOG(ERROR) << "Invalid base64 encoding of the Hints Proto Override";
+    return nullptr;
+  }
+
+  std::unique_ptr<optimization_guide::proto::Configuration>
+      proto_configuration =
+          std::make_unique<optimization_guide::proto::Configuration>();
+  if (!proto_configuration->ParseFromString(binary_pb)) {
+    LOG(ERROR) << "Invalid proto provided to the Hints Proto Override";
+    return nullptr;
+  }
+
+  return proto_configuration;
+}
+
+}  // namespace
+
 PreviewsOptimizationGuide::PreviewsOptimizationGuide(
     optimization_guide::OptimizationGuideService* optimization_guide_service,
     const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner)
@@ -27,7 +63,22 @@
           {base::MayBlock(), base::TaskPriority::BEST_EFFORT})),
       ui_weak_ptr_factory_(this) {
   DCHECK(optimization_guide_service_);
-  optimization_guide_service_->AddObserver(this);
+
+  // Check if there is a valid hint proto given on the command line first. We
+  // don't normally expect one, but if one is provided then use that and do not
+  // register as an observer as the opt_guide service.
+  std::unique_ptr<optimization_guide::proto::Configuration> manual_config =
+      ParseHintsProtoFromCommandLine();
+  if (manual_config) {
+    base::PostTaskAndReplyWithResult(
+        background_task_runner_.get(), FROM_HERE,
+        base::BindOnce(&PreviewsHints::CreateFromHintsConfiguration,
+                       *manual_config),
+        base::BindOnce(&PreviewsOptimizationGuide::UpdateHints,
+                       ui_weak_ptr_factory_.GetWeakPtr()));
+  } else {
+    optimization_guide_service_->AddObserver(this);
+  }
 }
 
 PreviewsOptimizationGuide::~PreviewsOptimizationGuide() {
diff --git a/components/previews/content/previews_optimization_guide.h b/components/previews/content/previews_optimization_guide.h
index 6eec1202..360b37e63 100644
--- a/components/previews/content/previews_optimization_guide.h
+++ b/components/previews/content/previews_optimization_guide.h
@@ -80,6 +80,8 @@
   void OnHintsComponentAvailable(
       const optimization_guide::HintsComponentInfo& info) override;
 
+  PreviewsHints* GetHintsForTesting() { return hints_.get(); }
+
  private:
   // Updates the hints to the latest hints sent by the Component Updater.
   void UpdateHints(std::unique_ptr<PreviewsHints> hints);
diff --git a/components/previews/content/previews_optimization_guide_unittest.cc b/components/previews/content/previews_optimization_guide_unittest.cc
index 0738a3c5..ae3754b0 100644
--- a/components/previews/content/previews_optimization_guide_unittest.cc
+++ b/components/previews/content/previews_optimization_guide_unittest.cc
@@ -6,8 +6,10 @@
 
 #include <memory>
 
+#include "base/base64.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
@@ -25,6 +27,7 @@
 #include "components/previews/content/previews_user_data.h"
 #include "components/previews/core/bloom_filter.h"
 #include "components/previews/core/previews_features.h"
+#include "components/previews/core/previews_switches.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
@@ -88,6 +91,13 @@
     guide_->OnHintsComponentAvailable(info);
   }
 
+  void NewGuide() {
+    guide_ = std::make_unique<PreviewsOptimizationGuide>(
+        optimization_guide_service_.get(),
+        scoped_task_environment_.GetMainThreadTaskRunner());
+    RunUntilIdle();
+  }
+
   void ResetGuide() {
     guide_.reset();
     RunUntilIdle();
@@ -350,6 +360,45 @@
                                      PreviewsType::NOSCRIPT, &ect_threshold));
 }
 
+TEST_F(PreviewsOptimizationGuideTest,
+       ProcessHintsWithValidCommandLineOverride) {
+  optimization_guide::proto::Configuration config;
+  optimization_guide::proto::Hint* hint = config.add_hints();
+  hint->set_key("somedomain.org");
+  hint->set_key_representation(optimization_guide::proto::HOST_SUFFIX);
+  optimization_guide::proto::PageHint* page_hint = hint->add_page_hints();
+  page_hint->set_page_pattern("noscript_default_2g");
+  optimization_guide::proto::Optimization* optimization =
+      page_hint->add_whitelisted_optimizations();
+  optimization->set_optimization_type(optimization_guide::proto::NOSCRIPT);
+
+  std::string encoded_config;
+  config.SerializeToString(&encoded_config);
+  base::Base64Encode(encoded_config, &encoded_config);
+
+  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+      switches::kHintsProtoOverride, encoded_config);
+  NewGuide();
+
+  // Verify page matches and ECT thresholds.
+  PreviewsUserData user_data(kDefaultPageId);
+  net::EffectiveConnectionType ect_threshold;
+  EXPECT_TRUE(guide()->GetHintsForTesting());
+  EXPECT_TRUE(guide()->IsWhitelisted(
+      &user_data, GURL("https://somedomain.org/noscript_default_2g"),
+      PreviewsType::NOSCRIPT, &ect_threshold));
+  EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_2G, ect_threshold);
+}
+
+TEST_F(PreviewsOptimizationGuideTest,
+       ProcessHintsWithInvalidCommandLineOverride) {
+  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+      switches::kHintsProtoOverride, "this-is-not-a-proto");
+  NewGuide();
+
+  EXPECT_FALSE(guide()->GetHintsForTesting());
+}
+
 // Test when resource loading hints are enabled.
 TEST_F(PreviewsOptimizationGuideTest,
        ProcessHintsForResourceLoadingHintsPopulatedCorrectly) {
diff --git a/components/previews/core/previews_switches.cc b/components/previews/core/previews_switches.cc
index 6e24120..a50966c 100644
--- a/components/previews/core/previews_switches.cc
+++ b/components/previews/core/previews_switches.cc
@@ -26,5 +26,11 @@
 const char kClearLitePageRedirectLocalBlacklist[] =
     "clear-litepage-redirect-local-blacklist-on-startup";
 
+// Overrides the Hints Protobuf that would come from the component updater. If
+// the value of this switch is invalid, regular hint processing is used.
+// The value of this switch should be a base64 encoding of a binary
+// Configuration message, found in optimization_guide's hints.proto.
+const char kHintsProtoOverride[] = "optimization_guide_hints_override";
+
 }  // namespace switches
 }  // namespace previews
diff --git a/components/previews/core/previews_switches.h b/components/previews/core/previews_switches.h
index a7516aa..0fe70a78 100644
--- a/components/previews/core/previews_switches.h
+++ b/components/previews/core/previews_switches.h
@@ -13,6 +13,7 @@
 extern const char kLitePageServerPreviewHost[];
 extern const char kIgnoreLitePageRedirectOptimizationBlacklist[];
 extern const char kClearLitePageRedirectLocalBlacklist[];
+extern const char kHintsProtoOverride[];
 
 }  // namespace switches
 }  // namespace previews
diff --git a/components/resources/components_scaled_resources.grd b/components/resources/components_scaled_resources.grd
index 511ec196..2403267 100644
--- a/components/resources/components_scaled_resources.grd
+++ b/components/resources/components_scaled_resources.grd
@@ -13,7 +13,6 @@
   <release seq="1">
     <structures fallback_to_low_resolution="true">
       <part file="autofill_scaled_resources.grdp" />
-      <part file="content_suggestions_scaled_resources.grdp" />
       <part file="crash_scaled_resources.grdp" />
       <part file="flags_ui_scaled_resources.grdp" />
       <part file="neterror_scaled_resources.grdp" />
diff --git a/components/resources/content_suggestions_scaled_resources.grdp b/components/resources/content_suggestions_scaled_resources.grdp
deleted file mode 100644
index 12b382dc..0000000
--- a/components/resources/content_suggestions_scaled_resources.grdp
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<grit-part>
-  <structure type="chrome_scaled_image" name="IDR_PHYSICAL_WEB_LOGO_WITH_PADDING" file="content_suggestions/physical_web_logo_with_padding.png" />
-</grit-part>
diff --git a/components/resources/default_100_percent/content_suggestions/physical_web_logo_with_padding.png b/components/resources/default_100_percent/content_suggestions/physical_web_logo_with_padding.png
deleted file mode 100644
index 271b580..0000000
--- a/components/resources/default_100_percent/content_suggestions/physical_web_logo_with_padding.png
+++ /dev/null
Binary files differ
diff --git a/components/resources/default_200_percent/content_suggestions/physical_web_logo_with_padding.png b/components/resources/default_200_percent/content_suggestions/physical_web_logo_with_padding.png
deleted file mode 100644
index 96aba76..0000000
--- a/components/resources/default_200_percent/content_suggestions/physical_web_logo_with_padding.png
+++ /dev/null
Binary files differ
diff --git a/components/resources/default_300_percent/content_suggestions/physical_web_logo_with_padding.png b/components/resources/default_300_percent/content_suggestions/physical_web_logo_with_padding.png
deleted file mode 100644
index e1ebaed8..0000000
--- a/components/resources/default_300_percent/content_suggestions/physical_web_logo_with_padding.png
+++ /dev/null
Binary files differ
diff --git a/components/safe_browsing/db/v4_local_database_manager.cc b/components/safe_browsing/db/v4_local_database_manager.cc
index 317a9c6..b87ae494 100644
--- a/components/safe_browsing/db/v4_local_database_manager.cc
+++ b/components/safe_browsing/db/v4_local_database_manager.cc
@@ -17,7 +17,6 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/task/post_task.h"
-#include "base/timer/elapsed_timer.h"
 #include "components/safe_browsing/db/v4_feature_list.h"
 #include "components/safe_browsing/db/v4_protocol_manager_util.h"
 #include "content/public/browser/browser_task_traits.h"
@@ -601,11 +600,8 @@
     const std::unique_ptr<PendingCheck>& check,
     FullHashToStoreAndHashPrefixesMap* full_hash_to_store_and_hash_prefixes) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
   DCHECK(enabled_);
-  DCHECK(v4_database_);
 
-  base::ElapsedTimer timer;
   full_hash_to_store_and_hash_prefixes->clear();
   for (const auto& full_hash : check->full_hashes) {
     StoreAndHashPrefixes matched_store_and_hash_prefixes;
@@ -617,11 +613,6 @@
     }
   }
 
-  // NOTE(vakh): This doesn't distinguish which stores it's searching through.
-  // However, the vast majority of the entries in this histogram will be from
-  // searching the three CHECK_BROWSE_URL stores.
-  UMA_HISTOGRAM_COUNTS_10M("SafeBrowsing.V4GetPrefixMatches.TimeUs",
-                           timer.Elapsed().InMicroseconds());
   return !full_hash_to_store_and_hash_prefixes->empty();
 }
 
diff --git a/components/services/heap_profiling/public/cpp/allocator_shim.cc b/components/services/heap_profiling/public/cpp/allocator_shim.cc
index ef9d4c8..45c3b19 100644
--- a/components/services/heap_profiling/public/cpp/allocator_shim.cc
+++ b/components/services/heap_profiling/public/cpp/allocator_shim.cc
@@ -882,12 +882,16 @@
   serializer->AddAllInstructionPointers(frame_count - skip_frames,
                                         frames + skip_frames);
 
+  // Both thread name and task context require access to TLS.
+  if (ScopedAllowAlloc::HasTLSBeenDestroyed())
+    return;
+
   if (g_include_thread_names) {
     const char* thread_name = GetOrSetThreadName();
     serializer->AddCString(thread_name);
   }
 
-  if (!*context && !ScopedAllowAlloc::HasTLSBeenDestroyed()) {
+  if (!*context) {
     const auto* tracker =
         AllocationContextTracker::GetInstanceForCurrentThread();
     if (tracker)
diff --git a/components/storage_monitor/BUILD.gn b/components/storage_monitor/BUILD.gn
index a3d2988..cd32730 100644
--- a/components/storage_monitor/BUILD.gn
+++ b/components/storage_monitor/BUILD.gn
@@ -84,7 +84,7 @@
       "storage_monitor_linux.cc",
       "storage_monitor_linux.h",
     ]
-    deps += [ "//chromeos" ]
+    deps += [ "//chromeos/disks" ]
   }
 }
 
@@ -157,6 +157,6 @@
     }
   }
   if (is_chromeos) {
-    deps += [ "//chromeos:test_support" ]
+    deps += [ "//chromeos/disks:test_support" ]
   }
 }
diff --git a/components/subresource_filter/content/renderer/subresource_filter_agent.cc b/components/subresource_filter/content/renderer/subresource_filter_agent.cc
index 20b21bbd..0202b182 100644
--- a/components/subresource_filter/content/renderer/subresource_filter_agent.cc
+++ b/components/subresource_filter/content/renderer/subresource_filter_agent.cc
@@ -199,24 +199,6 @@
 }
 
 void SubresourceFilterAgent::DidCreateNewDocument() {
-  if (!first_document_)
-    return;
-  first_document_ = false;
-
-  // Local subframes will first navigate to kAboutBlankURL. Frames created by
-  // the browser initialize the LocalFrame before creating
-  // RenderFrameObservers, so the about:blank document isn't observed. We only
-  // care about local subframes.
-  if (IsAdSubframe() && GetDocumentURL() == url::kAboutBlankURL)
-    SendFrameIsAdSubframe();
-}
-
-void SubresourceFilterAgent::DidCommitProvisionalLoad(
-    bool is_same_document_navigation,
-    ui::PageTransition transition) {
-  if (is_same_document_navigation)
-    return;
-
   // Filter may outlive us, so reset the ad tracker.
   if (filter_for_last_committed_load_)
     filter_for_last_committed_load_->set_ad_resource_tracker(nullptr);
@@ -226,6 +208,20 @@
   // which require changes to the unit tests.
   const GURL& url = GetDocumentURL();
 
+  if (first_document_) {
+    first_document_ = false;
+
+    // Local subframes will first navigate to kAboutBlankURL. Frames created by
+    // the browser initialize the LocalFrame before creating
+    // RenderFrameObservers, so the about:blank document isn't observed. We only
+    // care about local subframes.
+    if (url == url::kAboutBlankURL) {
+      if (IsAdSubframe())
+        SendFrameIsAdSubframe();
+      return;
+    }
+  }
+
   bool use_parent_activation = !IsMainFrame() && ShouldUseParentActivation(url);
 
   const mojom::ActivationState activation_state =
diff --git a/components/subresource_filter/content/renderer/subresource_filter_agent.h b/components/subresource_filter/content/renderer/subresource_filter_agent.h
index 8338bb1..70c0406 100644
--- a/components/subresource_filter/content/renderer/subresource_filter_agent.h
+++ b/components/subresource_filter/content/renderer/subresource_filter_agent.h
@@ -97,8 +97,6 @@
   // content::RenderFrameObserver:
   void OnDestruct() override;
   void DidCreateNewDocument() override;
-  void DidCommitProvisionalLoad(bool is_same_document_navigation,
-                                ui::PageTransition transition) override;
   void DidFailProvisionalLoad(const blink::WebURLError& error) override;
   void DidFinishLoad() override;
   void WillCreateWorkerFetchContext(blink::WebWorkerFetchContext*) override;
diff --git a/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc b/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc
index 4f9f7b0..3963044 100644
--- a/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc
+++ b/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc
@@ -139,14 +139,13 @@
 
   void StartLoadWithoutSettingActivationState() {
     agent_as_rfo()->DidStartProvisionalLoad(nullptr, true);
-    agent_as_rfo()->DidCommitProvisionalLoad(
-        false /* is_same_document_navigation */, ui::PAGE_TRANSITION_LINK);
+    agent_as_rfo()->DidCreateNewDocument();
   }
 
   void PerformSameDocumentNavigationWithoutSettingActivationLevel() {
     agent_as_rfo()->DidStartProvisionalLoad(nullptr, true);
-    agent_as_rfo()->DidCommitProvisionalLoad(
-        true /* is_same_document_navigation */, ui::PAGE_TRANSITION_LINK);
+    // No DidCreateNewDocument, since same document navigations by definition
+    // don't create a new document.
     // No DidFinishLoad is called in this case.
   }
 
@@ -163,8 +162,7 @@
       AdFrameType ad_type = AdFrameType::kNonAd) {
     agent_as_rfo()->DidStartProvisionalLoad(nullptr, true);
     agent()->ActivateForNextCommittedLoad(state.Clone(), ad_type);
-    agent_as_rfo()->DidCommitProvisionalLoad(
-        false /* is_same_document_navigation */, ui::PAGE_TRANSITION_LINK);
+    agent_as_rfo()->DidCreateNewDocument();
   }
 
   void FinishLoad() { agent_as_rfo()->DidFinishLoad(); }
@@ -606,11 +604,15 @@
   EXPECT_CALL(*agent(), GetDocumentURL())
       .WillOnce(::testing::Return(GURL("about:blank")));
   agent_as_rfo()->DidCreateNewDocument();
+  EXPECT_CALL(*agent(), GetDocumentURL())
+      .WillOnce(::testing::Return(GURL("about:blank")));
   agent_as_rfo()->DidCreateNewDocument();
 }
 
 TEST_F(SubresourceFilterAgentTest, DryRun_DoesNotSendFrameIsAdSubframe) {
   ExpectNoSendFrameIsAdSubframe();
+  EXPECT_CALL(*agent(), GetDocumentURL())
+      .WillOnce(::testing::Return(GURL("about:blank")));
   agent_as_rfo()->DidCreateNewDocument();
 }
 
diff --git a/components/ui_devtools/views/BUILD.gn b/components/ui_devtools/views/BUILD.gn
index ccbbbd51..9bc16b6 100644
--- a/components/ui_devtools/views/BUILD.gn
+++ b/components/ui_devtools/views/BUILD.gn
@@ -43,8 +43,8 @@
   }
 
   sources = [
+    "dom_agent_unittest.cc",
     "overlay_agent_unittest.cc",
-    "ui_devtools_unittest.cc",
     "view_element_unittest.cc",
     "widget_element_unittest.cc",
     "window_element_unittest.cc",
diff --git a/components/ui_devtools/views/dom_agent_unittest.cc b/components/ui_devtools/views/dom_agent_unittest.cc
new file mode 100644
index 0000000..58da7bb9
--- /dev/null
+++ b/components/ui_devtools/views/dom_agent_unittest.cc
@@ -0,0 +1,546 @@
+// Copyright 2019 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 <memory>
+
+#include "components/ui_devtools/views/dom_agent_aura.h"
+
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/ui_devtools/css_agent.h"
+#include "components/ui_devtools/ui_devtools_unittest_utils.h"
+#include "components/ui_devtools/ui_element.h"
+#include "components/ui_devtools/views/overlay_agent_aura.h"
+#include "components/ui_devtools/views/view_element.h"
+#include "components/ui_devtools/views/widget_element.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/widget/native_widget_private.h"
+#include "ui/views/widget/widget.h"
+
+#if defined(USE_AURA)
+#include "components/ui_devtools/views/window_element.h"
+#include "ui/aura/client/window_parenting_client.h"
+#include "ui/aura/env.h"
+#include "ui/aura/window_tree_host.h"
+#endif  // defined(USE_AURA)
+
+namespace ui_devtools {
+namespace {
+
+using namespace ui_devtools::protocol;
+
+class TestView : public views::View {
+ public:
+  TestView(const char* name) : name_(name) {}
+
+  const char* GetClassName() const override { return name_; }
+
+ private:
+  const char* name_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestView);
+};
+
+std::string GetAttributeValue(const std::string& attribute, DOM::Node* node) {
+  EXPECT_TRUE(node->hasAttributes());
+  Array<std::string>* attributes = node->getAttributes(nullptr);
+  for (size_t i = 0; i < attributes->length() - 1; i++) {
+    if (attributes->get(i) == attribute)
+      return attributes->get(i + 1);
+  }
+  return std::string();
+}
+
+DOM::Node* FindNodeWithID(int id, DOM::Node* root) {
+  if (id == root->getNodeId()) {
+    return root;
+  }
+  Array<DOM::Node>* children = root->getChildren(nullptr);
+  for (size_t i = 0; i < children->length(); i++) {
+    if (DOM::Node* node = FindNodeWithID(id, children->get(i)))
+      return node;
+  }
+  return nullptr;
+}
+
+}  // namespace
+
+class DOMAgentTest : public views::ViewsTestBase {
+ public:
+  DOMAgentTest() {}
+  ~DOMAgentTest() override {}
+
+  views::internal::NativeWidgetPrivate* CreateTestNativeWidget() {
+    views::Widget* widget = new views::Widget;
+    views::Widget::InitParams params;
+    params.ownership = views::Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET;
+    params.parent = GetContext();
+    widget->Init(params);
+    return widget->native_widget_private();
+  }
+
+  std::unique_ptr<views::Widget> CreateTestWidget(const gfx::Rect& bounds) {
+    auto widget = std::make_unique<views::Widget>();
+    views::Widget::InitParams params;
+    params.delegate = nullptr;
+    params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+    params.bounds = bounds;
+    params.parent = GetContext();
+    widget->Init(params);
+    widget->Show();
+    return widget;
+  }
+
+  std::unique_ptr<aura::Window> CreateChildWindow(
+      aura::Window* parent,
+      aura::client::WindowType type = aura::client::WINDOW_TYPE_NORMAL) {
+    std::unique_ptr<aura::Window> window =
+        std::make_unique<aura::Window>(nullptr, type);
+    window->Init(ui::LAYER_NOT_DRAWN);
+    window->SetBounds(gfx::Rect());
+    parent->AddChild(window.get());
+    window->Show();
+    return window;
+  }
+
+  void SetUp() override {
+    fake_frontend_channel_ = std::make_unique<FakeFrontendChannel>();
+    uber_dispatcher_ =
+        std::make_unique<UberDispatcher>(fake_frontend_channel_.get());
+    aura::Env* env = aura::Env::GetInstance();
+    dom_agent_ = std::make_unique<DOMAgentAura>(env);
+    dom_agent_->Init(uber_dispatcher_.get());
+    css_agent_ = std::make_unique<CSSAgent>(dom_agent_.get());
+    css_agent_->Init(uber_dispatcher_.get());
+    css_agent_->enable();
+    overlay_agent_ = std::make_unique<OverlayAgentAura>(dom_agent_.get(), env);
+    overlay_agent_->Init(uber_dispatcher_.get());
+    overlay_agent_->enable();
+
+    // We need to create |dom_agent| first to observe creation of
+    // WindowTreeHosts in ViewTestBase::SetUp().
+    views::ViewsTestBase::SetUp();
+
+    top_window = CreateChildWindow(GetContext());
+  }
+
+  void TearDown() override {
+    top_window.reset();
+    css_agent_.reset();
+    overlay_agent_.reset();
+    dom_agent_.reset();
+
+    uber_dispatcher_.reset();
+    fake_frontend_channel_.reset();
+    views::ViewsTestBase::TearDown();
+  }
+
+  template <typename T>
+  bool WasChildNodeInserted(T* parent, int previous_sibling_id = 0) {
+    const int parent_id = GetIDForBackendElement(parent);
+    return frontend_channel()->CountProtocolNotificationMessageStartsWith(
+               base::StringPrintf("{\"method\":\"DOM.childNodeInserted\","
+                                  "\"params\":{\"parentNodeId\":%d,"
+                                  "\"previousNodeId\":%d",
+                                  parent_id, previous_sibling_id)) == 1;
+  }
+  template <typename T, typename U>
+  bool WasChildNodeInserted(T* parent, U* previous_sibling) {
+    const int previous_sibling_id =
+        previous_sibling ? GetIDForBackendElement(previous_sibling) : 0;
+    return WasChildNodeInserted(parent, previous_sibling_id);
+  }
+
+  template <typename T>
+  bool WasChildNodeRemoved(T* parent, int node_id) {
+    const int parent_id = GetIDForBackendElement(parent);
+    return frontend_channel()->CountProtocolNotificationMessage(
+               base::StringPrintf(
+                   "{\"method\":\"DOM.childNodeRemoved\",\"params\":{"
+                   "\"parentNodeId\":%d,\"nodeId\":%d}}",
+                   parent_id, node_id)) == 1;
+  }
+
+  template <typename T>
+  int GetIDForBackendElement(T* element) {
+    return dom_agent()->element_root()->FindUIElementIdForBackendElement<T>(
+        element);
+  }
+
+  template <typename T>
+  DOM::Node* FindInRoot(T* element, DOM::Node* root) {
+    return FindNodeWithID(GetIDForBackendElement(element), root);
+  }
+
+  // The following three methods test that a tree of DOM::Node exactly
+  // corresponds 1:1 with a views/Aura hierarchy
+
+#if defined(USE_AURA)
+  bool ElementTreeMatchesDOMTree(aura::Window* window, DOM::Node* root) {
+    if (GetIDForBackendElement(window) != root->getNodeId() ||
+        "Window" != root->getNodeName() ||
+        window->GetName() != GetAttributeValue("name", root)) {
+      return false;
+    }
+
+    Array<DOM::Node>* children = root->getChildren(nullptr);
+    size_t child_index = 0;
+    views::Widget* widget = views::Widget::GetWidgetForNativeView(window);
+    if (widget &&
+        !ElementTreeMatchesDOMTree(widget, children->get(child_index++))) {
+      return false;
+    }
+    for (aura::Window* child_window : window->children()) {
+      if (!ElementTreeMatchesDOMTree(child_window,
+                                     children->get(child_index++)))
+        return false;
+    }
+    // Make sure there are no stray children.
+    return child_index == children->length();
+  }
+#endif
+
+  bool ElementTreeMatchesDOMTree(views::Widget* widget, DOM::Node* root) {
+    if (GetIDForBackendElement(widget) != root->getNodeId() ||
+        "Widget" != root->getNodeName() ||
+        widget->GetName() != GetAttributeValue("name", root)) {
+      return false;
+    }
+
+    Array<DOM::Node>* children = root->getChildren(nullptr);
+    views::View* root_view = widget->GetRootView();
+    if (!root_view)
+      return children->length() == 0;
+    else
+      return ElementTreeMatchesDOMTree(root_view, children->get(0));
+  }
+
+  bool ElementTreeMatchesDOMTree(views::View* view, DOM::Node* root) {
+    if (GetIDForBackendElement(view) != root->getNodeId() ||
+        "View" != root->getNodeName() ||
+        view->GetClassName() != GetAttributeValue("name", root)) {
+      return false;
+    }
+
+    Array<DOM::Node>* children = root->getChildren(nullptr);
+    std::vector<views::View*> child_views = view->GetChildrenInZOrder();
+    const size_t child_count = child_views.size();
+    if (child_count != children->length())
+      return false;
+
+    for (size_t i = 0; i < child_count; i++) {
+      if (!ElementTreeMatchesDOMTree(child_views[i], children->get(i)))
+        return false;
+    }
+    return true;
+  }
+
+  FakeFrontendChannel* frontend_channel() {
+    return fake_frontend_channel_.get();
+  }
+  DOMAgentAura* dom_agent() { return dom_agent_.get(); }
+
+  std::unique_ptr<aura::Window> top_window;
+
+ private:
+  std::unique_ptr<UberDispatcher> uber_dispatcher_;
+  std::unique_ptr<FakeFrontendChannel> fake_frontend_channel_;
+  std::unique_ptr<DOMAgentAura> dom_agent_;
+  std::unique_ptr<CSSAgent> css_agent_;
+  std::unique_ptr<OverlayAgentAura> overlay_agent_;
+
+  DISALLOW_COPY_AND_ASSIGN(DOMAgentTest);
+};
+
+// Tests to ensure that the DOMAgent's hierarchy matches the real hierarchy.
+#if defined(USE_AURA)
+
+TEST_F(DOMAgentTest, GetDocumentWithWindowWidgetView) {
+  // parent_window
+  //   widget
+  //     (root/content views)
+  //        child_view
+  //   child_window
+  std::unique_ptr<views::Widget> widget(
+      CreateTestWidget(gfx::Rect(1, 1, 1, 1)));
+  aura::Window* parent_window = widget->GetNativeWindow();
+  parent_window->SetName("parent_window");
+  std::unique_ptr<aura::Window> child_window = CreateChildWindow(parent_window);
+  child_window->SetName("child_window");
+  widget->Show();
+  views::View* child_view = new TestView("child_view");
+  widget->GetRootView()->AddChildView(child_view);
+
+  std::unique_ptr<DOM::Node> root;
+  dom_agent()->getDocument(&root);
+
+  DOM::Node* parent_node = FindInRoot(parent_window, root.get());
+  DCHECK(parent_node);
+
+  EXPECT_TRUE(ElementTreeMatchesDOMTree(parent_window, parent_node));
+}
+
+TEST_F(DOMAgentTest, GetDocumentNativeWidgetOwnsWidget) {
+  views::internal::NativeWidgetPrivate* native_widget_private =
+      CreateTestNativeWidget();
+  views::Widget* widget = native_widget_private->GetWidget();
+  aura::Window* parent_window = widget->GetNativeWindow();
+
+  std::unique_ptr<DOM::Node> root;
+  dom_agent()->getDocument(&root);
+
+  DOM::Node* parent_node = FindInRoot(parent_window, root.get());
+  DCHECK(parent_node);
+
+  EXPECT_TRUE(ElementTreeMatchesDOMTree(parent_window, parent_node));
+  // Destroy NativeWidget followed by |widget|
+  widget->CloseNow();
+}
+
+#endif  // defined(USE_AURA)
+
+TEST_F(DOMAgentTest, GetDocumentMultipleWidgets) {
+  // widget_a
+  //   (root/contents views)
+  //     child_a1
+  //     child_a2
+  // widget_b
+  //   (root/contents views)
+  //      child_b1
+  //        child_b11
+  //          child_b111
+  //            child_b1111
+  //          child_b112
+  //          child_b113
+  //        child_b12
+  //          child_b121
+  //          child_b122
+  std::unique_ptr<views::Widget> widget_a(
+      CreateTestWidget(gfx::Rect(1, 1, 1, 1)));
+  std::unique_ptr<views::Widget> widget_b(
+      CreateTestWidget(gfx::Rect(100, 100, 1, 1)));
+
+  widget_a->GetRootView()->AddChildView(new TestView("child_a1"));
+  widget_a->GetRootView()->AddChildView(new TestView("child_a2"));
+
+  auto child_b1 = std::make_unique<TestView>("child_b1");
+  child_b1->set_owned_by_client();
+  widget_b->GetRootView()->AddChildView(child_b1.get());
+
+  auto child_b11 = std::make_unique<TestView>("child_b11");
+  child_b11->set_owned_by_client();
+  child_b1->AddChildView(child_b11.get());
+
+  auto child_b111 = std::make_unique<TestView>("child_b111");
+  child_b111->set_owned_by_client();
+  child_b11->AddChildView(child_b111.get());
+  child_b111->AddChildView(new TestView("child_b1111"));
+
+  child_b11->AddChildView(new TestView("child_b112"));
+  child_b11->AddChildView(new TestView("child_b113"));
+
+  auto child_b12 = std::make_unique<TestView>("child_b12");
+  child_b12->set_owned_by_client();
+  child_b1->AddChildView(child_b12.get());
+  child_b12->AddChildView(new TestView("child_b121"));
+  child_b12->AddChildView(new TestView("child_b122"));
+
+  std::unique_ptr<DOM::Node> root;
+  dom_agent()->getDocument(&root);
+
+  DOM::Node* widget_node_a = FindInRoot(widget_a.get(), root.get());
+  DCHECK(widget_node_a);
+
+  EXPECT_TRUE(ElementTreeMatchesDOMTree(widget_a.get(), widget_node_a));
+
+  DOM::Node* widget_node_b = FindInRoot(widget_b.get(), root.get());
+  DCHECK(widget_node_b);
+
+  EXPECT_TRUE(ElementTreeMatchesDOMTree(widget_b.get(), widget_node_b));
+}
+
+// Tests to ensure correct messages are sent when elements are added,
+// removed, and moved around.
+
+#if defined(USE_AURA)
+TEST_F(DOMAgentTest, WindowAddedChildNodeInserted) {
+  // Initialize DOMAgent
+  std::unique_ptr<aura::Window> first_child =
+      CreateChildWindow(top_window.get());
+
+  std::unique_ptr<DOM::Node> root;
+  dom_agent()->getDocument(&root);
+
+  std::unique_ptr<aura::Window> second_child(
+      CreateChildWindow(top_window.get()));
+  EXPECT_TRUE(WasChildNodeInserted(top_window.get(), first_child.get()));
+}
+
+TEST_F(DOMAgentTest, WindowDestroyedChildNodeRemoved) {
+  std::unique_ptr<aura::Window> child_1 = CreateChildWindow(top_window.get());
+  std::unique_ptr<aura::Window> child_2 = CreateChildWindow(child_1.get());
+
+  // Initialize DOMAgent
+  std::unique_ptr<DOM::Node> root;
+  dom_agent()->getDocument(&root);
+
+  int child_id = GetIDForBackendElement(child_2.get());
+
+  child_2.reset();
+  EXPECT_TRUE(WasChildNodeRemoved(child_1.get(), child_id));
+}
+
+TEST_F(DOMAgentTest, WindowReorganizedChildNodeRearranged) {
+  std::unique_ptr<aura::Window> child_1 = CreateChildWindow(top_window.get());
+  std::unique_ptr<aura::Window> child_2 = CreateChildWindow(top_window.get());
+  std::unique_ptr<aura::Window> child_11 = CreateChildWindow(child_1.get());
+  std::unique_ptr<aura::Window> child_21 = CreateChildWindow(child_2.get());
+
+  // Initialize DOMAgent
+  std::unique_ptr<DOM::Node> root;
+  dom_agent()->getDocument(&root);
+
+  int moving_child_id = GetIDForBackendElement(child_11.get());
+  child_2->AddChild(child_11.get());
+  EXPECT_TRUE(WasChildNodeRemoved(child_1.get(), moving_child_id));
+  EXPECT_TRUE(WasChildNodeInserted(child_2.get(), child_21.get()));
+}
+
+TEST_F(DOMAgentTest, WindowReorganizedChildNodeRemovedAndInserted) {
+  std::unique_ptr<aura::Window> child_1 = CreateChildWindow(top_window.get());
+  std::unique_ptr<aura::Window> child_2 = CreateChildWindow(top_window.get());
+  std::unique_ptr<aura::Window> child_21 = CreateChildWindow(child_2.get());
+  std::unique_ptr<aura::Window> child_22 = CreateChildWindow(child_2.get());
+  // Initialized at the end since it will be a child of |child_2| at
+  // tear down.
+  std::unique_ptr<aura::Window> child_11 = CreateChildWindow(child_1.get());
+
+  // Initialize DOMAgent
+  std::unique_ptr<DOM::Node> root;
+  dom_agent()->getDocument(&root);
+
+  int moving_child_id = GetIDForBackendElement(child_11.get());
+
+  child_1->RemoveChild(child_11.get());
+  EXPECT_TRUE(WasChildNodeRemoved(child_1.get(), moving_child_id));
+
+  child_2->AddChild(child_11.get());
+  EXPECT_TRUE(WasChildNodeInserted(child_2.get(), child_22.get()));
+}
+
+TEST_F(DOMAgentTest, WindowStackingChangedChildNodeRemovedAndInserted) {
+  std::unique_ptr<aura::Window> child_11 = CreateChildWindow(top_window.get());
+  std::unique_ptr<aura::Window> child_12 = CreateChildWindow(top_window.get());
+  std::unique_ptr<aura::Window> child_13 = CreateChildWindow(top_window.get());
+
+  // Initialize DOMAgent
+  std::unique_ptr<DOM::Node> root;
+  dom_agent()->getDocument(&root);
+
+  int moving_child_id = GetIDForBackendElement(child_11.get());
+  top_window->StackChildAbove(child_11.get(), child_12.get());
+  EXPECT_TRUE(WasChildNodeRemoved(top_window.get(), moving_child_id));
+  EXPECT_TRUE(WasChildNodeInserted(top_window.get(), child_12.get()));
+}
+#endif  // defined(USE_AURA)
+
+TEST_F(DOMAgentTest, ViewInserted) {
+  std::unique_ptr<views::Widget> widget(
+      CreateTestWidget(gfx::Rect(1, 1, 1, 1)));
+  widget->Show();
+
+  // Initialize DOMAgent
+  std::unique_ptr<DOM::Node> root;
+  dom_agent()->getDocument(&root);
+
+  views::View* root_view = widget->GetRootView();
+  root_view->AddChildView(new views::View);
+  EXPECT_TRUE(WasChildNodeInserted(root_view, root_view->child_at(0)));
+}
+
+TEST_F(DOMAgentTest, ViewRemoved) {
+  std::unique_ptr<views::Widget> widget(
+      CreateTestWidget(gfx::Rect(1, 1, 1, 1)));
+  widget->Show();
+  views::View* root_view = widget->GetRootView();
+
+  // Need to store |child_view| in unique_ptr because it is removed from the
+  // widget and needs to be destroyed independently
+  std::unique_ptr<views::View> child_view = std::make_unique<views::View>();
+  root_view->AddChildView(child_view.get());
+
+  // Initialize DOMAgent
+  std::unique_ptr<DOM::Node> root;
+  dom_agent()->getDocument(&root);
+
+  int removed_node_id = GetIDForBackendElement(child_view.get());
+  root_view->RemoveChildView(child_view.get());
+  EXPECT_TRUE(WasChildNodeRemoved(root_view, removed_node_id));
+}
+
+TEST_F(DOMAgentTest, ViewRearranged) {
+  std::unique_ptr<views::Widget> widget(
+      CreateTestWidget(gfx::Rect(1, 1, 1, 1)));
+
+  widget->Show();
+  views::View* root_view = widget->GetRootView();
+  views::View* parent_view = new views::View;
+  views::View* target_view = new views::View;
+  views::View* child_view = new views::View;
+  views::View* child_view_1 = new views::View;
+
+  root_view->AddChildView(parent_view);
+  root_view->AddChildView(target_view);
+  parent_view->AddChildView(child_view);
+  parent_view->AddChildView(child_view_1);
+
+  // Initialize DOMAgent
+  std::unique_ptr<DOM::Node> root;
+  dom_agent()->getDocument(&root);
+
+  // Reorder child_view_1 from index 1 to 0 in view::Views tree. This makes
+  // DOM tree remove view node at position 1 and insert it at position 0.
+  int child_1_id = GetIDForBackendElement(child_view_1);
+  parent_view->ReorderChildView(child_view_1, 0);
+  EXPECT_TRUE(WasChildNodeRemoved(parent_view, child_1_id));
+  EXPECT_TRUE(WasChildNodeInserted(parent_view));
+
+  // Reorder child_view_1 to the same index 0 shouldn't perform reroder
+  // work, so we still expect 1 remove and 1 insert protocol notification
+  // messages.
+  parent_view->ReorderChildView(child_view_1, 0);
+  EXPECT_TRUE(WasChildNodeRemoved(parent_view, child_1_id));
+  EXPECT_TRUE(WasChildNodeInserted(parent_view));
+
+  int child_id = GetIDForBackendElement(child_view);
+  target_view->AddChildView(child_view);
+  EXPECT_TRUE(WasChildNodeRemoved(parent_view, child_id));
+  EXPECT_TRUE(WasChildNodeInserted(target_view));
+}
+
+TEST_F(DOMAgentTest, ViewRearrangedRemovedAndInserted) {
+  std::unique_ptr<views::Widget> widget(
+      CreateTestWidget(gfx::Rect(1, 1, 1, 1)));
+
+  widget->Show();
+  views::View* root_view = widget->GetRootView();
+  views::View* parent_view = new views::View;
+  views::View* target_view = new views::View;
+  views::View* child_view = new views::View;
+  root_view->AddChildView(parent_view);
+  root_view->AddChildView(target_view);
+  parent_view->AddChildView(child_view);
+
+  // Initialize DOMAgent
+  std::unique_ptr<DOM::Node> root;
+  dom_agent()->getDocument(&root);
+
+  int child_id = GetIDForBackendElement(child_view);
+  parent_view->RemoveChildView(child_view);
+  target_view->AddChildView(child_view);
+  EXPECT_TRUE(WasChildNodeRemoved(parent_view, child_id));
+  EXPECT_TRUE(WasChildNodeInserted(target_view));
+}
+
+}  // namespace ui_devtools
diff --git a/components/ui_devtools/views/ui_devtools_unittest.cc b/components/ui_devtools/views/ui_devtools_unittest.cc
deleted file mode 100644
index f5c9d85..0000000
--- a/components/ui_devtools/views/ui_devtools_unittest.cc
+++ /dev/null
@@ -1,555 +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 <memory>
-
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "components/ui_devtools/css_agent.h"
-#include "components/ui_devtools/ui_devtools_unittest_utils.h"
-#include "components/ui_devtools/ui_element.h"
-#include "components/ui_devtools/views/dom_agent_aura.h"
-#include "components/ui_devtools/views/overlay_agent_aura.h"
-#include "components/ui_devtools/views/view_element.h"
-#include "components/ui_devtools/views/widget_element.h"
-#include "components/ui_devtools/views/window_element.h"
-#include "ui/aura/client/window_parenting_client.h"
-#include "ui/aura/env.h"
-#include "ui/aura/window_tree_host.h"
-#include "ui/views/test/views_test_base.h"
-#include "ui/views/widget/native_widget_private.h"
-#include "ui/views/widget/widget.h"
-#include "ui/wm/core/coordinate_conversion.h"
-
-namespace ui_devtools {
-namespace {
-
-using namespace ui_devtools::protocol;
-
-const int kDefaultChildNodeCount = -1;
-
-class TestView : public views::View {
- public:
-  TestView(const char* name) : name_(name) {}
-
-  const char* GetClassName() const override { return name_; }
-
- private:
-  const char* name_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestView);
-};
-
-std::string GetAttributeValue(const std::string& attribute, DOM::Node* node) {
-  EXPECT_TRUE(node->hasAttributes());
-  Array<std::string>* attributes = node->getAttributes(nullptr);
-  for (size_t i = 0; i < attributes->length() - 1; i++) {
-    if (attributes->get(i) == attribute)
-      return attributes->get(i + 1);
-  }
-  return nullptr;
-}
-
-bool Equals(aura::Window* window, DOM::Node* node) {
-  int children_count = static_cast<int>(window->children().size());
-  if (views::Widget::GetWidgetForNativeView(window))
-    children_count++;
-  return "Window" == node->getNodeName() &&
-         window->GetName() == GetAttributeValue("name", node) &&
-         children_count == node->getChildNodeCount(kDefaultChildNodeCount);
-}
-
-void Compare(views::Widget* widget, DOM::Node* node) {
-  EXPECT_EQ("Widget", node->getNodeName());
-  EXPECT_EQ(widget->GetName(), GetAttributeValue("name", node));
-  EXPECT_EQ(widget->GetRootView() ? 1 : 0,
-            node->getChildNodeCount(kDefaultChildNodeCount));
-}
-
-void Compare(views::View* view, DOM::Node* node) {
-  EXPECT_EQ("View", node->getNodeName());
-  EXPECT_EQ(view->GetClassName(), GetAttributeValue("name", node));
-  EXPECT_EQ(view->child_count(),
-            node->getChildNodeCount(kDefaultChildNodeCount));
-}
-
-void Compare(aura::Window* window, DOM::Node* node) {
-  EXPECT_TRUE(Equals(window, node));
-}
-
-DOM::Node* FindInRoot(aura::Window* window, DOM::Node* root) {
-  if (Equals(window, root))
-    return root;
-
-  Array<DOM::Node>* children = root->getChildren(nullptr);
-  DOM::Node* window_node = nullptr;
-  for (size_t i = 0; i < children->length(); i++) {
-    window_node = FindInRoot(window, children->get(i));
-    if (window_node)
-      return window_node;
-  }
-  return window_node;
-}
-
-}  // namespace
-
-class UIDevToolsTest : public views::ViewsTestBase {
- public:
-  UIDevToolsTest() {}
-  ~UIDevToolsTest() override {}
-
-  views::internal::NativeWidgetPrivate* CreateTestNativeWidget() {
-    views::Widget* widget = new views::Widget;
-    views::Widget::InitParams params;
-    params.ownership = views::Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET;
-    params.parent = GetPrimaryRootWindow();
-    widget->Init(params);
-    return widget->native_widget_private();
-  }
-
-  std::unique_ptr<views::Widget> CreateTestWidget(const gfx::Rect& bounds) {
-    std::unique_ptr<views::Widget> widget(new views::Widget);
-    views::Widget::InitParams params;
-    params.delegate = nullptr;
-    params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
-    params.bounds = bounds;
-    params.parent = GetPrimaryRootWindow();
-    widget->Init(params);
-    widget->Show();
-    return widget;
-  }
-
-  std::unique_ptr<aura::Window> CreateChildWindow(
-      aura::Window* parent,
-      aura::client::WindowType type = aura::client::WINDOW_TYPE_NORMAL) {
-    std::unique_ptr<aura::Window> window =
-        std::make_unique<aura::Window>(nullptr, type);
-    window->Init(ui::LAYER_NOT_DRAWN);
-    window->SetBounds(gfx::Rect());
-    parent->AddChild(window.get());
-    window->Show();
-    return window;
-  }
-
-  void SetUp() override {
-    fake_frontend_channel_ = std::make_unique<FakeFrontendChannel>();
-    uber_dispatcher_ =
-        std::make_unique<UberDispatcher>(fake_frontend_channel_.get());
-    aura::Env* env = aura::Env::GetInstance();
-    dom_agent_ = std::make_unique<DOMAgentAura>(env);
-    dom_agent_->Init(uber_dispatcher_.get());
-    css_agent_ = std::make_unique<CSSAgent>(dom_agent_.get());
-    css_agent_->Init(uber_dispatcher_.get());
-    css_agent_->enable();
-    overlay_agent_ = std::make_unique<OverlayAgentAura>(dom_agent_.get(), env);
-    overlay_agent_->Init(uber_dispatcher_.get());
-    overlay_agent_->enable();
-
-    // We need to create |dom_agent| first to observe creation of
-    // WindowTreeHosts in ViewTestBase::SetUp().
-    views::ViewsTestBase::SetUp();
-
-    top_window = CreateChildWindow(GetPrimaryRootWindow());
-    top_default_container_window = CreateChildWindow(GetPrimaryRootWindow());
-    top_overlay_window = CreateChildWindow(GetPrimaryRootWindow(),
-                                           aura::client::WINDOW_TYPE_UNKNOWN);
-  }
-
-  void TearDown() override {
-    top_overlay_window.reset();
-    top_default_container_window.reset();
-    top_window.reset();
-    css_agent_.reset();
-    overlay_agent_.reset();
-    dom_agent_.reset();
-    uber_dispatcher_.reset();
-    fake_frontend_channel_.reset();
-    views::ViewsTestBase::TearDown();
-  }
-
-  void ExpectChildNodeInserted(int parent_id, int prev_sibling_id) {
-    EXPECT_EQ(1, frontend_channel()->CountProtocolNotificationMessageStartsWith(
-                     base::StringPrintf("{\"method\":\"DOM.childNodeInserted\","
-                                        "\"params\":{\"parentNodeId\":%d,"
-                                        "\"previousNodeId\":%d",
-                                        parent_id, prev_sibling_id)));
-  }
-
-  void ExpectChildNodeRemoved(int parent_id, int node_id) {
-    EXPECT_EQ(1, frontend_channel()->CountProtocolNotificationMessage(
-                     base::StringPrintf(
-                         "{\"method\":\"DOM.childNodeRemoved\",\"params\":{"
-                         "\"parentNodeId\":%d,\"nodeId\":%d}}",
-                         parent_id, node_id)));
-  }
-
-  FakeFrontendChannel* frontend_channel() {
-    return fake_frontend_channel_.get();
-  }
-
-  aura::Window* GetPrimaryRootWindow() {
-    DCHECK(dom_agent()->root_windows().size());
-    return dom_agent()->root_windows()[0];
-  }
-
-  CSSAgent* css_agent() { return css_agent_.get(); }
-  DOMAgentAura* dom_agent() { return dom_agent_.get(); }
-  OverlayAgentAura* overlay_agent() { return overlay_agent_.get(); }
-
-  std::unique_ptr<aura::Window> top_overlay_window;
-  std::unique_ptr<aura::Window> top_window;
-  std::unique_ptr<aura::Window> top_default_container_window;
-
- private:
-  std::unique_ptr<UberDispatcher> uber_dispatcher_;
-  std::unique_ptr<FakeFrontendChannel> fake_frontend_channel_;
-  std::unique_ptr<DOMAgentAura> dom_agent_;
-  std::unique_ptr<CSSAgent> css_agent_;
-  std::unique_ptr<OverlayAgentAura> overlay_agent_;
-
-  DISALLOW_COPY_AND_ASSIGN(UIDevToolsTest);
-};
-
-
-TEST_F(UIDevToolsTest, GetDocumentWithWindowWidgetView) {
-  std::unique_ptr<views::Widget> widget(
-      CreateTestWidget(gfx::Rect(1, 1, 1, 1)));
-  aura::Window* parent_window = widget->GetNativeWindow();
-  parent_window->SetName("parent_window");
-  std::unique_ptr<aura::Window> child_window = CreateChildWindow(parent_window);
-  child_window->SetName("child_window");
-  widget->Show();
-  views::View* child_view = new TestView("child_view");
-  widget->GetRootView()->AddChildView(child_view);
-
-  std::unique_ptr<DOM::Node> root;
-  dom_agent()->getDocument(&root);
-
-  DOM::Node* parent_node = FindInRoot(parent_window, root.get());
-  ASSERT_TRUE(parent_node);
-  Array<DOM::Node>* parent_children = parent_node->getChildren(nullptr);
-  ASSERT_TRUE(parent_children);
-  DOM::Node* widget_node = parent_children->get(0);
-  Compare(widget.get(), widget_node);
-  Compare(child_window.get(), parent_children->get(1));
-  Array<DOM::Node>* widget_children = widget_node->getChildren(nullptr);
-  ASSERT_TRUE(widget_children);
-  Compare(widget->GetRootView(), widget_children->get(0));
-  ASSERT_TRUE(widget_children->get(0)->getChildren(nullptr));
-  Compare(child_view, widget_children->get(0)->getChildren(nullptr)->get(1));
-}
-
-TEST_F(UIDevToolsTest, GetDocumentNativeWidgetOwnsWidget) {
-  views::internal::NativeWidgetPrivate* native_widget_private =
-      CreateTestNativeWidget();
-  views::Widget* widget = native_widget_private->GetWidget();
-  aura::Window* parent_window = widget->GetNativeWindow();
-
-  std::unique_ptr<DOM::Node> root;
-  dom_agent()->getDocument(&root);
-
-  DOM::Node* parent_node = FindInRoot(parent_window, root.get());
-  ASSERT_TRUE(parent_node);
-  DOM::Node* widget_node = parent_node->getChildren(nullptr)->get(0);
-  Compare(widget, widget_node);
-  // Destroy NativeWidget followed by |widget|
-  widget->CloseNow();
-}
-
-TEST_F(UIDevToolsTest, WindowAddedChildNodeInserted) {
-  // Initialize DOMAgent
-  std::unique_ptr<aura::Window> window_child =
-      CreateChildWindow(top_window.get());
-
-  std::unique_ptr<DOM::Node> root;
-  dom_agent()->getDocument(&root);
-
-  aura::Window* root_window = GetPrimaryRootWindow();
-  aura::Window* parent_window = root_window->children()[0];
-  DOM::Node* parent_node = FindInRoot(parent_window, root.get());
-  Array<DOM::Node>* parent_node_children = parent_node->getChildren(nullptr);
-  DOM::Node* sibling_node =
-      parent_node_children->get(parent_node_children->length() - 1);
-
-  std::unique_ptr<aura::Window> child(CreateChildWindow(parent_window));
-  ExpectChildNodeInserted(parent_node->getNodeId(), sibling_node->getNodeId());
-}
-
-TEST_F(UIDevToolsTest, WindowDestroyedChildNodeRemoved) {
-  std::unique_ptr<aura::Window> child_1 = CreateChildWindow(top_window.get());
-  std::unique_ptr<aura::Window> child_2 = CreateChildWindow(child_1.get());
-
-  // Initialize DOMAgent
-  std::unique_ptr<DOM::Node> root;
-  dom_agent()->getDocument(&root);
-
-  aura::Window* root_window = GetPrimaryRootWindow();
-  aura::Window* rotation_window = root_window->children()[0];
-  aura::Window* parent_window = rotation_window->children()[0];
-  aura::Window* child_window = parent_window->children()[0];
-  DOM::Node* root_node =
-      root->getChildren(nullptr)->get(0)->getChildren(nullptr)->get(0);
-  DOM::Node* parent_node = root_node->getChildren(nullptr)->get(0);
-  DOM::Node* child_node = parent_node->getChildren(nullptr)->get(0);
-
-  Compare(parent_window, parent_node);
-  Compare(child_window, child_node);
-  child_2.reset();
-  ExpectChildNodeRemoved(parent_node->getNodeId(), child_node->getNodeId());
-}
-
-TEST_F(UIDevToolsTest, WindowReorganizedChildNodeRearranged) {
-  std::unique_ptr<aura::Window> child_1 = CreateChildWindow(top_window.get());
-  std::unique_ptr<aura::Window> child_2 = CreateChildWindow(top_window.get());
-  std::unique_ptr<aura::Window> child_11 = CreateChildWindow(child_1.get());
-  std::unique_ptr<aura::Window> child_21 = CreateChildWindow(child_2.get());
-
-  // Initialize DOMAgent
-  std::unique_ptr<DOM::Node> root;
-  dom_agent()->getDocument(&root);
-
-  aura::Window* root_window = GetPrimaryRootWindow();
-  aura::Window* rotation_window = root_window->children()[0];
-  aura::Window* parent_window = rotation_window->children()[0];
-  aura::Window* target_window = rotation_window->children()[1];
-  aura::Window* child_window = parent_window->children()[0];
-
-  DOM::Node* root_node =
-      root->getChildren(nullptr)->get(0)->getChildren(nullptr)->get(0);
-  DOM::Node* parent_node = root_node->getChildren(nullptr)->get(0);
-  DOM::Node* target_node = root_node->getChildren(nullptr)->get(1);
-  Array<DOM::Node>* target_node_children = target_node->getChildren(nullptr);
-  DOM::Node* sibling_node =
-      target_node_children->get(target_node_children->length() - 1);
-  DOM::Node* child_node = parent_node->getChildren(nullptr)->get(0);
-
-  Compare(parent_window, parent_node);
-  Compare(target_window, target_node);
-  Compare(child_window, child_node);
-  target_window->AddChild(child_window);
-  ExpectChildNodeRemoved(parent_node->getNodeId(), child_node->getNodeId());
-  ExpectChildNodeInserted(target_node->getNodeId(), sibling_node->getNodeId());
-}
-
-TEST_F(UIDevToolsTest, WindowReorganizedChildNodeRemovedAndInserted) {
-  std::unique_ptr<aura::Window> child_1 = CreateChildWindow(top_window.get());
-  std::unique_ptr<aura::Window> child_2 = CreateChildWindow(top_window.get());
-  std::unique_ptr<aura::Window> child_21 = CreateChildWindow(child_2.get());
-  std::unique_ptr<aura::Window> child_22 = CreateChildWindow(child_2.get());
-
-  aura::Window* root_window = GetPrimaryRootWindow();
-  aura::Window* rotation_window = root_window->children()[0];
-  aura::Window* parent_window = rotation_window->children()[0];
-  aura::Window* target_window = rotation_window->children()[1];
-  std::unique_ptr<aura::Window> child_window(CreateChildWindow(parent_window));
-
-  // Initialize DOMAgent
-  std::unique_ptr<DOM::Node> root;
-  dom_agent()->getDocument(&root);
-  DOM::Node* root_node =
-      root->getChildren(nullptr)->get(0)->getChildren(nullptr)->get(0);
-  DOM::Node* parent_node = root_node->getChildren(nullptr)->get(0);
-  DOM::Node* target_node = root_node->getChildren(nullptr)->get(1);
-  Array<DOM::Node>* target_node_children = target_node->getChildren(nullptr);
-  DOM::Node* sibling_node =
-      target_node_children->get(target_node_children->length() - 1);
-  Array<DOM::Node>* parent_node_children = parent_node->getChildren(nullptr);
-  DOM::Node* child_node =
-      parent_node_children->get(parent_node_children->length() - 1);
-
-  Compare(parent_window, parent_node);
-  Compare(target_window, target_node);
-  Compare(child_window.get(), child_node);
-  parent_window->RemoveChild(child_window.get());
-  target_window->AddChild(child_window.get());
-  ExpectChildNodeRemoved(parent_node->getNodeId(), child_node->getNodeId());
-  ExpectChildNodeInserted(target_node->getNodeId(), sibling_node->getNodeId());
-}
-
-TEST_F(UIDevToolsTest, WindowStackingChangedChildNodeRemovedAndInserted) {
-  std::unique_ptr<aura::Window> child_11 = CreateChildWindow(top_window.get());
-  std::unique_ptr<aura::Window> child_12 = CreateChildWindow(top_window.get());
-  std::unique_ptr<aura::Window> child_13 = CreateChildWindow(top_window.get());
-
-  // Initialize DOMAgent
-  std::unique_ptr<DOM::Node> root;
-  dom_agent()->getDocument(&root);
-
-  aura::Window* root_window = GetPrimaryRootWindow();
-  aura::Window* parent_window = root_window->children()[0];
-  aura::Window* child_window = parent_window->children()[0];
-  aura::Window* target_window = parent_window->children()[1];
-
-  DOM::Node* parent_node =
-      root->getChildren(nullptr)->get(0)->getChildren(nullptr)->get(0);
-  Array<DOM::Node>* parent_node_children = parent_node->getChildren(nullptr);
-  DOM::Node* child_node = parent_node_children->get(0);
-  DOM::Node* sibling_node = parent_node_children->get(1);
-  int parent_id = parent_node->getNodeId();
-
-  Compare(parent_window, parent_node);
-  Compare(child_window, child_node);
-  parent_window->StackChildAbove(child_window, target_window);
-  ExpectChildNodeRemoved(parent_id, child_node->getNodeId());
-  ExpectChildNodeInserted(parent_id, sibling_node->getNodeId());
-}
-
-TEST_F(UIDevToolsTest, ViewInserted) {
-  std::unique_ptr<views::Widget> widget(
-      CreateTestWidget(gfx::Rect(1, 1, 1, 1)));
-  aura::Window* window = widget->GetNativeWindow();
-  widget->Show();
-
-  // Initialize DOMAgent
-  std::unique_ptr<DOM::Node> root;
-  dom_agent()->getDocument(&root);
-
-  DOM::Node* parent_node = FindInRoot(window, root.get());
-  ASSERT_TRUE(parent_node);
-  DOM::Node* widget_node = parent_node->getChildren(nullptr)->get(0);
-  DOM::Node* root_view_node = widget_node->getChildren(nullptr)->get(0);
-  Array<DOM::Node>* root_view_children = root_view_node->getChildren(nullptr);
-  ASSERT_TRUE(root_view_children);
-  DOM::Node* sibling_view_node =
-      root_view_children->get(root_view_children->length() - 1);
-
-  widget->GetRootView()->AddChildView(new views::View);
-  ExpectChildNodeInserted(root_view_node->getNodeId(),
-                          sibling_view_node->getNodeId());
-}
-
-TEST_F(UIDevToolsTest, ViewRemoved) {
-  std::unique_ptr<views::Widget> widget(
-      CreateTestWidget(gfx::Rect(1, 1, 1, 1)));
-  // Need to store |view| in unique_ptr because it is removed from the widget
-  // and needs to be destroyed independently
-  std::unique_ptr<views::View> child_view = std::make_unique<views::View>();
-  aura::Window* window = widget->GetNativeWindow();
-  widget->Show();
-  views::View* root_view = widget->GetRootView();
-  root_view->AddChildView(child_view.get());
-
-  // Initialize DOMAgent
-  std::unique_ptr<DOM::Node> root;
-  dom_agent()->getDocument(&root);
-
-  DOM::Node* parent_node = FindInRoot(window, root.get());
-  ASSERT_TRUE(parent_node);
-  DOM::Node* widget_node = parent_node->getChildren(nullptr)->get(0);
-  DOM::Node* root_view_node = widget_node->getChildren(nullptr)->get(0);
-  Array<DOM::Node>* root_view_children = root_view_node->getChildren(nullptr);
-  ASSERT_TRUE(root_view_children);
-  DOM::Node* child_view_node =
-      root_view_children->get(root_view_children->length() - 1);
-
-  Compare(child_view.get(), child_view_node);
-  root_view->RemoveChildView(child_view.get());
-  ExpectChildNodeRemoved(root_view_node->getNodeId(),
-                         child_view_node->getNodeId());
-}
-
-TEST_F(UIDevToolsTest, ViewRearranged) {
-  std::unique_ptr<views::Widget> widget(
-      CreateTestWidget(gfx::Rect(1, 1, 1, 1)));
-  aura::Window* window = widget->GetNativeWindow();
-  widget->Show();
-  views::View* root_view = widget->GetRootView();
-  views::View* parent_view = new views::View;
-  views::View* target_view = new views::View;
-  views::View* child_view = new views::View;
-  views::View* child_view_1 = new views::View;
-
-  root_view->AddChildView(parent_view);
-  root_view->AddChildView(target_view);
-  parent_view->AddChildView(child_view);
-  parent_view->AddChildView(child_view_1);
-
-  // Initialize DOMAgent
-  std::unique_ptr<DOM::Node> root;
-  dom_agent()->getDocument(&root);
-
-  DOM::Node* parent_node = FindInRoot(window, root.get());
-  ASSERT_TRUE(parent_node);
-  DOM::Node* widget_node = parent_node->getChildren(nullptr)->get(0);
-  DOM::Node* root_view_node = widget_node->getChildren(nullptr)->get(0);
-  Array<DOM::Node>* root_view_children = root_view_node->getChildren(nullptr);
-  ASSERT_TRUE(root_view_children);
-  size_t root_children_size = root_view_children->length();
-  ASSERT_TRUE(root_children_size >= 2);
-  DOM::Node* parent_view_node = root_view_children->get(root_children_size - 2);
-  DOM::Node* target_view_node = root_view_children->get(root_children_size - 1);
-  DOM::Node* child_view_node = parent_view_node->getChildren(nullptr)->get(0);
-  DOM::Node* child_view_node_1 = parent_view_node->getChildren(nullptr)->get(1);
-
-  Compare(parent_view, parent_view_node);
-  Compare(target_view, target_view_node);
-  Compare(child_view, child_view_node);
-  Compare(child_view_1, child_view_node_1);
-
-  ASSERT_NE(child_view_node->getNodeId(), child_view_node_1->getNodeId());
-
-  // Reorder child_view_1 from index 1 to 0 in view::Views tree. This makes DOM
-  // tree remove view node at position 1 and insert it at position 0.
-  parent_view->ReorderChildView(child_view_1, 0);
-  ExpectChildNodeRemoved(parent_view_node->getNodeId(),
-                         child_view_node_1->getNodeId());
-  ExpectChildNodeInserted(parent_view_node->getNodeId(), 0);
-
-  // Reorder child_view_1 to the same index 0 shouldn't perform reroder work, so
-  // we still expect 1 remove and 1 insert protocol notification messages.
-  parent_view->ReorderChildView(child_view_1, 0);
-  ExpectChildNodeRemoved(parent_view_node->getNodeId(),
-                         child_view_node_1->getNodeId());
-  ExpectChildNodeInserted(parent_view_node->getNodeId(), 0);
-
-  target_view->AddChildView(child_view);
-  ExpectChildNodeRemoved(parent_view_node->getNodeId(),
-                         child_view_node->getNodeId());
-  ExpectChildNodeInserted(target_view_node->getNodeId(), 0);
-}
-
-TEST_F(UIDevToolsTest, ViewRearrangedRemovedAndInserted) {
-  std::unique_ptr<views::Widget> widget(
-      CreateTestWidget(gfx::Rect(1, 1, 1, 1)));
-  aura::Window* window = widget->GetNativeWindow();
-  widget->Show();
-  views::View* root_view = widget->GetRootView();
-  views::View* parent_view = new views::View;
-  views::View* target_view = new views::View;
-  views::View* child_view = new views::View;
-  root_view->AddChildView(parent_view);
-  root_view->AddChildView(target_view);
-  parent_view->AddChildView(child_view);
-
-  // Initialize DOMAgent
-  std::unique_ptr<DOM::Node> root;
-  dom_agent()->getDocument(&root);
-
-  DOM::Node* parent_node = FindInRoot(window, root.get());
-  ASSERT_TRUE(parent_node);
-  DOM::Node* widget_node = parent_node->getChildren(nullptr)->get(0);
-  DOM::Node* root_view_node = widget_node->getChildren(nullptr)->get(0);
-  Array<DOM::Node>* root_view_children = root_view_node->getChildren(nullptr);
-  ASSERT_TRUE(root_view_children);
-  size_t root_children_size = root_view_children->length();
-  ASSERT_TRUE(root_children_size >= 2);
-  DOM::Node* parent_view_node = root_view_children->get(root_children_size - 2);
-  DOM::Node* target_view_node = root_view_children->get(root_children_size - 1);
-  DOM::Node* child_view_node = parent_view_node->getChildren(nullptr)->get(0);
-
-  Compare(parent_view, parent_view_node);
-  Compare(target_view, target_view_node);
-  Compare(child_view, child_view_node);
-  parent_view->RemoveChildView(child_view);
-  target_view->AddChildView(child_view);
-  ExpectChildNodeRemoved(parent_view_node->getNodeId(),
-                         child_view_node->getNodeId());
-  ExpectChildNodeInserted(target_view_node->getNodeId(), 0);
-}
-
-
-// TODO(thanhph): Make test AshDevToolsTest.MultipleDisplayHighlight work with
-// multiple displays. https://crbug.com/726831.
-
-}  // namespace ui_devtools
diff --git a/components/viz/client/hit_test_data_provider_draw_quad.cc b/components/viz/client/hit_test_data_provider_draw_quad.cc
index 83927ee..220d9a67 100644
--- a/components/viz/client/hit_test_data_provider_draw_quad.cc
+++ b/components/viz/client/hit_test_data_provider_draw_quad.cc
@@ -43,6 +43,10 @@
         const SurfaceDrawQuad* surface_quad =
             SurfaceDrawQuad::MaterialCast(quad);
 
+        // Skip the quad if it has pointer-events:none set.
+        if (surface_quad->ignores_input_event)
+          continue;
+
         // Skip the quad if the FrameSinkId between fallback and primary is not
         // the same, because we don't know which FrameSinkId would be used to
         // draw this quad.
diff --git a/components/viz/client/hit_test_data_provider_draw_quad_unittest.cc b/components/viz/client/hit_test_data_provider_draw_quad_unittest.cc
index 9cbc521c..1db3643 100644
--- a/components/viz/client/hit_test_data_provider_draw_quad_unittest.cc
+++ b/components/viz/client/hit_test_data_provider_draw_quad_unittest.cc
@@ -50,7 +50,7 @@
   surface_quad->SetNew(
       pass->shared_quad_state_list.back(), child_rect, child_rect,
       SurfaceRange(fallback_child_surface_id, child_surface_id), SK_ColorWHITE,
-      false);
+      /*stretch_content_to_fill_bounds=*/false, /*ignores_input_event=*/false);
 
   return pass;
 }
diff --git a/components/viz/common/quads/draw_quad_unittest.cc b/components/viz/common/quads/draw_quad_unittest.cc
index f2d0d31..ceba6e7 100644
--- a/components/viz/common/quads/draw_quad_unittest.cc
+++ b/components/viz/common/quads/draw_quad_unittest.cc
@@ -287,16 +287,19 @@
 
   CREATE_QUAD_NEW(SurfaceDrawQuad, visible_rect,
                   SurfaceRange(fallback_surface_id, primary_surface_id),
-                  SK_ColorWHITE, true);
+                  SK_ColorWHITE, /*stretch_content_to_fill_bounds=*/true,
+                  /*ignores_input_event=*/true);
   EXPECT_EQ(DrawQuad::SURFACE_CONTENT, copy_quad->material);
   EXPECT_EQ(visible_rect, copy_quad->visible_rect);
   EXPECT_EQ(primary_surface_id, copy_quad->surface_range.end());
   EXPECT_EQ(fallback_surface_id, *copy_quad->surface_range.start());
   EXPECT_TRUE(copy_quad->stretch_content_to_fill_bounds);
+  EXPECT_TRUE(copy_quad->ignores_input_event);
 
   CREATE_QUAD_ALL(SurfaceDrawQuad,
                   SurfaceRange(fallback_surface_id, primary_surface_id),
-                  SK_ColorWHITE, false);
+                  SK_ColorWHITE, /*stretch_content_to_fill_bounds=*/false,
+                  /*ignores_input_event=*/false);
   EXPECT_EQ(DrawQuad::SURFACE_CONTENT, copy_quad->material);
   EXPECT_EQ(primary_surface_id, copy_quad->surface_range.end());
   EXPECT_EQ(fallback_surface_id, *copy_quad->surface_range.start());
@@ -583,7 +586,8 @@
   CREATE_SHARED_STATE();
   CREATE_QUAD_NEW(SurfaceDrawQuad, visible_rect,
                   SurfaceRange(base::nullopt, surface_id), SK_ColorWHITE,
-                  false);
+                  /*stretch_content_to_fill_bounds=*/false,
+                  /*ignores_input_event=*/false);
   EXPECT_EQ(0, IterateAndCount(quad_new));
 }
 
diff --git a/components/viz/common/quads/surface_draw_quad.cc b/components/viz/common/quads/surface_draw_quad.cc
index f59cae0..e16353e 100644
--- a/components/viz/common/quads/surface_draw_quad.cc
+++ b/components/viz/common/quads/surface_draw_quad.cc
@@ -25,13 +25,15 @@
                              const gfx::Rect& visible_rect,
                              const SurfaceRange& surface_range,
                              SkColor default_background_color,
-                             bool stretch_content_to_fill_bounds) {
+                             bool stretch_content_to_fill_bounds,
+                             bool ignores_input_event) {
   bool needs_blending = true;
   DrawQuad::SetAll(shared_quad_state, DrawQuad::SURFACE_CONTENT, rect,
                    visible_rect, needs_blending);
   this->surface_range = surface_range;
   this->default_background_color = default_background_color;
   this->stretch_content_to_fill_bounds = stretch_content_to_fill_bounds;
+  this->ignores_input_event = ignores_input_event;
 }
 
 void SurfaceDrawQuad::SetAll(const SharedQuadState* shared_quad_state,
@@ -40,12 +42,14 @@
                              bool needs_blending,
                              const SurfaceRange& surface_range,
                              SkColor default_background_color,
-                             bool stretch_content_to_fill_bounds) {
+                             bool stretch_content_to_fill_bounds,
+                             bool ignores_input_event) {
   DrawQuad::SetAll(shared_quad_state, DrawQuad::SURFACE_CONTENT, rect,
                    visible_rect, needs_blending);
   this->surface_range = surface_range;
   this->default_background_color = default_background_color;
   this->stretch_content_to_fill_bounds = stretch_content_to_fill_bounds;
+  this->ignores_input_event = ignores_input_event;
 }
 
 const SurfaceDrawQuad* SurfaceDrawQuad::MaterialCast(const DrawQuad* quad) {
diff --git a/components/viz/common/quads/surface_draw_quad.h b/components/viz/common/quads/surface_draw_quad.h
index d63abc1..17f3e60f 100644
--- a/components/viz/common/quads/surface_draw_quad.h
+++ b/components/viz/common/quads/surface_draw_quad.h
@@ -28,7 +28,8 @@
               const gfx::Rect& visible_rect,
               const SurfaceRange& surface_range,
               SkColor default_background_color,
-              bool stretch_content_to_fill_bounds);
+              bool stretch_content_to_fill_bounds,
+              bool ignores_input_event);
 
   void SetAll(const SharedQuadState* shared_quad_state,
               const gfx::Rect& rect,
@@ -36,11 +37,15 @@
               bool needs_blending,
               const SurfaceRange& surface_range,
               SkColor default_background_color,
-              bool stretch_content_to_fill_bounds);
+              bool stretch_content_to_fill_bounds,
+              bool ignores_input_event);
 
   SurfaceRange surface_range;
   SkColor default_background_color = SK_ColorWHITE;
   bool stretch_content_to_fill_bounds = false;
+  // TODO(crbug.com/914530): Remove once VizHitTestSurfaceLayer is enabled by
+  // default.
+  bool ignores_input_event = false;
 
   static const SurfaceDrawQuad* MaterialCast(const DrawQuad* quad);
 
diff --git a/components/viz/service/display/display.cc b/components/viz/service/display/display.cc
index 9b8780f..236611f 100644
--- a/components/viz/service/display/display.cc
+++ b/components/viz/service/display/display.cc
@@ -379,6 +379,16 @@
   // Run callbacks early to allow pipelining and collect presented callbacks.
   RunDrawCallbacks();
 
+  // Mark all the drawn surfaces, so that they can start receiving begin-frames.
+  const auto& undrawn_surfaces = aggregator_->undrawn_surfaces();
+  for (const auto& surface_id : aggregator_->previous_contained_surfaces()) {
+    if (undrawn_surfaces.count(surface_id.first))
+      continue;
+    Surface* surface = surface_manager_->GetSurfaceForId(surface_id.first);
+    if (surface)
+      surface->MarkAsDrawn();
+  }
+
   frame.metadata.latency_info.insert(frame.metadata.latency_info.end(),
                                      stored_latency_info_.begin(),
                                      stored_latency_info_.end());
@@ -605,7 +615,7 @@
     aggregator_->ReleaseResources(surface_id);
 }
 
-bool Display::SurfaceHasUndrawnFrame(const SurfaceId& surface_id) const {
+bool Display::SurfaceHasUnackedFrame(const SurfaceId& surface_id) const {
   if (!surface_manager_)
     return false;
 
@@ -613,7 +623,7 @@
   if (!surface)
     return false;
 
-  return surface->HasUndrawnActiveFrame();
+  return surface->HasUnackedActiveFrame();
 }
 
 void Display::DidFinishFrame(const BeginFrameAck& ack) {
@@ -823,7 +833,7 @@
   for (const auto& surface_id : surfaces_to_ack_on_next_draw_) {
     Surface* surface = surface_manager_->GetSurfaceForId(surface_id);
     if (surface)
-      surface->RunDrawCallback();
+      surface->SendAckToClient();
   }
   surfaces_to_ack_on_next_draw_.clear();
   // |surfaces_to_ack_on_next_draw_| does not cover surfaces that are being
@@ -832,7 +842,7 @@
     for (const auto& id_entry : aggregator_->previous_contained_surfaces()) {
       Surface* surface = surface_manager_->GetSurfaceForId(id_entry.first);
       if (surface)
-        surface->RunDrawCallback();
+        surface->SendAckToClient();
     }
   }
 }
diff --git a/components/viz/service/display/display.h b/components/viz/service/display/display.h
index 6d738d4..f5d58f6 100644
--- a/components/viz/service/display/display.h
+++ b/components/viz/service/display/display.h
@@ -99,7 +99,7 @@
 
   // DisplaySchedulerClient implementation.
   bool DrawAndSwap() override;
-  bool SurfaceHasUndrawnFrame(const SurfaceId& surface_id) const override;
+  bool SurfaceHasUnackedFrame(const SurfaceId& surface_id) const override;
   bool SurfaceDamaged(const SurfaceId& surface_id,
                       const BeginFrameAck& ack) override;
   void SurfaceDiscarded(const SurfaceId& surface_id) override;
diff --git a/components/viz/service/display/display_scheduler.cc b/components/viz/service/display/display_scheduler.cc
index 3d8ef719..aa7f3dd 100644
--- a/components/viz/service/display/display_scheduler.cc
+++ b/components/viz/service/display/display_scheduler.cc
@@ -182,9 +182,9 @@
       continue;
     }
 
-    // Surface is ready if there is an undrawn active CompositorFrame, because
+    // Surface is ready if there is an unacked active CompositorFrame, because
     // its producer is CompositorFrameAck throttled.
-    if (client_->SurfaceHasUndrawnFrame(entry.first))
+    if (client_->SurfaceHasUnackedFrame(entry.first))
       continue;
 
     has_pending_surfaces_ = true;
diff --git a/components/viz/service/display/display_scheduler.h b/components/viz/service/display/display_scheduler.h
index 06ffc24..77939d9 100644
--- a/components/viz/service/display/display_scheduler.h
+++ b/components/viz/service/display/display_scheduler.h
@@ -28,7 +28,7 @@
   virtual ~DisplaySchedulerClient() {}
 
   virtual bool DrawAndSwap() = 0;
-  virtual bool SurfaceHasUndrawnFrame(const SurfaceId& surface_id) const = 0;
+  virtual bool SurfaceHasUnackedFrame(const SurfaceId& surface_id) const = 0;
   virtual bool SurfaceDamaged(const SurfaceId& surface_id,
                               const BeginFrameAck& ack) = 0;
   virtual void SurfaceDiscarded(const SurfaceId& surface_id) = 0;
diff --git a/components/viz/service/display/display_scheduler_unittest.cc b/components/viz/service/display/display_scheduler_unittest.cc
index d2d324e6..bd7f380 100644
--- a/components/viz/service/display/display_scheduler_unittest.cc
+++ b/components/viz/service/display/display_scheduler_unittest.cc
@@ -42,7 +42,7 @@
     return success;
   }
 
-  bool SurfaceHasUndrawnFrame(const SurfaceId& surface_id) const override {
+  bool SurfaceHasUnackedFrame(const SurfaceId& surface_id) const override {
     return base::ContainsKey(undrawn_surfaces_, surface_id);
   }
 
diff --git a/components/viz/service/display/display_unittest.cc b/components/viz/service/display/display_unittest.cc
index f0f3ebc0..580c225 100644
--- a/components/viz/service/display/display_unittest.cc
+++ b/components/viz/service/display/display_unittest.cc
@@ -94,6 +94,25 @@
   bool swapped;
 };
 
+class StubDisplayClient : public DisplayClient {
+ public:
+  void DisplayOutputSurfaceLost() override {}
+  void DisplayWillDrawAndSwap(bool will_draw_and_swap,
+                              RenderPassList* render_passes) override {}
+  void DisplayDidDrawAndSwap() override {}
+  void DisplayDidReceiveCALayerParams(
+      const gfx::CALayerParams& ca_layer_params) override{};
+  void DisplayDidCompleteSwapWithSize(const gfx::Size& pixel_size) override {}
+  void DidSwapAfterSnapshotRequestReceived(
+      const std::vector<ui::LatencyInfo>& latency_info) override {}
+};
+
+void CopyCallback(bool* called, std::unique_ptr<CopyOutputResult> result) {
+  *called = true;
+}
+
+}  // namespace
+
 class DisplayTest : public testing::Test {
  public:
   DisplayTest()
@@ -169,6 +188,17 @@
       manager_.UnregisterBeginFrameSource(begin_frame_source_.get());
   }
 
+  bool ShouldSendBeginFrame(CompositorFrameSinkSupport* support,
+                            base::TimeTicks frame_time) {
+    return support->ShouldSendBeginFrame(frame_time);
+  }
+
+  void UpdateBeginFrameTime(CompositorFrameSinkSupport* support,
+                            base::TimeTicks frame_time) {
+    support->last_frame_time_ = frame_time;
+    support->presentation_feedbacks_.clear();
+  }
+
  protected:
   void SubmitCompositorFrame(RenderPassList* pass_list,
                              const LocalSurfaceId& local_surface_id) {
@@ -199,23 +229,6 @@
   TestDisplayScheduler* scheduler_ = nullptr;
 };
 
-class StubDisplayClient : public DisplayClient {
- public:
-  void DisplayOutputSurfaceLost() override {}
-  void DisplayWillDrawAndSwap(bool will_draw_and_swap,
-                              RenderPassList* render_passes) override {}
-  void DisplayDidDrawAndSwap() override {}
-  void DisplayDidReceiveCALayerParams(
-      const gfx::CALayerParams& ca_layer_params) override{};
-  void DisplayDidCompleteSwapWithSize(const gfx::Size& pixel_size) override {}
-  void DidSwapAfterSnapshotRequestReceived(
-      const std::vector<ui::LatencyInfo>& latency_info) override {}
-};
-
-void CopyCallback(bool* called, std::unique_ptr<CopyOutputResult> result) {
-  *called = true;
-}
-
 // Check that frame is damaged and swapped only under correct conditions.
 TEST_F(DisplayTest, DisplayDamaged) {
   RendererSettings settings;
@@ -3319,7 +3332,8 @@
     quad2->SetNew(shared_quad_state2, rect2 /* rect */,
                   rect2 /* visible_rect */,
                   SurfaceRange(base::nullopt, sub_surface_id), SK_ColorBLACK,
-                  false /* stretch_content_to_fill_bounds */);
+                  false /* stretch_content_to_fill_bounds */,
+                  false /* has_pointer_events_none */);
 
     pass_list.push_back(std::move(pass));
     SubmitCompositorFrame(&pass_list, local_surface_id);
@@ -3362,6 +3376,89 @@
   TearDownDisplay();
 }
 
+TEST_F(DisplayTest, BeginFrameThrottling) {
+  id_allocator_.GenerateId();
+  SetUpGpuDisplay(RendererSettings());
+
+  StubDisplayClient client;
+  display_->Initialize(&client, manager_.surface_manager());
+  display_->SetLocalSurfaceId(
+      id_allocator_.GetCurrentLocalSurfaceIdAllocation().local_surface_id(),
+      1.f);
+  support_->SetNeedsBeginFrame(true);
+
+  // BeginFrame should not be throttled when the client has not submitted any
+  // compositor frames.
+  base::TimeTicks frame_time = base::TimeTicks::Now();
+  EXPECT_TRUE(ShouldSendBeginFrame(support_.get(), frame_time));
+  UpdateBeginFrameTime(support_.get(), frame_time);
+
+  // Submit the first frame for the client. Begin-frame should still not be
+  // throttled since it has not been embedded yet.
+  RenderPassList pass_list;
+  auto pass = RenderPass::Create();
+  pass->output_rect = gfx::Rect(0, 0, 100, 100);
+  pass->damage_rect = gfx::Rect(10, 10, 1, 1);
+  pass->id = 1u;
+  pass_list.push_back(std::move(pass));
+
+  SubmitCompositorFrame(
+      &pass_list,
+      id_allocator_.GetCurrentLocalSurfaceIdAllocation().local_surface_id());
+  frame_time = base::TimeTicks::Now();
+  EXPECT_TRUE(ShouldSendBeginFrame(support_.get(), frame_time));
+  UpdateBeginFrameTime(support_.get(), frame_time);
+
+  display_->DrawAndSwap();
+  frame_time = base::TimeTicks::Now();
+  EXPECT_TRUE(ShouldSendBeginFrame(support_.get(), frame_time));
+  UpdateBeginFrameTime(support_.get(), frame_time);
+
+  // Submit a second frame. This time, begin-frame should be throttled after the
+  // first begin-frame is sent because of presentation-feedbacks, until the next
+  // draw happens.
+  pass = RenderPass::Create();
+  pass->output_rect = gfx::Rect(0, 0, 100, 100);
+  pass->damage_rect = gfx::Rect(10, 10, 1, 1);
+  pass->id = 1u;
+  pass_list.push_back(std::move(pass));
+  SubmitCompositorFrame(
+      &pass_list,
+      id_allocator_.GetCurrentLocalSurfaceIdAllocation().local_surface_id());
+  frame_time = base::TimeTicks::Now();
+  EXPECT_TRUE(ShouldSendBeginFrame(support_.get(), frame_time));
+  UpdateBeginFrameTime(support_.get(), frame_time);
+  EXPECT_FALSE(ShouldSendBeginFrame(support_.get(), frame_time));
+
+  // Drawing should unthrottle begin-frames.
+  display_->DrawAndSwap();
+  frame_time = base::TimeTicks::Now();
+  EXPECT_TRUE(ShouldSendBeginFrame(support_.get(), frame_time));
+  UpdateBeginFrameTime(support_.get(), frame_time);
+
+  // Submit a third frame. Again, begin-frame should be throttled after the
+  // begin-frame for presenatation-feedback.
+  pass = RenderPass::Create();
+  pass->output_rect = gfx::Rect(0, 0, 100, 100);
+  pass->damage_rect = gfx::Rect(10, 10, 1, 1);
+  pass->id = 1u;
+  pass_list.push_back(std::move(pass));
+  SubmitCompositorFrame(
+      &pass_list,
+      id_allocator_.GetCurrentLocalSurfaceIdAllocation().local_surface_id());
+  frame_time = base::TimeTicks::Now();
+  EXPECT_TRUE(ShouldSendBeginFrame(support_.get(), frame_time));
+  UpdateBeginFrameTime(support_.get(), frame_time);
+  EXPECT_FALSE(ShouldSendBeginFrame(support_.get(), frame_time));
+
+  // Instead of doing a draw, forward time by ~1 seconds. That should unthrottle
+  // the begin-frame.
+  frame_time += base::TimeDelta::FromSecondsD(1.1);
+  EXPECT_TRUE(ShouldSendBeginFrame(support_.get(), frame_time));
+
+  TearDownDisplay();
+}
+
 TEST_F(DisplayTest, InvalidPresentationTimestamps) {
   RendererSettings settings;
   id_allocator_.GenerateId();
@@ -3441,5 +3538,4 @@
   TearDownDisplay();
 }
 
-}  // namespace
 }  // namespace viz
diff --git a/components/viz/service/display/surface_aggregator_perftest.cc b/components/viz/service/display/surface_aggregator_perftest.cc
index 65d5cba..2975828a 100644
--- a/components/viz/service/display/surface_aggregator_perftest.cc
+++ b/components/viz/service/display/surface_aggregator_perftest.cc
@@ -97,7 +97,8 @@
             SurfaceRange(base::nullopt,
                          SurfaceId(FrameSinkId(1, i),
                                    LocalSurfaceId(i, kArbitraryToken))),
-            SK_ColorWHITE, false);
+            SK_ColorWHITE, /*stretch_content_to_fill_bounds=*/false,
+            /*ignores_input_event=*/false);
       }
 
       frame_builder.AddRenderPass(std::move(pass));
@@ -122,7 +123,8 @@
               base::nullopt,
               SurfaceId(FrameSinkId(1, num_surfaces),
                         LocalSurfaceId(num_surfaces, kArbitraryToken))),
-          SK_ColorWHITE, false);
+          SK_ColorWHITE, /*stretch_content_to_fill_bounds=*/false,
+          /*ignores_input_event=*/false);
 
       pass->output_rect = gfx::Rect(0, 0, 100, 100);
 
diff --git a/components/viz/service/display/surface_aggregator_pixeltest.cc b/components/viz/service/display/surface_aggregator_pixeltest.cc
index fafa7191..0c72156 100644
--- a/components/viz/service/display/surface_aggregator_pixeltest.cc
+++ b/components/viz/service/display/surface_aggregator_pixeltest.cc
@@ -144,10 +144,11 @@
                                        device_viewport_size_);
 
     auto* surface_quad = pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
-    surface_quad->SetNew(pass->shared_quad_state_list.back(),
-                         gfx::Rect(child_size), gfx::Rect(child_size),
-                         SurfaceRange(base::nullopt, child_surface_id),
-                         SK_ColorWHITE, false);
+    surface_quad->SetNew(
+        pass->shared_quad_state_list.back(), gfx::Rect(child_size),
+        gfx::Rect(child_size), SurfaceRange(base::nullopt, child_surface_id),
+        SK_ColorWHITE, /*stretch_content_to_fill_bounds=*/false,
+        /*ignores_input_event=*/false);
 
     auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
     bool force_anti_aliasing_off = false;
@@ -237,20 +238,22 @@
                                        device_viewport_size_);
 
     auto* left_surface_quad = pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
-    left_surface_quad->SetNew(pass->shared_quad_state_list.back(),
-                              gfx::Rect(child_size), gfx::Rect(child_size),
-                              SurfaceRange(base::nullopt, left_child_id),
-                              SK_ColorWHITE, false);
+    left_surface_quad->SetNew(
+        pass->shared_quad_state_list.back(), gfx::Rect(child_size),
+        gfx::Rect(child_size), SurfaceRange(base::nullopt, left_child_id),
+        SK_ColorWHITE, /*stretch_content_to_fill_bounds=*/false,
+        /*ignores_input_event=*/false);
 
     surface_transform.Translate(100, 0);
     CreateAndAppendTestSharedQuadState(pass.get(), surface_transform,
                                        device_viewport_size_);
 
     auto* right_surface_quad = pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
-    right_surface_quad->SetNew(pass->shared_quad_state_list.back(),
-                               gfx::Rect(child_size), gfx::Rect(child_size),
-                               SurfaceRange(base::nullopt, right_child_id),
-                               SK_ColorWHITE, false);
+    right_surface_quad->SetNew(
+        pass->shared_quad_state_list.back(), gfx::Rect(child_size),
+        gfx::Rect(child_size), SurfaceRange(base::nullopt, right_child_id),
+        SK_ColorWHITE, /*stretch_content_to_fill_bounds=*/false,
+        /*ignores_input_event=*/false);
 
     auto root_frame =
         CompositorFrameBuilder().AddRenderPass(std::move(pass)).Build();
diff --git a/components/viz/service/display/surface_aggregator_unittest.cc b/components/viz/service/display/surface_aggregator_unittest.cc
index 9034dba..1233bb5 100644
--- a/components/viz/service/display/surface_aggregator_unittest.cc
+++ b/components/viz/service/display/surface_aggregator_unittest.cc
@@ -137,13 +137,15 @@
     static Quad SurfaceQuad(const SurfaceRange& surface_range,
                             SkColor default_background_color,
                             const gfx::Rect& primary_surface_rect,
-                            bool stretch_content_to_fill_bounds) {
+                            bool stretch_content_to_fill_bounds,
+                            bool ignores_input_event) {
       Quad quad;
       quad.material = DrawQuad::SURFACE_CONTENT;
       quad.primary_surface_rect = primary_surface_rect;
       quad.surface_range = surface_range;
       quad.default_background_color = default_background_color;
       quad.stretch_content_to_fill_bounds = stretch_content_to_fill_bounds;
+      quad.ignores_input_event = ignores_input_event;
       return quad;
     }
 
@@ -152,7 +154,8 @@
                             const gfx::Rect& primary_surface_rect,
                             float opacity,
                             const gfx::Transform& transform,
-                            bool stretch_content_to_fill_bounds) {
+                            bool stretch_content_to_fill_bounds,
+                            bool ignores_input_event) {
       Quad quad;
       quad.material = DrawQuad::SURFACE_CONTENT;
       quad.primary_surface_rect = primary_surface_rect;
@@ -161,6 +164,7 @@
       quad.surface_range = surface_range;
       quad.default_background_color = default_background_color;
       quad.stretch_content_to_fill_bounds = stretch_content_to_fill_bounds;
+      quad.ignores_input_event = ignores_input_event;
       return quad;
     }
 
@@ -176,6 +180,7 @@
     SurfaceRange surface_range;
     SkColor default_background_color;
     bool stretch_content_to_fill_bounds;
+    bool ignores_input_event;
     gfx::Rect primary_surface_rect;
     float opacity;
     gfx::Transform to_target_transform;
@@ -219,7 +224,8 @@
         AddSurfaceQuad(pass, desc.primary_surface_rect, desc.opacity,
                        desc.to_target_transform, desc.surface_range,
                        desc.default_background_color,
-                       desc.stretch_content_to_fill_bounds);
+                       desc.stretch_content_to_fill_bounds,
+                       desc.ignores_input_event);
         break;
       case DrawQuad::RENDER_PASS:
         AddRenderPassQuad(pass, desc.render_pass_id);
@@ -298,7 +304,8 @@
                              const gfx::Transform& transform,
                              const SurfaceRange& surface_range,
                              SkColor default_background_color,
-                             bool stretch_content_to_fill_bounds) {
+                             bool stretch_content_to_fill_bounds,
+                             bool ignores_input_event) {
     gfx::Transform layer_to_target_transform = transform;
     gfx::Rect layer_bounds(primary_surface_rect);
     gfx::Rect visible_layer_rect(primary_surface_rect);
@@ -317,7 +324,7 @@
     surface_quad->SetNew(pass->shared_quad_state_list.back(),
                          primary_surface_rect, primary_surface_rect,
                          surface_range, default_background_color,
-                         stretch_content_to_fill_bounds);
+                         stretch_content_to_fill_bounds, ignores_input_event);
   }
 
   static void AddRenderPassQuad(RenderPass* pass, RenderPassId render_pass_id) {
@@ -456,8 +463,10 @@
       const std::vector<SurfaceRange>& ranges) {
     std::vector<Quad> quads;
     for (const SurfaceRange& range : ranges) {
-      quads.push_back(Quad::SurfaceQuad(range, SK_ColorWHITE, gfx::Rect(5, 5),
-                                        1.f, gfx::Transform(), false));
+      quads.push_back(Quad::SurfaceQuad(
+          range, SK_ColorWHITE, gfx::Rect(5, 5), 1.f, gfx::Transform(),
+          /*stretch_content_to_fill_bounds=*/false,
+          /*ignores_input_event=*/false));
     }
     std::vector<Pass> passes = {Pass(quads, SurfaceSize())};
     RenderPassList pass_list;
@@ -542,9 +551,11 @@
                         embedded_local_surface_id, device_scale_factor);
   SurfaceId root_surface_id(support_->frame_sink_id(), root_local_surface_id_);
   {
-    std::vector<Quad> quads = {Quad::SurfaceQuad(
-        SurfaceRange(base::nullopt, embedded_surface_id), SK_ColorWHITE,
-        gfx::Rect(5, 5), .5f, gfx::Transform(), false)};
+    std::vector<Quad> quads = {
+        Quad::SurfaceQuad(SurfaceRange(base::nullopt, embedded_surface_id),
+                          SK_ColorWHITE, gfx::Rect(5, 5), .5f, gfx::Transform(),
+                          /*stretch_content_to_fill_bounds=*/false,
+                          /*ignores_input_event=*/false)};
     std::vector<Pass> passes = {Pass(quads, SurfaceSize())};
 
     SubmitCompositorFrame(support_.get(), passes, root_local_surface_id_,
@@ -566,7 +577,9 @@
   {
     std::vector<Quad> quads = {Quad::SurfaceQuad(
         SurfaceRange(base::nullopt, embedded_surface_id), SK_ColorWHITE,
-        gfx::Rect(5, 5), .9999f, gfx::Transform(), false)};
+        gfx::Rect(5, 5), .9999f, gfx::Transform(),
+        /*stretch_content_to_fill_bounds=*/false,
+        /*ignores_input_event=*/false)};
     std::vector<Pass> passes = {Pass(quads, SurfaceSize())};
 
     SubmitCompositorFrame(support_.get(), passes, root_local_surface_id_,
@@ -602,9 +615,10 @@
                         embedded_local_surface_id, device_scale_factor);
   gfx::Transform rotate;
   rotate.Rotate(30);
-  std::vector<Quad> quads = {
-      Quad::SurfaceQuad(SurfaceRange(base::nullopt, embedded_surface_id),
-                        SK_ColorWHITE, gfx::Rect(5, 5), 1.f, rotate, false)};
+  std::vector<Quad> quads = {Quad::SurfaceQuad(
+      SurfaceRange(base::nullopt, embedded_surface_id), SK_ColorWHITE,
+      gfx::Rect(5, 5), 1.f, rotate, /*stretch_content_to_fill_bounds=*/false,
+      /*ignores_input_event=*/false)};
   std::vector<Pass> passes = {Pass(quads, SurfaceSize())};
 
   SubmitCompositorFrame(support_.get(), passes, root_local_surface_id_,
@@ -723,7 +737,9 @@
   std::vector<Quad> root_quads = {
       Quad::SolidColorQuad(SK_ColorWHITE, gfx::Rect(5, 5)),
       Quad::SurfaceQuad(SurfaceRange(base::nullopt, embedded_surface_id),
-                        SK_ColorWHITE, gfx::Rect(5, 5), false),
+                        SK_ColorWHITE, gfx::Rect(5, 5),
+                        /*stretch_content_to_fill_bounds=*/false,
+                        /*ignores_input_event=*/false),
       Quad::SolidColorQuad(SK_ColorBLACK, gfx::Rect(5, 5))};
   std::vector<Pass> root_passes = {Pass(root_quads, SurfaceSize())};
 
@@ -768,7 +784,9 @@
       if (embed.second) {
         embedded_quads.push_back(Quad::SurfaceQuad(
             SurfaceRange(base::nullopt, embed.first->surface_id()),
-            SK_ColorWHITE, embed.first->bounds(), false));
+            SK_ColorWHITE, embed.first->bounds(),
+            /*stretch_content_to_fill_bounds=*/false,
+            /*ignores_input_event=*/false));
       } else {
         referenced_surfaces.emplace_back(
             SurfaceRange(base::nullopt, embed.first->surface_id()));
@@ -830,7 +848,9 @@
   std::vector<Quad> root_quads = {
       Quad::SolidColorQuad(SK_ColorWHITE, gfx::Rect(5, 5)),
       Quad::SurfaceQuad(SurfaceRange(base::nullopt, parent.surface_id()),
-                        SK_ColorWHITE, parent.bounds(), false),
+                        SK_ColorWHITE, parent.bounds(),
+                        /*stretch_content_to_fill_bounds=*/false,
+                        /*ignores_input_event=*/false),
       Quad::SolidColorQuad(SK_ColorBLACK, gfx::Rect(5, 5))};
   std::vector<Pass> root_passes = {Pass(root_quads, SurfaceSize())};
 
@@ -887,7 +907,9 @@
   std::vector<Quad> root_quads = {
       Quad::SolidColorQuad(SK_ColorWHITE, gfx::Rect(5, 5)),
       Quad::SurfaceQuad(SurfaceRange(base::nullopt, parent.surface_id()),
-                        SK_ColorWHITE, parent.bounds(), false),
+                        SK_ColorWHITE, parent.bounds(),
+                        /*stretch_content_to_fill_bounds=*/false,
+                        /*ignores_input_event=*/false),
       Quad::SolidColorQuad(SK_ColorBLACK, gfx::Rect(5, 5))};
   std::vector<Pass> root_passes = {Pass(root_quads, SurfaceSize())};
 
@@ -952,7 +974,8 @@
   constexpr gfx::Rect surface_quad_rect(12, 15);
   std::vector<Quad> root_quads = {Quad::SurfaceQuad(
       SurfaceRange(fallback_child_surface_id, primary_child_surface_id),
-      SK_ColorWHITE, surface_quad_rect, false)};
+      SK_ColorWHITE, surface_quad_rect,
+      /*stretch_content_to_fill_bounds=*/false, /*ignores_input_event=*/false)};
   std::vector<Pass> root_passes = {Pass(root_quads, SurfaceSize())};
 
   MockAggregatedDamageCallback aggregated_damage_callback;
@@ -1101,9 +1124,9 @@
   }
 
   constexpr gfx::Rect surface_quad_rect(10, 5);
-  std::vector<Quad> root_quads = {
-      Quad::SurfaceQuad(SurfaceRange(primary_child_surface_id), SK_ColorWHITE,
-                        surface_quad_rect, true)};
+  std::vector<Quad> root_quads = {Quad::SurfaceQuad(
+      SurfaceRange(primary_child_surface_id), SK_ColorWHITE, surface_quad_rect,
+      /*stretch_content_to_fill_bounds=*/true, /*ignores_input_event=*/false)};
   std::vector<Pass> root_passes = {Pass(root_quads, SurfaceSize())};
 
   MockAggregatedDamageCallback aggregated_damage_callback;
@@ -1171,9 +1194,9 @@
   }
 
   constexpr gfx::Rect surface_quad_rect(10, 5);
-  std::vector<Quad> root_quads = {
-      Quad::SurfaceQuad(SurfaceRange(primary_child_surface_id), SK_ColorWHITE,
-                        surface_quad_rect, true)};
+  std::vector<Quad> root_quads = {Quad::SurfaceQuad(
+      SurfaceRange(primary_child_surface_id), SK_ColorWHITE, surface_quad_rect,
+      /*stretch_content_to_fill_bounds=*/true, /*ignores_input_event=*/false)};
   std::vector<Pass> root_passes = {Pass(root_quads, SurfaceSize())};
 
   MockAggregatedDamageCallback aggregated_damage_callback;
@@ -1242,9 +1265,9 @@
   }
 
   constexpr gfx::Rect surface_quad_rect(10, 5);
-  std::vector<Quad> root_quads = {
-      Quad::SurfaceQuad(SurfaceRange(primary_child_surface_id), SK_ColorWHITE,
-                        surface_quad_rect, true)};
+  std::vector<Quad> root_quads = {Quad::SurfaceQuad(
+      SurfaceRange(primary_child_surface_id), SK_ColorWHITE, surface_quad_rect,
+      /*stretch_content_to_fill_bounds=*/true, /*ignores_input_event=*/false)};
   std::vector<Pass> root_passes = {Pass(root_quads, SurfaceSize())};
 
   MockAggregatedDamageCallback aggregated_damage_callback;
@@ -1328,7 +1351,8 @@
   // |fallback_child_surface_id|.
   std::vector<Quad> root_quads = {Quad::SurfaceQuad(
       SurfaceRange(fallback_child_surface_id, primary_child_surface_id),
-      SK_ColorWHITE, gfx::Rect(5, 5), false)};
+      SK_ColorWHITE, gfx::Rect(5, 5), /*stretch_content_to_fill_bounds=*/false,
+      /*ignores_input_event=*/false)};
   constexpr gfx::Size root_size(75, 75);
   std::vector<Pass> root_passes = {Pass(root_quads, root_size, NoDamage())};
 
@@ -1400,7 +1424,9 @@
   std::vector<Quad> root_quads = {
       Quad::SolidColorQuad(SK_ColorWHITE, gfx::Rect(5, 5)),
       Quad::SurfaceQuad(SurfaceRange(base::nullopt, embedded_surface_id),
-                        SK_ColorWHITE, gfx::Rect(5, 5), false),
+                        SK_ColorWHITE, gfx::Rect(5, 5),
+                        /*stretch_content_to_fill_bounds=*/false,
+                        /*ignores_input_event=*/false),
       Quad::SolidColorQuad(SK_ColorBLACK, gfx::Rect(5, 5))};
   std::vector<Pass> root_passes = {Pass(root_quads, SurfaceSize())};
 
@@ -1460,7 +1486,9 @@
   std::vector<Quad> root_quads = {
       Quad::SolidColorQuad(SK_ColorWHITE, gfx::Rect(5, 5)),
       Quad::SurfaceQuad(SurfaceRange(base::nullopt, embedded_surface_id),
-                        SK_ColorWHITE, gfx::Rect(5, 5), false),
+                        SK_ColorWHITE, gfx::Rect(5, 5),
+                        /*stretch_content_to_fill_bounds=*/false,
+                        /*ignores_input_event=*/false),
       Quad::SolidColorQuad(SK_ColorBLACK, gfx::Rect(5, 5))};
   std::vector<Quad> root_quads2 = {
       Quad::SolidColorQuad(SK_ColorRED, gfx::Rect(5, 5))};
@@ -1554,7 +1582,9 @@
   std::vector<Quad> parent_quads = {
       Quad::SolidColorQuad(SK_ColorGRAY, gfx::Rect(5, 5)),
       Quad::SurfaceQuad(SurfaceRange(base::nullopt, embedded_surface_id),
-                        SK_ColorWHITE, gfx::Rect(5, 5), false),
+                        SK_ColorWHITE, gfx::Rect(5, 5),
+                        /*stretch_content_to_fill_bounds=*/false,
+                        /*ignores_input_event=*/false),
       Quad::SolidColorQuad(SK_ColorLTGRAY, gfx::Rect(5, 5))};
   std::vector<Pass> parent_passes = {Pass(parent_quads, SurfaceSize())};
 
@@ -1647,7 +1677,9 @@
       {Quad::SolidColorQuad(5, gfx::Rect(5, 5)),
        Quad::SolidColorQuad(6, gfx::Rect(5, 5))},
       {Quad::SurfaceQuad(SurfaceRange(base::nullopt, embedded_surface_id),
-                         SK_ColorWHITE, gfx::Rect(5, 5), false),
+                         SK_ColorWHITE, gfx::Rect(5, 5),
+                         /*stretch_content_to_fill_bounds=*/false,
+                         /*ignores_input_event=*/false),
        Quad::RenderPassQuad(pass_ids[0])},
       {Quad::SolidColorQuad(7, gfx::Rect(5, 5)),
        Quad::RenderPassQuad(pass_ids[1])}};
@@ -1771,7 +1803,9 @@
           SurfaceRange(SurfaceId(
               FrameSinkId(),
               LocalSurfaceId(0xdeadbeef, 0xdeadbeef, kArbitraryToken))),
-          SK_ColorWHITE, gfx::Rect(5, 5), false),
+          SK_ColorWHITE, gfx::Rect(5, 5),
+          /*stretch_content_to_fill_bounds=*/false,
+          /*ignores_input_event=*/false),
       Quad::SolidColorQuad(SK_ColorBLUE, gfx::Rect(5, 5))};
   std::vector<Pass> passes = {Pass(quads, SurfaceSize())};
 
@@ -1799,7 +1833,9 @@
   std::vector<Quad> quads = {
       Quad::SolidColorQuad(SK_ColorGREEN, gfx::Rect(5, 5)),
       Quad::SurfaceQuad(SurfaceRange(base::nullopt, surface_with_no_frame_id),
-                        SK_ColorYELLOW, gfx::Rect(5, 5), false),
+                        SK_ColorYELLOW, gfx::Rect(5, 5),
+                        /*stretch_content_to_fill_bounds=*/false,
+                        /*ignores_input_event=*/false),
       Quad::SolidColorQuad(SK_ColorBLUE, gfx::Rect(5, 5))};
   std::vector<Pass> passes = {Pass(quads, SurfaceSize())};
 
@@ -1826,9 +1862,9 @@
   const SurfaceId surface_with_no_frame_id(support_->frame_sink_id(),
                                            empty_local_surface_id);
 
-  std::vector<Quad> quads = {
-      Quad::SurfaceQuad(SurfaceRange(surface_with_no_frame_id), SK_ColorYELLOW,
-                        gfx::Rect(5, 5), false)};
+  std::vector<Quad> quads = {Quad::SurfaceQuad(
+      SurfaceRange(surface_with_no_frame_id), SK_ColorYELLOW, gfx::Rect(5, 5),
+      /*stretch_content_to_fill_bounds=*/false, /*ignores_input_event=*/false)};
   std::vector<Pass> passes = {Pass(quads, SurfaceSize())};
 
   constexpr float device_scale_factor = 1.0f;
@@ -1849,7 +1885,9 @@
   SurfaceId root_surface_id(support_->frame_sink_id(), root_local_surface_id_);
   std::vector<Quad> quads = {
       Quad::SurfaceQuad(SurfaceRange(base::nullopt, root_surface_id),
-                        SK_ColorWHITE, gfx::Rect(5, 5), false),
+                        SK_ColorWHITE, gfx::Rect(5, 5),
+                        /*stretch_content_to_fill_bounds=*/false,
+                        /*ignores_input_event=*/false),
       Quad::SolidColorQuad(SK_ColorYELLOW, gfx::Rect(5, 5))};
   std::vector<Pass> passes = {Pass(quads, SurfaceSize())};
 
@@ -1874,7 +1912,9 @@
   std::vector<Quad> parent_quads = {
       Quad::SolidColorQuad(SK_ColorBLUE, gfx::Rect(5, 5)),
       Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_surface_id),
-                        SK_ColorWHITE, gfx::Rect(5, 5), false),
+                        SK_ColorWHITE, gfx::Rect(5, 5),
+                        /*stretch_content_to_fill_bounds=*/false,
+                        /*ignores_input_event=*/false),
       Quad::SolidColorQuad(SK_ColorCYAN, gfx::Rect(5, 5))};
   std::vector<Pass> parent_passes = {Pass(parent_quads, SurfaceSize())};
 
@@ -1886,7 +1926,9 @@
   std::vector<Quad> child_quads = {
       Quad::SolidColorQuad(SK_ColorGREEN, gfx::Rect(5, 5)),
       Quad::SurfaceQuad(SurfaceRange(base::nullopt, root_surface_id),
-                        SK_ColorWHITE, gfx::Rect(5, 5), false),
+                        SK_ColorWHITE, gfx::Rect(5, 5),
+                        /*stretch_content_to_fill_bounds=*/false,
+                        /*ignores_input_event=*/false),
       Quad::SolidColorQuad(SK_ColorMAGENTA, gfx::Rect(5, 5))};
   std::vector<Pass> child_passes = {Pass(child_quads, SurfaceSize())};
 
@@ -1933,7 +1975,9 @@
   RenderPassId parent_pass_id[] = {3u, 2u};
   std::vector<Quad> parent_quad[2] = {
       {Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_surface_id),
-                         SK_ColorWHITE, gfx::Rect(5, 5), false)},
+                         SK_ColorWHITE, gfx::Rect(5, 5),
+                         /*stretch_content_to_fill_bounds=*/false,
+                         /*ignores_input_event=*/false)},
       {Quad::RenderPassQuad(parent_pass_id[0])}};
   std::vector<Pass> parent_passes = {
       Pass(parent_quad[0], parent_pass_id[0], SurfaceSize()),
@@ -2079,7 +2123,8 @@
   grandchild_surface_quad->SetNew(
       child_one_pass->shared_quad_state_list.back(), gfx::Rect(SurfaceSize()),
       gfx::Rect(SurfaceSize()),
-      SurfaceRange(base::nullopt, grandchild_surface_id), SK_ColorWHITE, false);
+      SurfaceRange(base::nullopt, grandchild_surface_id), SK_ColorWHITE,
+      /*stretch_content_to_fill_bounds=*/false, /*ignores_input_event=*/false);
   AddSolidColorQuadWithBlendMode(SurfaceSize(), child_one_pass.get(),
                                  blend_modes[3]);
   QueuePassAsFrame(std::move(child_one_pass), child_one_local_surface_id,
@@ -2110,7 +2155,8 @@
   child_one_surface_quad->SetNew(
       root_pass->shared_quad_state_list.back(), gfx::Rect(SurfaceSize()),
       gfx::Rect(SurfaceSize()),
-      SurfaceRange(base::nullopt, child_one_surface_id), SK_ColorWHITE, false);
+      SurfaceRange(base::nullopt, child_one_surface_id), SK_ColorWHITE,
+      /*stretch_content_to_fill_bounds=*/false, /*ignores_input_event=*/false);
   AddSolidColorQuadWithBlendMode(SurfaceSize(), root_pass.get(),
                                  blend_modes[4]);
   auto* child_two_surface_quad =
@@ -2118,7 +2164,8 @@
   child_two_surface_quad->SetNew(
       root_pass->shared_quad_state_list.back(), gfx::Rect(SurfaceSize()),
       gfx::Rect(SurfaceSize()),
-      SurfaceRange(base::nullopt, child_two_surface_id), SK_ColorWHITE, false);
+      SurfaceRange(base::nullopt, child_two_surface_id), SK_ColorWHITE,
+      /*stretch_content_to_fill_bounds=*/false, /*ignores_input_event=*/false);
   AddSolidColorQuadWithBlendMode(SurfaceSize(), root_pass.get(),
                                  blend_modes[6]);
 
@@ -2209,9 +2256,10 @@
   SurfaceId middle_surface_id(middle_support->frame_sink_id(),
                               middle_local_surface_id);
   {
-    std::vector<Quad> middle_quads = {
-        Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_surface_id),
-                          SK_ColorWHITE, gfx::Rect(5, 5), false)};
+    std::vector<Quad> middle_quads = {Quad::SurfaceQuad(
+        SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
+        gfx::Rect(5, 5), /*stretch_content_to_fill_bounds=*/false,
+        /*ignores_input_event=*/false)};
     std::vector<Pass> middle_passes = {
         Pass(middle_quads, SurfaceSize()),
     };
@@ -2236,7 +2284,9 @@
   std::vector<Quad> secondary_quads = {
       Quad::SolidColorQuad(1, gfx::Rect(5, 5)),
       Quad::SurfaceQuad(SurfaceRange(base::nullopt, middle_surface_id),
-                        SK_ColorWHITE, gfx::Rect(5, 5), false)};
+                        SK_ColorWHITE, gfx::Rect(5, 5),
+                        /*stretch_content_to_fill_bounds=*/false,
+                        /*ignores_input_event=*/false)};
   std::vector<Quad> root_quads = {Quad::SolidColorQuad(1, gfx::Rect(5, 5))};
   std::vector<Pass> root_passes = {Pass(secondary_quads, SurfaceSize()),
                                    Pass(root_quads, SurfaceSize())};
@@ -2362,9 +2412,10 @@
   child_support_->SubmitCompositorFrame(child_local_surface_id,
                                         std::move(child_frame));
 
-  std::vector<Quad> parent_surface_quads = {
-      Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_surface_id),
-                        SK_ColorWHITE, gfx::Rect(5, 5), false)};
+  std::vector<Quad> parent_surface_quads = {Quad::SurfaceQuad(
+      SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
+      gfx::Rect(5, 5), /*stretch_content_to_fill_bounds=*/false,
+      /*ignores_input_event=*/false)};
   std::vector<Pass> parent_surface_passes = {
       Pass(parent_surface_quads, 1, SurfaceSize())};
 
@@ -2382,9 +2433,10 @@
   parent_support->SubmitCompositorFrame(parent_local_surface_id,
                                         std::move(parent_surface_frame));
 
-  std::vector<Quad> root_surface_quads = {
-      Quad::SurfaceQuad(SurfaceRange(base::nullopt, parent_surface_id),
-                        SK_ColorWHITE, gfx::Rect(5, 5), false)};
+  std::vector<Quad> root_surface_quads = {Quad::SurfaceQuad(
+      SurfaceRange(base::nullopt, parent_surface_id), SK_ColorWHITE,
+      gfx::Rect(5, 5), /*stretch_content_to_fill_bounds=*/false,
+      /*ignores_input_event=*/false)};
   std::vector<Quad> root_render_pass_quads = {Quad::RenderPassQuad(1)};
 
   std::vector<Pass> root_passes = {
@@ -2550,9 +2602,10 @@
   child_support_->SubmitCompositorFrame(child_local_surface_id,
                                         std::move(child_frame));
 
-  std::vector<Quad> parent_surface_quads = {
-      Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_surface_id),
-                        SK_ColorWHITE, gfx::Rect(5, 5), false)};
+  std::vector<Quad> parent_surface_quads = {Quad::SurfaceQuad(
+      SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
+      gfx::Rect(5, 5), /*stretch_content_to_fill_bounds=*/false,
+      /*ignores_input_event=*/false)};
   std::vector<Pass> parent_surface_passes = {
       Pass(parent_surface_quads, 1, SurfaceSize())};
 
@@ -2570,9 +2623,10 @@
   parent_support->SubmitCompositorFrame(parent_local_surface_id,
                                         std::move(parent_surface_frame));
 
-  std::vector<Quad> root_surface_quads = {
-      Quad::SurfaceQuad(SurfaceRange(base::nullopt, parent_surface_id),
-                        SK_ColorWHITE, gfx::Rect(50, 50), true)};
+  std::vector<Quad> root_surface_quads = {Quad::SurfaceQuad(
+      SurfaceRange(base::nullopt, parent_surface_id), SK_ColorWHITE,
+      gfx::Rect(50, 50), /*stretch_content_to_fill_bounds=*/true,
+      /*ignores_input_event=*/false)};
   std::vector<Quad> root_render_pass_quads = {Quad::RenderPassQuad(1)};
 
   std::vector<Pass> root_passes = {
@@ -2656,9 +2710,10 @@
   child_support_->SubmitCompositorFrame(child_local_surface_id,
                                         std::move(child_frame));
 
-  std::vector<Quad> parent_surface_quads = {
-      Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_surface_id),
-                        SK_ColorWHITE, gfx::Rect(5, 5), false)};
+  std::vector<Quad> parent_surface_quads = {Quad::SurfaceQuad(
+      SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
+      gfx::Rect(5, 5), /*stretch_content_to_fill_bounds=*/false,
+      /*ignores_input_event=*/false)};
   std::vector<Pass> parent_surface_passes = {
       Pass(parent_surface_quads, 1, SurfaceSize())};
 
@@ -2676,9 +2731,10 @@
   parent_support->SubmitCompositorFrame(parent_local_surface_id,
                                         std::move(parent_surface_frame));
 
-  std::vector<Quad> root_surface_quads = {
-      Quad::SurfaceQuad(SurfaceRange(base::nullopt, parent_surface_id),
-                        SK_ColorWHITE, gfx::Rect(200, 200), true)};
+  std::vector<Quad> root_surface_quads = {Quad::SurfaceQuad(
+      SurfaceRange(base::nullopt, parent_surface_id), SK_ColorWHITE,
+      gfx::Rect(200, 200), /*stretch_content_to_fill_bounds=*/true,
+      /*ignores_input_event=*/false)};
   std::vector<Quad> root_render_pass_quads = {Quad::RenderPassQuad(1)};
 
   std::vector<Pass> root_passes = {
@@ -3086,9 +3142,10 @@
   }
 
   {
-    std::vector<Quad> root_quads = {
-        Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_surface_id),
-                          SK_ColorWHITE, gfx::Rect(5, 5), false)};
+    std::vector<Quad> root_quads = {Quad::SurfaceQuad(
+        SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
+        gfx::Rect(5, 5), /*stretch_content_to_fill_bounds=*/false,
+        /*ignores_input_event=*/false)};
 
     std::vector<Pass> root_passes = {Pass(root_quads, SurfaceSize())};
 
@@ -3122,9 +3179,10 @@
 
   // Create a root surface with a smaller damage rect.
   {
-    std::vector<Quad> root_quads = {
-        Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_surface_id),
-                          SK_ColorWHITE, gfx::Rect(5, 5), false)};
+    std::vector<Quad> root_quads = {Quad::SurfaceQuad(
+        SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
+        gfx::Rect(5, 5), /*stretch_content_to_fill_bounds=*/false,
+        /*ignores_input_event=*/false)};
 
     std::vector<Pass> root_passes = {Pass(root_quads, SurfaceSize())};
 
@@ -3229,9 +3287,10 @@
   // of it and its descendant passes should be aggregated.
   {
     int root_pass_ids[] = {1, 2, 3};
-    std::vector<Quad> root_quads1 = {
-        Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_surface_id),
-                          SK_ColorWHITE, gfx::Rect(5, 5), false)};
+    std::vector<Quad> root_quads1 = {Quad::SurfaceQuad(
+        SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
+        gfx::Rect(5, 5), /*stretch_content_to_fill_bounds=*/false,
+        /*ignores_input_event=*/false)};
     std::vector<Quad> root_quads2 = {Quad::RenderPassQuad(root_pass_ids[0])};
     std::vector<Quad> root_quads3 = {Quad::RenderPassQuad(root_pass_ids[1])};
     std::vector<Pass> root_passes = {
@@ -3284,7 +3343,9 @@
     std::vector<Quad> root_quads2 = {
         Quad::RenderPassQuad(root_pass_ids[0]),
         Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_surface_id),
-                          SK_ColorWHITE, gfx::Rect(5, 5), false)};
+                          SK_ColorWHITE, gfx::Rect(5, 5),
+                          /*stretch_content_to_fill_bounds=*/false,
+                          /*ignores_input_event=*/false)};
     std::vector<Pass> root_passes = {
         Pass(root_quads1, root_pass_ids[0], SurfaceSize()),
         Pass(root_quads2, root_pass_ids[1], SurfaceSize())};
@@ -3336,7 +3397,9 @@
     std::vector<Quad> root_quads2 = {
         Quad::RenderPassQuad(root_pass_ids[0]),
         Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_surface_id),
-                          SK_ColorWHITE, gfx::Rect(5, 5), false)};
+                          SK_ColorWHITE, gfx::Rect(5, 5),
+                          /*stretch_content_to_fill_bounds=*/false,
+                          /*ignores_input_event=*/false)};
     std::vector<Pass> root_passes = {
         Pass(root_quads1, root_pass_ids[0], pass_with_filter_size),
         Pass(root_quads2, root_pass_ids[1], SurfaceSize())};
@@ -3392,7 +3455,9 @@
     std::vector<Quad> root_quads2 = {
         Quad::RenderPassQuad(root_pass_ids[0]),
         Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_surface_id),
-                          SK_ColorWHITE, gfx::Rect(5, 5), false)};
+                          SK_ColorWHITE, gfx::Rect(5, 5),
+                          /*stretch_content_to_fill_bounds=*/false,
+                          /*ignores_input_event=*/false)};
     std::vector<Pass> root_passes = {
         Pass(root_quads1, root_pass_ids[0], pass_with_filter_size),
         Pass(root_quads2, root_pass_ids[1], SurfaceSize())};
@@ -3472,7 +3537,8 @@
     auto* surface_quad = pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
     surface_quad->SetNew(sqs, gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1),
                          SurfaceRange(base::nullopt, child_id), SK_ColorWHITE,
-                         false);
+                         /*stretch_content_to_fill_bounds=*/false,
+                         /*ignores_input_event=*/false);
   }
 
   for (size_t i = 0u; i < resource_ids.size(); ++i) {
@@ -3740,7 +3806,9 @@
 
     surface_quad->SetNew(sqs, gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1),
                          SurfaceRange(base::nullopt, surface1_id),
-                         SK_ColorWHITE, false);
+                         SK_ColorWHITE,
+                         /*stretch_content_to_fill_bounds=*/false,
+                         /*ignores_input_event=*/false);
     pass->copy_requests.push_back(CopyOutputRequest::CreateStubForTesting());
 
     CompositorFrame frame =
@@ -3835,9 +3903,10 @@
   child_support_->SubmitCompositorFrame(child_local_surface_id,
                                         std::move(child_surface_frame));
 
-  std::vector<Quad> root_surface_quads = {
-      Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_surface_id),
-                        SK_ColorWHITE, gfx::Rect(5, 5), false)};
+  std::vector<Quad> root_surface_quads = {Quad::SurfaceQuad(
+      SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
+      gfx::Rect(5, 5), /*stretch_content_to_fill_bounds=*/false,
+      /*ignores_input_event=*/false)};
   std::vector<Pass> root_passes = {Pass(root_surface_quads, 1, SurfaceSize())};
 
   CompositorFrame root_frame = MakeEmptyCompositorFrame();
@@ -3917,9 +3986,10 @@
   child_support_->SubmitCompositorFrame(child_local_surface_id,
                                         std::move(child_surface_frame));
 
-  std::vector<Quad> root_surface_quads = {
-      Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_surface_id),
-                        SK_ColorWHITE, gfx::Rect(5, 5), false)};
+  std::vector<Quad> root_surface_quads = {Quad::SurfaceQuad(
+      SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
+      gfx::Rect(5, 5), /*stretch_content_to_fill_bounds=*/false,
+      /*ignores_input_event=*/false)};
   std::vector<Pass> root_passes = {Pass(root_surface_quads, 1, SurfaceSize())};
 
   CompositorFrame root_frame = MakeEmptyCompositorFrame();
@@ -3963,7 +4033,9 @@
     std::vector<Quad> new_child_surface_quads = {
         child_surface_quads[0],
         Quad::SurfaceQuad(SurfaceRange(base::nullopt, grand_child_surface_id),
-                          SK_ColorWHITE, gfx::Rect(5, 5), false)};
+                          SK_ColorWHITE, gfx::Rect(5, 5),
+                          /*stretch_content_to_fill_bounds=*/false,
+                          /*ignores_input_event=*/false)};
     std::vector<Pass> new_child_surface_passes = {
         Pass(new_child_surface_quads, 1, SurfaceSize())};
     child_surface_frame = MakeEmptyCompositorFrame();
@@ -4037,9 +4109,10 @@
   child_support_->SubmitCompositorFrame(child_local_surface_id,
                                         std::move(child_frame));
 
-  std::vector<Quad> root_surface_quads = {
-      Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_surface_id),
-                        SK_ColorWHITE, gfx::Rect(5, 5), false)};
+  std::vector<Quad> root_surface_quads = {Quad::SurfaceQuad(
+      SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
+      gfx::Rect(5, 5), /*stretch_content_to_fill_bounds=*/false,
+      /*ignores_input_event=*/false)};
   std::vector<Quad> root_render_pass_quads = {Quad::RenderPassQuad(1)};
 
   std::vector<Pass> root_passes = {
@@ -4206,9 +4279,10 @@
   child_support_->SubmitCompositorFrame(child_local_surface_id,
                                         std::move(child_frame));
 
-  std::vector<Quad> root_surface_quads = {
-      Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_surface_id),
-                        SK_ColorWHITE, gfx::Rect(5, 5), false)};
+  std::vector<Quad> root_surface_quads = {Quad::SurfaceQuad(
+      SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
+      gfx::Rect(5, 5), /*stretch_content_to_fill_bounds=*/false,
+      /*ignores_input_event=*/false)};
 
   std::vector<Pass> root_passes = {Pass(root_surface_quads, 1, SurfaceSize())};
 
@@ -4311,9 +4385,10 @@
                                         std::move(child_surface_frame));
 
   // root surface quads
-  std::vector<Quad> root_surface_quads = {
-      Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_surface_id),
-                        SK_ColorWHITE, gfx::Rect(SurfaceSize()), false)};
+  std::vector<Quad> root_surface_quads = {Quad::SurfaceQuad(
+      SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
+      gfx::Rect(SurfaceSize()), /*stretch_content_to_fill_bounds=*/false,
+      /*ignores_input_event=*/false)};
   std::vector<Pass> root_passes = {Pass(root_surface_quads, 1, SurfaceSize())};
 
   CompositorFrame root_frame = MakeEmptyCompositorFrame();
@@ -4436,7 +4511,9 @@
     int pass_id[] = {1, 2};
     std::vector<Quad> root_quads[2] = {
         {Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_surface_id),
-                           SK_ColorWHITE, gfx::Rect(5, 5), false)},
+                           SK_ColorWHITE, gfx::Rect(5, 5),
+                           /*stretch_content_to_fill_bounds=*/false,
+                           /*ignores_input_event=*/false)},
         {Quad::RenderPassQuad(pass_id[0])},
     };
     std::vector<Pass> root_passes = {
@@ -4477,7 +4554,9 @@
     int pass_id[] = {1, 2};
     std::vector<Quad> root_quads[2] = {
         {Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_surface_id),
-                           SK_ColorWHITE, gfx::Rect(5, 5), false)},
+                           SK_ColorWHITE, gfx::Rect(5, 5),
+                           /*stretch_content_to_fill_bounds=*/false,
+                           /*ignores_input_event=*/false)},
         {Quad::RenderPassQuad(pass_id[0])},
     };
     std::vector<Pass> root_passes = {
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
index 77454aa71..6660472 100644
--- a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
+++ b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
@@ -581,14 +581,14 @@
     HandleCallback();
   }
 
-  if (client_ &&
-      (client_needs_begin_frame_ || !presentation_feedbacks_.empty())) {
+  if (client_ && ShouldSendBeginFrame(args.frame_time)) {
     BeginFrameArgs copy_args = args;
     copy_args.trace_id = ComputeTraceId();
     TRACE_EVENT_WITH_FLOW1("viz,benchmark", "Graphics.Pipeline",
                            TRACE_ID_GLOBAL(copy_args.trace_id),
                            TRACE_EVENT_FLAG_FLOW_OUT, "step",
                            "IssueBeginFrame");
+    last_frame_time_ = args.frame_time;
     client_->OnBeginFrame(copy_args, std::move(presentation_feedbacks_));
     presentation_feedbacks_.clear();
   }
@@ -730,4 +730,33 @@
   return (client << 48) | (sink << 32) | trace_sequence_;
 }
 
+bool CompositorFrameSinkSupport::ShouldSendBeginFrame(
+    base::TimeTicks frame_time) {
+  // If there are pending presentation feedbacks from the previous frame(s),
+  // then the client needs to receive the begin-frame.
+  if (!presentation_feedbacks_.empty())
+    return true;
+
+  if (!client_needs_begin_frame_)
+    return false;
+
+  if (!last_activated_surface_id_.is_valid())
+    return true;
+
+  Surface* surface =
+      surface_manager_->GetSurfaceForId(last_activated_surface_id_);
+  // If client has not submitted any frames, or the first frame submitted is
+  // yet to be embedded, then allow the begin-frame to be dispatched to the
+  // client.
+  if (!surface || !surface->seen_first_surface_embedding())
+    return true;
+
+  // Send begin-frames if the client has requested for it, and the previously
+  // submitted frame has already been drawn, or if the previous begin-frame was
+  // sent more than 1 second ago.
+  constexpr base::TimeDelta throttled_rate = base::TimeDelta::FromSeconds(1);
+  return !surface->HasUndrawnActiveFrame() ||
+         (frame_time - last_frame_time_) >= throttled_rate;
+}
+
 }  // namespace viz
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support.h b/components/viz/service/frame_sinks/compositor_frame_sink_support.h
index ef02c98..88a7d5f3 100644
--- a/components/viz/service/frame_sinks/compositor_frame_sink_support.h
+++ b/components/viz/service/frame_sinks/compositor_frame_sink_support.h
@@ -181,6 +181,7 @@
   }
 
  private:
+  friend class DisplayTest;
   friend class FrameSinkManagerTest;
 
   SubmitResult MaybeSubmitCompositorFrameInternal(
@@ -221,6 +222,7 @@
 
   void MaybeEvictSurfaces();
   void EvictLastActiveSurface();
+  bool ShouldSendBeginFrame(base::TimeTicks timestamp);
 
   mojom::CompositorFrameSinkClient* const client_;
 
@@ -304,6 +306,8 @@
   base::flat_map<uint32_t, gfx::PresentationFeedback> presentation_feedbacks_;
   uint32_t last_evicted_parent_sequence_number_ = 0;
 
+  base::TimeTicks last_frame_time_;
+
   base::WeakPtrFactory<CompositorFrameSinkSupport> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(CompositorFrameSinkSupport);
diff --git a/components/viz/service/frame_sinks/direct_layer_tree_frame_sink_unittest.cc b/components/viz/service/frame_sinks/direct_layer_tree_frame_sink_unittest.cc
index 8b4659c..a83f12f 100644
--- a/components/viz/service/frame_sinks/direct_layer_tree_frame_sink_unittest.cc
+++ b/components/viz/service/frame_sinks/direct_layer_tree_frame_sink_unittest.cc
@@ -215,7 +215,8 @@
   auto* quad2 = pass2->quad_list.AllocateAndConstruct<SurfaceDrawQuad>();
   quad2->SetNew(shared_quad_state2, rect2 /* rect */, rect2 /* visible_rect */,
                 SurfaceRange(base::nullopt, child_surface_id), SK_ColorBLACK,
-                false /* stretch_content_to_fill_bounds */);
+                false /* stretch_content_to_fill_bounds */,
+                false /* ignores_input_event */);
   pass_list.push_back(std::move(pass2));
 
   auto pass3 = RenderPass::Create();
@@ -256,7 +257,8 @@
   auto* quad4 = pass4->quad_list.AllocateAndConstruct<SurfaceDrawQuad>();
   quad4->SetNew(shared_quad_state4, rect4 /* rect */, rect4 /* visible_rect */,
                 SurfaceRange(base::nullopt, child_surface_id4), SK_ColorBLACK,
-                false /* stretch_content_to_fill_bounds */);
+                false /* stretch_content_to_fill_bounds */,
+                false /* ignores_input_event */);
   pass_list.push_back(std::move(pass4));
 
   const auto* hit_test_region_list1 =
@@ -355,7 +357,8 @@
                     /*visible_rect=*/rect3_0,
                     SurfaceRange(base::nullopt, child_surface_id),
                     SK_ColorBLACK,
-                    /*stretch_content_to_fill_bounds=*/false);
+                    /*stretch_content_to_fill_bounds=*/false,
+                    /*ignores_input_event=*/false);
     pass_list.push_back(std::move(pass3_0));
 
     auto pass3_1 = RenderPass::Create();
@@ -399,7 +402,8 @@
                     /*visible_rect=*/rect4_0,
                     SurfaceRange(base::nullopt, child_surface_id),
                     SK_ColorBLACK,
-                    /*stretch_content_to_fill_bounds=*/false);
+                    /*stretch_content_to_fill_bounds=*/false,
+                    /*ignores_input_event=*/false);
     pass_list.push_back(std::move(pass4_0));
 
     auto pass4_1 = RenderPass::Create();
@@ -445,7 +449,8 @@
                     /*visible_rect=*/rect5_0,
                     SurfaceRange(base::nullopt, child_surface_id),
                     SK_ColorBLACK,
-                    /*stretch_content_to_fill_bounds=*/false);
+                    /*stretch_content_to_fill_bounds=*/false,
+                    /*ignores_input_event=*/false);
     pass_list.push_back(std::move(pass5_0));
 
     auto pass5_1 = RenderPass::Create();
@@ -491,7 +496,8 @@
                     /*visible_rect=*/rect6_0,
                     SurfaceRange(base::nullopt, child_surface_id),
                     SK_ColorBLACK,
-                    /*stretch_content_to_fill_bounds=*/false);
+                    /*stretch_content_to_fill_bounds=*/false,
+                    /*ignores_input_event=*/false);
     pass_list.push_back(std::move(pass6_0));
 
     auto pass6_1 = RenderPass::Create();
diff --git a/components/viz/service/frame_sinks/video_detector_unittest.cc b/components/viz/service/frame_sinks/video_detector_unittest.cc
index e3422b9..db249d5 100644
--- a/components/viz/service/frame_sinks/video_detector_unittest.cc
+++ b/components/viz/service/frame_sinks/video_detector_unittest.cc
@@ -138,7 +138,8 @@
       quad->SetNew(
           shared_quad_state, gfx::Rect(0, 0, 10, 10), gfx::Rect(0, 0, 5, 5),
           SurfaceRange(base::nullopt, frame_sink->last_activated_surface_id()),
-          SK_ColorMAGENTA, false);
+          SK_ColorMAGENTA, /*stretch_content_to_fill_bounds=*/false,
+          /*ignores_input_event=*/false);
     }
     root_frame_sink_->SubmitCompositorFrame(
         root_frame_sink_->last_activated_local_surface_id(), std::move(frame));
diff --git a/components/viz/service/surfaces/surface.cc b/components/viz/service/surfaces/surface.cc
index cea4274..b8b940f 100644
--- a/components/viz/service/surfaces/surface.cc
+++ b/components/viz/service/surfaces/surface.cc
@@ -360,7 +360,6 @@
                               PresentedCallback presented_callback)
     : frame(std::move(frame)),
       frame_index(frame_index),
-      frame_processed(false),
       presented_callback(std::move(presented_callback)) {}
 
 Surface::FrameData::FrameData(FrameData&& other) = default;
@@ -647,14 +646,19 @@
   return false;
 }
 
-void Surface::RunDrawCallback() {
-  if (!active_frame_data_ || active_frame_data_->frame_processed)
+void Surface::SendAckToClient() {
+  if (!active_frame_data_ || active_frame_data_->frame_acked)
     return;
-  active_frame_data_->frame_processed = true;
+  active_frame_data_->frame_acked = true;
   if (surface_client_)
     surface_client_->OnSurfaceProcessed(this);
 }
 
+void Surface::MarkAsDrawn() {
+  if (active_frame_data_)
+    active_frame_data_->frame_drawn = true;
+}
+
 void Surface::NotifyAggregatedDamage(const gfx::Rect& damage_rect,
                                      base::TimeTicks expected_display_time) {
   if (!active_frame_data_ || !surface_client_)
@@ -682,7 +686,7 @@
     resource.sync_token.Clear();
   surface_client_->UnrefResources(resources);
 
-  if (!frame_data->frame_processed)
+  if (!frame_data->frame_acked)
     surface_client_->OnSurfaceProcessed(this);
 
   if (frame_data->presented_callback) {
diff --git a/components/viz/service/surfaces/surface.h b/components/viz/service/surfaces/surface.h
index 2b5cdee..cf47e98 100644
--- a/components/viz/service/surfaces/surface.h
+++ b/components/viz/service/surfaces/surface.h
@@ -181,7 +181,8 @@
 
   void TakeLatencyInfo(std::vector<ui::LatencyInfo>* latency_info);
   bool TakePresentedCallback(PresentedCallback* callback);
-  void RunDrawCallback();
+  void SendAckToClient();
+  void MarkAsDrawn();
   void NotifyAggregatedDamage(const gfx::Rect& damage_rect,
                               base::TimeTicks expected_display_time);
 
@@ -205,13 +206,20 @@
   bool HasActiveFrame() const { return active_frame_data_.has_value(); }
   bool HasPendingFrame() const { return pending_frame_data_.has_value(); }
   bool HasUndrawnActiveFrame() const {
-    return HasActiveFrame() && !active_frame_data_->frame_processed;
+    return HasActiveFrame() && !active_frame_data_->frame_drawn;
+  }
+  bool HasUnackedActiveFrame() const {
+    return HasActiveFrame() && !active_frame_data_->frame_acked;
   }
 
   // Returns true if at any point, another Surface's CompositorFrame has
   // depended on this Surface.
   bool HasDependentFrame() const { return seen_first_surface_dependency_; }
 
+  bool seen_first_surface_embedding() const {
+    return seen_first_surface_embedding_;
+  }
+
   // SurfaceDeadlineClient implementation:
   void OnDeadline(base::TimeDelta duration) override;
 
@@ -241,8 +249,9 @@
 
     CompositorFrame frame;
     uint64_t frame_index;
-    // Whether the frame has been processed (displayed, or discarded), or not.
-    bool frame_processed = false;
+    // Whether the frame has been displayed or not.
+    bool frame_drawn = false;
+    bool frame_acked = false;
     // TODO(sad): This callback would ideally become part of SurfaceClient API.
     PresentedCallback presented_callback;
   };
diff --git a/components/viz/service/surfaces/surface_manager.cc b/components/viz/service/surfaces/surface_manager.cc
index e98dcff2..4a4dd72 100644
--- a/components/viz/service/surfaces/surface_manager.cc
+++ b/components/viz/service/surfaces/surface_manager.cc
@@ -552,7 +552,7 @@
   if (!SurfaceModified(surface->surface_id(), frame.metadata.begin_frame_ack)) {
     TRACE_EVENT_INSTANT0("viz", "Damage not visible.",
                          TRACE_EVENT_SCOPE_THREAD);
-    surface->RunDrawCallback();
+    surface->SendAckToClient();
   }
 
   for (auto& observer : observer_list_)
diff --git a/components/viz/test/surface_hittest_test_helpers.cc b/components/viz/test/surface_hittest_test_helpers.cc
index 11ebfff..0d19edf 100644
--- a/components/viz/test/surface_hittest_test_helpers.cc
+++ b/components/viz/test/surface_hittest_test_helpers.cc
@@ -57,7 +57,8 @@
       pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
   surface_quad->SetNew(pass->shared_quad_state_list.back(), quad_rect,
                        quad_rect, SurfaceRange(base::nullopt, surface_id),
-                       SK_ColorWHITE, false);
+                       SK_ColorWHITE, /*stretch_content_to_fill_bounds=*/false,
+                       /*ignores_input_event=*/false);
 }
 
 void CreateRenderPass(int render_pass_id,
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index d8038798..0d6f725 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -2414,6 +2414,7 @@
     deps += [
       "//chromeos",
       "//chromeos/assistant:buildflags",
+      "//chromeos/audio",
       "//chromeos/dbus:power_manager_proto",
       "//components/session_manager/core",
     ]
diff --git a/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
index c7a5673..8daecd3 100644
--- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -8200,14 +8200,25 @@
   EXPECT_EQ(url1, shell()->web_contents()->GetLastCommittedURL());
 }
 
+class NavigationControllerHistoryInterventionBrowserTest
+    : public NavigationControllerBrowserTest {
+ protected:
+  void SetUp() override {
+    feature_list_.InitAndEnableFeature(
+        features::kHistoryManipulationIntervention);
+    NavigationControllerBrowserTest::SetUp();
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
 // Tests that the navigation entry is marked as skippable on back/forward button
 // if it does a renderer initiated navigation without ever getting a user
 // activation.
-IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+IN_PROC_BROWSER_TEST_F(NavigationControllerHistoryInterventionBrowserTest,
                        NoUserActivationSetSkipOnBackForward) {
   base::HistogramTester histograms;
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(features::kHistoryManipulationIntervention);
 
   GURL non_skippable_url(
       embedded_test_server()->GetURL("/frame_tree/top.html"));
@@ -8257,11 +8268,9 @@
 // Tests that the navigation entry is marked as skippable on back/forward button
 // if it does a renderer initiated cross-site navigation without ever getting a
 // user activation.
-IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+IN_PROC_BROWSER_TEST_F(NavigationControllerHistoryInterventionBrowserTest,
                        NoUserActivationSetSkipOnBackForwardCrossSite) {
   base::HistogramTester histograms;
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(features::kHistoryManipulationIntervention);
 
   GURL non_skippable_url(
       embedded_test_server()->GetURL("/frame_tree/top.html"));
@@ -8362,13 +8371,11 @@
 // Tests that the navigation entry is marked as skippable on back button if it
 // does a renderer initiated navigation without ever getting a user activation.
 // Also tests this for an entry added using history.pushState.
-IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+IN_PROC_BROWSER_TEST_F(NavigationControllerHistoryInterventionBrowserTest,
                        NoUserActivationSetSkippableMultipleGoBack) {
   base::HistogramTester histograms;
   const std::string histogram_name =
       "Navigation.BackForward.SetShouldSkipOnBackForwardUI";
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(features::kHistoryManipulationIntervention);
 
   GURL skippable_url(embedded_test_server()->GetURL("/frame_tree/top.html"));
   EXPECT_TRUE(NavigateToURL(shell(), skippable_url));
@@ -8419,13 +8426,11 @@
 }
 
 // Same as above but tests the metrics on going forward.
-IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+IN_PROC_BROWSER_TEST_F(NavigationControllerHistoryInterventionBrowserTest,
                        NoUserActivationSetSkippableMultipleGoForward) {
   base::HistogramTester histograms;
   const std::string histogram_name =
       "Navigation.BackForward.SetShouldSkipOnBackForwardUI";
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(features::kHistoryManipulationIntervention);
 
   GURL skippable_url(embedded_test_server()->GetURL("/frame_tree/top.html"));
   EXPECT_TRUE(NavigateToURL(shell(), skippable_url));
@@ -8536,13 +8541,11 @@
 // Tests that the navigation entry is not marked as skippable on back/forward
 // button if it does a renderer initiated navigation after getting a user
 // activation.
-IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+IN_PROC_BROWSER_TEST_F(NavigationControllerHistoryInterventionBrowserTest,
                        UserActivationDoNotSkipOnBackForward) {
   base::HistogramTester histograms;
   const std::string histogram_name =
       "Navigation.BackForward.SetShouldSkipOnBackForwardUI";
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(features::kHistoryManipulationIntervention);
 
   GURL non_skippable_url(
       embedded_test_server()->GetURL("/frame_tree/top.html"));
@@ -8586,13 +8589,11 @@
 // Tests that the navigation entry should not be marked as skippable on
 // back/forward button if it is navigated away using a browser initiated
 // navigation.
-IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+IN_PROC_BROWSER_TEST_F(NavigationControllerHistoryInterventionBrowserTest,
                        BrowserInitiatedNavigationDoNotSkipOnBackForward) {
   base::HistogramTester histograms;
   const std::string histogram_name =
       "Navigation.BackForward.SetShouldSkipOnBackForwardUI";
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(features::kHistoryManipulationIntervention);
 
   GURL non_skippable_url(
       embedded_test_server()->GetURL("/frame_tree/top.html"));
diff --git a/content/browser/renderer_host/dwrite_font_proxy_impl_win.cc b/content/browser/renderer_host/dwrite_font_proxy_impl_win.cc
index 4d4eb4e..1aaa42e9 100644
--- a/content/browser/renderer_host/dwrite_font_proxy_impl_win.cc
+++ b/content/browser/renderer_host/dwrite_font_proxy_impl_win.cc
@@ -759,7 +759,13 @@
     return false;
   }
 
-  // TODO(drott): Add UMA for table build time and table size.
+  UMA_HISTOGRAM_TIMES("DirectWrite.Fonts.Proxy.LookupTableBuildTime",
+                      base::TimeTicks::Now() - time_ticks);
+  // The size is usually tens of kilobytes, ~50kb on a standard Windows 10
+  // installation, 1MB should be a more than high enough upper limit.
+  UMA_HISTOGRAM_CUSTOM_COUNTS(
+      "DirectWrite.Fonts.Proxy.LookupTableSize",
+      font_unique_name_table_memory_.mapping.size() / 1024, 1, 1000, 50);
 
   return true;
 }
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
index 7628598..958ef67 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -3108,7 +3108,7 @@
   view_->renderer_compositor_frame_sink_->Reset();
   viz::Surface* surface = manager->GetSurfaceForId(view_->surface_id());
   EXPECT_TRUE(surface);
-  surface->RunDrawCallback();
+  surface->SendAckToClient();
   view_->renderer_compositor_frame_sink_->Flush();
   EXPECT_TRUE(view_->renderer_compositor_frame_sink_->did_receive_ack());
 
diff --git a/content/browser/site_per_process_hit_test_browsertest.cc b/content/browser/site_per_process_hit_test_browsertest.cc
index 69aca76..61c6f13 100644
--- a/content/browser/site_per_process_hit_test_browsertest.cc
+++ b/content/browser/site_per_process_hit_test_browsertest.cc
@@ -3310,22 +3310,14 @@
 
 }  // namespace
 
-#if defined(OS_WIN)
-// https://crbug.com/882458
-#define MAYBE_CursorUpdateReceivedFromCrossSiteIframe \
-  DISABLED_CursorUpdateReceivedFromCrossSiteIframe
-#else
-#define MAYBE_CursorUpdateReceivedFromCrossSiteIframe \
-  CursorUpdateReceivedFromCrossSiteIframe
-#endif
 IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
-                       MAYBE_CursorUpdateReceivedFromCrossSiteIframe) {
+                       CursorUpdateReceivedFromCrossSiteIframe) {
   CursorUpdateReceivedFromCrossSiteIframeHelper(shell(),
                                                 embedded_test_server());
 }
 
 IN_PROC_BROWSER_TEST_P(SitePerProcessHighDPIHitTestBrowserTest,
-                       MAYBE_CursorUpdateReceivedFromCrossSiteIframe) {
+                       CursorUpdateReceivedFromCrossSiteIframe) {
   CursorUpdateReceivedFromCrossSiteIframeHelper(shell(),
                                                 embedded_test_server());
 }
@@ -5808,7 +5800,7 @@
 
 IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestDataGenerationBrowserTest,
                        PointerEventsNoneOOPIF) {
-  if (!features::IsVizHitTestingSurfaceLayerEnabled())
+  if (!features::IsVizHitTestingEnabled())
     return;
   auto hit_test_data = SetupAndGetHitTestData(
       "/frame_tree/page_with_positioned_frame_pointer-events_none.html", 0);
@@ -5819,13 +5811,17 @@
   expected_transform.Translate(-2 * device_scale_factor,
                                -2 * device_scale_factor);
 
-  // We should not submit hit test region for iframes with pointer-events: none
-  // in /2 hit testing.
+  // We should not submit hit test region for iframes with pointer-events: none.
   DCHECK(hit_test_data.size() == 3);
   EXPECT_EQ(expected_region.ToString(), hit_test_data[2].rect.ToString());
   EXPECT_TRUE(
       expected_transform.ApproximatelyEqual(hit_test_data[2].transform()));
-  EXPECT_EQ(kFastHitTestFlags, hit_test_data[2].flags);
+  // Non v2 hit-testing should still treat the second OOPIF as slow path.
+  if (features::IsVizHitTestingSurfaceLayerEnabled()) {
+    EXPECT_EQ(kFastHitTestFlags, hit_test_data[2].flags);
+  } else {
+    EXPECT_EQ(kSlowHitTestFlags, hit_test_data[2].flags);
+  }
 
   // Check that an update on the css property can trigger an update in submitted
   // hit test data.
@@ -5867,12 +5863,21 @@
   EXPECT_EQ(expected_region.ToString(), hit_test_data[2].rect.ToString());
   EXPECT_TRUE(
       expected_transform.ApproximatelyEqual(hit_test_data[2].transform()));
-  EXPECT_EQ(kFastHitTestFlags, hit_test_data[2].flags);
+  // Non v2 hit-testing should still treat OOPIFs as slow path.
+  if (features::IsVizHitTestingSurfaceLayerEnabled()) {
+    EXPECT_EQ(kFastHitTestFlags, hit_test_data[2].flags);
+  } else {
+    EXPECT_EQ(kSlowHitTestFlags, hit_test_data[2].flags);
+  }
 
   EXPECT_EQ(expected_region2.ToString(), hit_test_data[3].rect.ToString());
   EXPECT_TRUE(
       expected_transform2.ApproximatelyEqual(hit_test_data[3].transform()));
-  EXPECT_EQ(kFastHitTestFlags, hit_test_data[3].flags);
+  if (features::IsVizHitTestingSurfaceLayerEnabled()) {
+    EXPECT_EQ(kFastHitTestFlags, hit_test_data[3].flags);
+  } else {
+    EXPECT_EQ(kSlowHitTestFlags, hit_test_data[3].flags);
+  }
 }
 
 IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestDataGenerationBrowserTest,
diff --git a/content/browser/webauth/scoped_virtual_authenticator_environment.cc b/content/browser/webauth/scoped_virtual_authenticator_environment.cc
index 20f597b..abd4326 100644
--- a/content/browser/webauth/scoped_virtual_authenticator_environment.cc
+++ b/content/browser/webauth/scoped_virtual_authenticator_environment.cc
@@ -10,6 +10,7 @@
 #include "content/browser/webauth/authenticator_type_converters.h"
 #include "content/browser/webauth/virtual_authenticator.h"
 #include "content/browser/webauth/virtual_discovery.h"
+#include "device/fido/virtual_ctap2_device.h"
 
 namespace content {
 
@@ -31,8 +32,9 @@
   return environment.get();
 }
 
-ScopedVirtualAuthenticatorEnvironment::ScopedVirtualAuthenticatorEnvironment() =
-    default;
+ScopedVirtualAuthenticatorEnvironment::ScopedVirtualAuthenticatorEnvironment()
+    : virtual_device_state_(new device::VirtualFidoDevice::State) {}
+
 ScopedVirtualAuthenticatorEnvironment::
     ~ScopedVirtualAuthenticatorEnvironment() = default;
 
@@ -101,11 +103,22 @@
     device::FidoTransportProtocol transport,
     ::service_manager::Connector* connector) {
   auto discovery = std::make_unique<VirtualFidoDiscovery>(this, transport);
-  for (auto& authenticator : authenticators_) {
-    if (discovery->transport() != authenticator.second->transport())
-      continue;
-    discovery->AddVirtualDevice(authenticator.second->ConstructDevice());
+
+  if (bindings_.empty()) {
+    // If no bindings are active then create a virtual device. This is useful
+    // for web-platform tests which assume that they can make webauthn calls,
+    // but which don't implement the Chromium-specific mock Mojo interfaces.
+    auto device =
+        std::make_unique<device::VirtualCtap2Device>(virtual_device_state_);
+    discovery->AddVirtualDevice(std::move(device));
+  } else {
+    for (auto& authenticator : authenticators_) {
+      if (discovery->transport() != authenticator.second->transport())
+        continue;
+      discovery->AddVirtualDevice(authenticator.second->ConstructDevice());
+    }
   }
+
   discoveries_.insert(discovery.get());
   return discovery;
 }
diff --git a/content/browser/webauth/scoped_virtual_authenticator_environment.h b/content/browser/webauth/scoped_virtual_authenticator_environment.h
index 7054a5d..7a7450c 100644
--- a/content/browser/webauth/scoped_virtual_authenticator_environment.h
+++ b/content/browser/webauth/scoped_virtual_authenticator_environment.h
@@ -14,6 +14,7 @@
 #include "base/no_destructor.h"
 #include "content/common/content_export.h"
 #include "device/fido/fido_discovery_factory.h"
+#include "device/fido/virtual_fido_device.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "third_party/blink/public/platform/modules/webauthn/virtual_authenticator.mojom.h"
 
@@ -73,6 +74,8 @@
   // automatically unregister themselves upon their destruction.
   std::set<VirtualFidoDiscovery*> discoveries_;
 
+  scoped_refptr<device::VirtualFidoDevice::State> virtual_device_state_;
+
   DISALLOW_COPY_AND_ASSIGN(ScopedVirtualAuthenticatorEnvironment);
 };
 
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 6a7a83b..8a2ae837 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -587,7 +587,7 @@
 // http://crbug.com/688388. This value is sent to WebRTC's echo canceller to
 // toggle which echo canceller should be used.
 const base::Feature kWebRtcUseEchoCanceller3{"WebRtcUseEchoCanceller3",
-                                             base::FEATURE_DISABLED_BY_DEFAULT};
+                                             base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Use GpuMemoryBuffer backed VideoFrames in media streams.
 const base::Feature kWebRtcUseGpuMemoryBufferVideoFrames{
diff --git a/content/renderer/android/synchronous_layer_tree_frame_sink.cc b/content/renderer/android/synchronous_layer_tree_frame_sink.cc
index 62774cdc..c0e99ab9 100644
--- a/content/renderer/android/synchronous_layer_tree_frame_sink.cc
+++ b/content/renderer/android/synchronous_layer_tree_frame_sink.cc
@@ -324,7 +324,8 @@
             viz::SurfaceId(
                 kChildFrameSinkId,
                 child_local_surface_id_allocation_.local_surface_id())),
-        SK_ColorWHITE, false);
+        SK_ColorWHITE, false /* stretch_content_to_fill_bounds */,
+        false /* ignores_input_event */);
 
     child_support_->SubmitCompositorFrame(
         child_local_surface_id_allocation_.local_surface_id(),
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index b96018d..1963f0f 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1196,7 +1196,10 @@
   }
 
   if (is_chromeos) {
-    deps += [ "//chromeos" ]
+    deps += [
+      "//chromeos",
+      "//chromeos/audio",
+    ]
   }
 
   if (use_aura && !is_win) {
@@ -2075,7 +2078,10 @@
     libs = [ "IOSurface.framework" ]
   }
   if (is_chromeos) {
-    deps += [ "//chromeos" ]
+    deps += [
+      "//chromeos",
+      "//chromeos/audio",
+    ]
   }
   if (is_android) {
     sources += [
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
index 0d90611..f885d25 100644
--- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -183,6 +183,8 @@
     self.Fail('conformance2/textures/canvas_sub_rectangle/' +
         'tex-2d-rgb565-rgb-unsigned_byte.html',
         ['win', ('nvidia', 0x1cb3), 'opengl'], bug=781668)
+    self.Flaky('conformance2/vertex_arrays/vertex-array-object.html',
+        ['win', ('nvidia', 0x1cb3), 'opengl', 'passthrough'], bug=920265)
     self.Fail('conformance/limits/gl-max-texture-dimensions.html',
         ['win', ('nvidia', 0x1cb3), 'opengl'], bug=715001)
     self.Fail('conformance/textures/misc/texture-size.html',
@@ -1304,6 +1306,9 @@
     self.Fail('conformance2/textures/misc/' +
         'generate-mipmap-with-large-base-level.html',
         ['linux', ('amd', 0x6613)], bug=913301)
+    self.Skip('conformance2/uniforms/' +
+        'incompatible-texture-type-for-sampler.html',
+        ['linux', ('amd', 0x6613)], bug=809237)
 
     ####################
     # Android failures #
diff --git a/device/fido/ble/fido_ble_connection.cc b/device/fido/ble/fido_ble_connection.cc
index 32291b6..bce6047 100644
--- a/device/fido/ble/fido_ble_connection.cc
+++ b/device/fido/ble/fido_ble_connection.cc
@@ -100,7 +100,10 @@
   }
 
   for (const auto* service : device->GetGattServices()) {
-    if (service->GetUUID() == BluetoothUUID(kFidoServiceUUID))
+    // This assumes that no device is representing as both a FIDO BLE
+    // and a caBLE device.
+    if (service->GetUUID() == BluetoothUUID(kFidoServiceUUID) ||
+        service->GetUUID() == BluetoothUUID(kCableAdvertisementUUID128))
       return service;
   }
 
diff --git a/docs/android_studio.md b/docs/android_studio.md
index 0e5f2f8..1834dd3 100644
--- a/docs/android_studio.md
+++ b/docs/android_studio.md
@@ -11,10 +11,6 @@
 build/android/gradle/generate_gradle.py --output-directory out/Debug
 ```
 
-```shell
-build/android/gradle/generate_gradle.py --output-directory out/Debug --sdk AndroidStudioDefault
-```
-
 The above commands create a project dir `gradle` under your output directory.
 Use `--project-dir <project-dir>` to change this.
 
@@ -25,14 +21,9 @@
 See [android_test_instructions.md](android_test_instructions.md#Using-Emulators)
 for more information about building and running emulators.
 
-If you're asked to use Studio's Android SDK:
-* No.
-    * Selecting No ensures that the SDK used by Android Studio is the same as
-      the one set by `generate_gradle.py`. If you want a different SDK pass
-      `--sdk` to `generate_gradle.py`.
+If you're asked to use Studio's Android SDK: No.
 
-If you're asked to use Studio's Gradle wrapper:
-* Yes.
+If you're asked to use Studio's Gradle wrapper: Yes.
 
 You need to re-run `generate_gradle.py` whenever `BUILD.gn` files change.
 
@@ -89,11 +80,15 @@
 target (no shorthands). This will require you to install `cmake` and `ndk` when
 prompted. Accept Android Studio's prompts for these SDK packages.
 
+You need to disable a new gradle option in order to edit native files:
+File -&gt; Settings -&gt; Experimental
+-&gt; Gradle and uncheck "Only resolve selected variants".
+
 This is not necessary, but to avoid "This file is not part of the project...",
 you can either add an extra `--native-target` flag or simply copy and paste the
 absolute path to that file into the CMakeLists.txt file alongside the existing
-file paths. Note that these changes will be overwritten on your next invocation
-of `generate_gradle.py`.
+file paths. Note that changes to CMakeLists.txt will be overwritten on your next
+invocation of `generate_gradle.py`.
 
 Example:
 
diff --git a/docs/ui/views/overview.md b/docs/ui/views/overview.md
index a379b9f..aa8e5e69 100644
--- a/docs/ui/views/overview.md
+++ b/docs/ui/views/overview.md
@@ -127,6 +127,22 @@
 non-client frame view may be swapped out as the system theme changes without
 affecting the client view.
 
+The overall structure of a Widget and its helper Views looks like this:
+
+```
+(Widget
+  (RootView
+    (NonClientView
+      (NonClientFrameView
+        title
+        non-client buttons, e.g. close button
+        ...)
+      (ClientView
+        contents
+        dialog buttons
+        ...))))
+```
+
 ## Dialogs
 
 A commonly-used type of client view is a **dialog client view**, which has a
diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn
index a208a20..d6b0fe3 100644
--- a/extensions/browser/BUILD.gn
+++ b/extensions/browser/BUILD.gn
@@ -505,6 +505,7 @@
 
     deps += [
       "//chromeos",
+      "//chromeos/audio",
       "//chromeos/dbus:media_perception_proto",
       "//chromeos/dbus:power_manager_proto",
       "//chromeos/login/login_state",
diff --git a/extensions/browser/api/audio/BUILD.gn b/extensions/browser/api/audio/BUILD.gn
index 4df4bd05..da4d4f8c 100644
--- a/extensions/browser/api/audio/BUILD.gn
+++ b/extensions/browser/api/audio/BUILD.gn
@@ -18,18 +18,19 @@
     "pref_names.h",
   ]
 
-  if (is_chromeos) {
-    sources += [ "audio_service_chromeos.cc" ]
-  } else {
-    sources += [ "audio_service.cc" ]
-  }
+  public_deps = [
+    "//extensions/browser:browser_sources",
+  ]
 
   deps = [
     "//components/prefs",
     "//extensions/common/api",
   ]
 
-  public_deps = [
-    "//extensions/browser:browser_sources",
-  ]
+  if (is_chromeos) {
+    deps += [ "//chromeos/audio" ]
+    sources += [ "audio_service_chromeos.cc" ]
+  } else {
+    sources += [ "audio_service.cc" ]
+  }
 }
diff --git a/extensions/shell/BUILD.gn b/extensions/shell/BUILD.gn
index dfb4201..f1f731f 100644
--- a/extensions/shell/BUILD.gn
+++ b/extensions/shell/BUILD.gn
@@ -228,6 +228,8 @@
     ]
     deps += [
       "//chromeos",
+      "//chromeos/audio",
+      "//chromeos/disks",
       "//chromeos/login/login_state",
       "//ui/chromeos",
       "//ui/display/manager",
@@ -354,6 +356,7 @@
     deps += [
       "//chromeos",
       "//chromeos:test_support_without_gmock",
+      "//chromeos/audio",
     ]
   }
 
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index 9a659301..ceb31c28 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -3492,6 +3492,27 @@
   }
 }
 
+void GLES2Implementation::GetResultNameHelper(GLsizei bufsize,
+                                              GLsizei* length,
+                                              char* name) {
+  // Length of string (without final \0) that we will write to the buffer.
+  GLsizei max_length = 0;
+  if (name && (bufsize > 0)) {
+    std::vector<int8_t> str;
+    GetBucketContents(kResultBucketId, &str);
+    if (!str.empty()) {
+      DCHECK_LE(str.size(), static_cast<size_t>(INT_MAX));
+      // Note: both bufsize and str.size() count/include the terminating \0.
+      max_length = std::min(bufsize, static_cast<GLsizei>(str.size())) - 1;
+    }
+    memcpy(name, str.data(), max_length);
+    name[max_length] = '\0';
+  }
+  if (length) {
+    *length = max_length;
+  }
+}
+
 bool GLES2Implementation::GetActiveAttribHelper(GLuint program,
                                                 GLuint index,
                                                 GLsizei bufsize,
@@ -3519,21 +3540,8 @@
     if (type) {
       *type = result->type;
     }
-    if (length || name) {
-      std::vector<int8_t> str;
-      // Note: this can invalidate |result|.
-      GetBucketContents(kResultBucketId, &str);
-      GLsizei max_size =
-          std::min(static_cast<size_t>(bufsize) - 1,
-                   std::max(static_cast<size_t>(0), str.size() - 1));
-      if (length) {
-        *length = max_size;
-      }
-      if (name && bufsize > 0) {
-        memcpy(name, &str[0], max_size);
-        name[max_size] = '\0';
-      }
-    }
+    // Note: this can invalidate |result|.
+    GetResultNameHelper(bufsize, length, name);
   }
   return success;
 }
@@ -3592,29 +3600,18 @@
   helper_->GetActiveUniform(program, index, kResultBucketId, GetResultShmId(),
                             result.offset());
   WaitForCmd();
-  if (result->success) {
+  bool success = !!result->success;
+  if (success) {
     if (size) {
       *size = result->size;
     }
     if (type) {
       *type = result->type;
     }
-    if (length || name) {
-      std::vector<int8_t> str;
-      GetBucketContents(kResultBucketId, &str);
-      GLsizei max_size =
-          std::min(static_cast<size_t>(bufsize) - 1,
-                   std::max(static_cast<size_t>(0), str.size() - 1));
-      if (length) {
-        *length = max_size;
-      }
-      if (name && bufsize > 0) {
-        memcpy(name, &str[0], max_size);
-        name[max_size] = '\0';
-      }
-    }
+    // Note: this can invalidate |result|.
+    GetResultNameHelper(bufsize, length, name);
   }
-  return result->success != 0;
+  return success;
 }
 
 void GLES2Implementation::GetActiveUniform(GLuint program,
@@ -3670,27 +3667,12 @@
   helper_->GetActiveUniformBlockName(program, index, kResultBucketId,
                                      GetResultShmId(), result.offset());
   WaitForCmd();
-  if (*result) {
-    if (bufsize == 0) {
-      if (length) {
-        *length = 0;
-      }
-    } else if (length || name) {
-      std::vector<int8_t> str;
-      GetBucketContents(kResultBucketId, &str);
-      DCHECK_GT(str.size(), 0u);
-      GLsizei max_size =
-          std::min(bufsize, static_cast<GLsizei>(str.size())) - 1;
-      if (length) {
-        *length = max_size;
-      }
-      if (name) {
-        memcpy(name, &str[0], max_size);
-        name[max_size] = '\0';
-      }
-    }
+  bool success = !!result;
+  if (success) {
+    // Note: this can invalidate |result|.
+    GetResultNameHelper(bufsize, length, name);
   }
-  return *result != 0;
+  return success;
 }
 
 void GLES2Implementation::GetActiveUniformBlockName(GLuint program,
@@ -4025,25 +4007,8 @@
     if (type) {
       *type = result->type;
     }
-    if (length || name) {
-      std::vector<int8_t> str;
-      GetBucketContents(kResultBucketId, &str);
-      GLsizei max_size = std::min(bufsize, static_cast<GLsizei>(str.size()));
-      if (max_size > 0) {
-        --max_size;
-      }
-      if (length) {
-        *length = max_size;
-      }
-      if (name) {
-        if (max_size > 0) {
-          memcpy(name, &str[0], max_size);
-          name[max_size] = '\0';
-        } else if (bufsize > 0) {
-          name[0] = '\0';
-        }
-      }
-    }
+    // Note: this can invalidate |result|.
+    GetResultNameHelper(bufsize, length, name);
   }
   return result->success != 0;
 }
@@ -5162,7 +5127,7 @@
     const GLfloat* clip_rect,
     GLint sorting_context_id,
     const GLfloat* transform) {
-  size_t shm_size = 20 * sizeof(GLfloat);
+  uint32_t shm_size = 20 * sizeof(GLfloat);
   ScopedTransferBufferPtr buffer(shm_size, helper_, transfer_buffer_);
   if (!buffer.valid() || buffer.size() < shm_size) {
     SetGLError(GL_OUT_OF_MEMORY, "GLES2::ScheduleCALayerSharedStateCHROMIUM",
@@ -5183,7 +5148,7 @@
                                                   GLuint edge_aa_mask,
                                                   const GLfloat* bounds_rect,
                                                   GLuint filter) {
-  size_t shm_size = 8 * sizeof(GLfloat);
+  uint32_t shm_size = 8 * sizeof(GLfloat);
   ScopedTransferBufferPtr buffer(shm_size, helper_, transfer_buffer_);
   if (!buffer.valid() || buffer.size() < shm_size) {
     SetGLError(GL_OUT_OF_MEMORY, "GLES2::ScheduleCALayerCHROMIUM",
@@ -6652,11 +6617,11 @@
   base::CheckedNumeric<uint32_t> total_size = count;
   total_size += 1;
   total_size *= sizeof(GLint);
-  if (!total_size.IsValid()) {
+  uint32_t header_size = 0;
+  if (!total_size.AssignIfValid(&header_size)) {
     SetGLError(GL_INVALID_VALUE, func_name, "overflow");
     return false;
   }
-  size_t header_size = total_size.ValueOrDefault(0);
   std::vector<GLint> header(count + 1);
   header[0] = static_cast<GLint>(count);
   for (GLsizei ii = 0; ii < count; ++ii) {
@@ -6668,35 +6633,30 @@
     }
     total_size += len;
     total_size += 1;  // NULL at the end of each char array.
-    if (!total_size.IsValid()) {
-      SetGLError(GL_INVALID_VALUE, func_name, "overflow");
-      return false;
-    }
     header[ii + 1] = len;
   }
   // Pack data into a bucket on the service.
-  helper_->SetBucketSize(kResultBucketId, total_size.ValueOrDefault(0));
-  size_t offset = 0;
+  uint32_t validated_size = 0;
+  if (!total_size.AssignIfValid(&validated_size)) {
+    SetGLError(GL_INVALID_VALUE, func_name, "overflow");
+    return false;
+  }
+  helper_->SetBucketSize(kResultBucketId, validated_size);
+  uint32_t offset = 0;
   for (GLsizei ii = 0; ii <= count; ++ii) {
     const char* src =
         (ii == 0) ? reinterpret_cast<const char*>(&header[0]) : str[ii - 1];
-    base::CheckedNumeric<size_t> checked_size =
-        (ii == 0) ? header_size : static_cast<size_t>(header[ii]);
+    uint32_t size = (ii == 0) ? header_size : header[ii];
     if (ii > 0) {
-      checked_size += 1;  // NULL in the end.
+      size += 1;  // NULL in the end.
     }
-    if (!checked_size.IsValid()) {
-      SetGLError(GL_INVALID_VALUE, func_name, "overflow");
-      return false;
-    }
-    size_t size = checked_size.ValueOrDefault(0);
     while (size) {
       ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
       if (!buffer.valid() || buffer.size() == 0) {
         SetGLError(GL_OUT_OF_MEMORY, func_name, "too large");
         return false;
       }
-      size_t copy_size = buffer.size();
+      uint32_t copy_size = buffer.size();
       if (ii > 0 && buffer.size() == size)
         --copy_size;
       if (copy_size)
@@ -7005,9 +6965,9 @@
     const GLfloat* transform_values,
     ScopedTransferBufferPtr* buffer,
     uint32_t* out_paths_shm_id,
-    size_t* out_paths_offset,
+    uint32_t* out_paths_offset,
     uint32_t* out_transforms_shm_id,
-    size_t* out_transforms_offset) {
+    uint32_t* out_transforms_offset) {
   if (num_paths < 0) {
     SetGLError(GL_INVALID_VALUE, function_name, "numPaths < 0");
     return false;
@@ -7121,9 +7081,9 @@
 
   ScopedTransferBufferPtr buffer(helper_, transfer_buffer_);
   uint32_t paths_shm_id = 0;
-  size_t paths_offset = 0;
+  uint32_t paths_offset = 0;
   uint32_t transforms_shm_id = 0;
-  size_t transforms_offset = 0;
+  uint32_t transforms_offset = 0;
   if (!PrepareInstancedPathCommand(
           "glStencilFillPathInstancedCHROMIUM", num_paths, path_name_type,
           paths, transform_type, transform_values, &buffer, &paths_shm_id,
@@ -7156,9 +7116,9 @@
 
   ScopedTransferBufferPtr buffer(helper_, transfer_buffer_);
   uint32_t paths_shm_id = 0;
-  size_t paths_offset = 0;
+  uint32_t paths_offset = 0;
   uint32_t transforms_shm_id = 0;
-  size_t transforms_offset = 0;
+  uint32_t transforms_offset = 0;
   if (!PrepareInstancedPathCommand(
           "glStencilStrokePathInstancedCHROMIUM", num_paths, path_name_type,
           paths, transform_type, transform_values, &buffer, &paths_shm_id,
@@ -7189,9 +7149,9 @@
 
   ScopedTransferBufferPtr buffer(helper_, transfer_buffer_);
   uint32_t paths_shm_id = 0;
-  size_t paths_offset = 0;
+  uint32_t paths_offset = 0;
   uint32_t transforms_shm_id = 0;
-  size_t transforms_offset = 0;
+  uint32_t transforms_offset = 0;
   if (!PrepareInstancedPathCommand(
           "glCoverFillPathInstancedCHROMIUM", num_paths, path_name_type, paths,
           transform_type, transform_values, &buffer, &paths_shm_id,
@@ -7223,9 +7183,9 @@
 
   ScopedTransferBufferPtr buffer(helper_, transfer_buffer_);
   uint32_t paths_shm_id = 0;
-  size_t paths_offset = 0;
+  uint32_t paths_offset = 0;
   uint32_t transforms_shm_id = 0;
-  size_t transforms_offset = 0;
+  uint32_t transforms_offset = 0;
   if (!PrepareInstancedPathCommand(
           "glCoverStrokePathInstancedCHROMIUM", num_paths, path_name_type,
           paths, transform_type, transform_values, &buffer, &paths_shm_id,
@@ -7259,9 +7219,9 @@
 
   ScopedTransferBufferPtr buffer(helper_, transfer_buffer_);
   uint32_t paths_shm_id = 0;
-  size_t paths_offset = 0;
+  uint32_t paths_offset = 0;
   uint32_t transforms_shm_id = 0;
-  size_t transforms_offset = 0;
+  uint32_t transforms_offset = 0;
   if (!PrepareInstancedPathCommand(
           "glStencilThenCoverFillPathInstancedCHROMIUM", num_paths,
           path_name_type, paths, transform_type, transform_values, &buffer,
@@ -7298,9 +7258,9 @@
 
   ScopedTransferBufferPtr buffer(helper_, transfer_buffer_);
   uint32_t paths_shm_id = 0;
-  size_t paths_offset = 0;
+  uint32_t paths_offset = 0;
   uint32_t transforms_shm_id = 0;
-  size_t transforms_offset = 0;
+  uint32_t transforms_offset = 0;
   if (!PrepareInstancedPathCommand(
           "glStencilThenCoverStrokePathInstancedCHROMIUM", num_paths,
           path_name_type, paths, transform_type, transform_values, &buffer,
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h
index 174431b..872494a 100644
--- a/gpu/command_buffer/client/gles2_implementation.h
+++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -149,6 +149,12 @@
   GLint GetUniformLocationHelper(GLuint program, const char* name);
   GLint GetFragDataIndexEXTHelper(GLuint program, const char* name);
   GLint GetFragDataLocationHelper(GLuint program, const char* name);
+
+  // Writes the result bucket into a buffer pointed by name and of maximum size
+  // buffsize. If length is !null, it receives the number of characters written
+  // (excluding the final \0). This is a helper function for GetActive*Helper
+  // functions that return names.
+  void GetResultNameHelper(GLsizei bufsize, GLsizei* length, char* name);
   bool GetActiveAttribHelper(
       GLuint program, GLuint index, GLsizei bufsize, GLsizei* length,
       GLint* size, GLenum* type, char* name);
@@ -628,9 +634,9 @@
                                    const GLfloat* transform_values,
                                    ScopedTransferBufferPtr* buffer,
                                    uint32_t* out_paths_shm_id,
-                                   size_t* out_paths_offset,
+                                   uint32_t* out_paths_offset,
                                    uint32_t* out_transforms_shm_id,
-                                   size_t* out_transforms_offset);
+                                   uint32_t* out_transforms_offset);
 
 // Set to 1 to have the client fail when a GL error is generated.
 // This helps find bugs in the renderer since the debugger stops on the error.
diff --git a/gpu/command_buffer/client/implementation_base.cc b/gpu/command_buffer/client/implementation_base.cc
index e07e10c..3477663 100644
--- a/gpu/command_buffer/client/implementation_base.cc
+++ b/gpu/command_buffer/client/implementation_base.cc
@@ -19,8 +19,8 @@
 namespace gpu {
 
 #if !defined(_MSC_VER)
-const size_t ImplementationBase::kMaxSizeOfSimpleResult;
-const unsigned int ImplementationBase::kStartingOffset;
+const uint32_t ImplementationBase::kMaxSizeOfSimpleResult;
+const uint32_t ImplementationBase::kStartingOffset;
 #endif
 
 ImplementationBase::ImplementationBase(CommandBufferHelper* helper,
diff --git a/gpu/command_buffer/client/implementation_base.h b/gpu/command_buffer/client/implementation_base.h
index b77ca46..b4ebeac 100644
--- a/gpu/command_buffer/client/implementation_base.h
+++ b/gpu/command_buffer/client/implementation_base.h
@@ -45,11 +45,11 @@
       public GpuControlClient {
  public:
   // The maximum result size from simple GL get commands.
-  static const size_t kMaxSizeOfSimpleResult =
+  static const uint32_t kMaxSizeOfSimpleResult =
       16 * sizeof(uint32_t);  // NOLINT.
 
   // used for testing only. If more things are reseved add them here.
-  static const unsigned int kStartingOffset = kMaxSizeOfSimpleResult;
+  static const uint32_t kStartingOffset = kMaxSizeOfSimpleResult;
 
   // Alignment of allocations.
   static const unsigned int kAlignment = 16;
diff --git a/gpu/command_buffer/client/program_info_manager.cc b/gpu/command_buffer/client/program_info_manager.cc
index 222e5b4a..9581a354 100644
--- a/gpu/command_buffer/client/program_info_manager.cc
+++ b/gpu/command_buffer/client/program_info_manager.cc
@@ -13,14 +13,33 @@
 static T LocalGetAs(const std::vector<int8_t>& data,
                     uint32_t offset,
                     size_t size) {
-  const int8_t* p = &data[0] + offset;
-  if (offset + size > data.size()) {
-    NOTREACHED();
-    return nullptr;
-  }
+  const int8_t* p = data.data() + offset;
+  DCHECK_LE(offset + size, data.size());
   return static_cast<T>(static_cast<const void*>(p));
 }
 
+// Writes the strimg pointed by name and of maximum size buffsize. If length is
+// !null, it receives the number of characters written (excluding the final \0).
+// This is a helper function for GetActive*Helper functions that return names.
+void FillNameAndLength(GLsizei bufsize,
+                       GLsizei* length,
+                       char* name,
+                       const std::string& string) {
+  // Length of string (without final \0) that we will write to the
+  // buffer.
+  GLsizei max_length = 0;
+  if (name && (bufsize > 0)) {
+    DCHECK_LE(string.size(), static_cast<size_t>(INT_MAX));
+    // Note: bufsize counts the terminating \0, but not string.size().
+    max_length = std::min(bufsize - 1, static_cast<GLsizei>(string.size()));
+    memcpy(name, string.data(), max_length);
+    name[max_length] = '\0';
+  }
+  if (length) {
+    *length = max_length;
+  }
+}
+
 }  // namespace
 
 namespace gpu {
@@ -812,18 +831,7 @@
         if (type) {
           *type = attrib_info->type;
         }
-        if (length || name) {
-          GLsizei max_size = std::min(
-              static_cast<size_t>(bufsize) - 1,
-              std::max(static_cast<size_t>(0), attrib_info->name.size()));
-          if (length) {
-            *length = max_size;
-          }
-          if (name && bufsize > 0) {
-            memcpy(name, attrib_info->name.c_str(), max_size);
-            name[max_size] = '\0';
-          }
-        }
+        FillNameAndLength(bufsize, length, name, attrib_info->name);
         return true;
       }
     }
@@ -848,18 +856,7 @@
         if (type) {
           *type = uniform_info->type;
         }
-        if (length || name) {
-          GLsizei max_size = std::min(
-              static_cast<size_t>(bufsize) - 1,
-              std::max(static_cast<size_t>(0), uniform_info->name.size()));
-          if (length) {
-            *length = max_size;
-          }
-          if (name && bufsize > 0) {
-            memcpy(name, uniform_info->name.c_str(), max_size);
-            name[max_size] = '\0';
-          }
-        }
+        FillNameAndLength(bufsize, length, name, uniform_info->name);
         return true;
       }
     }
@@ -884,30 +881,13 @@
     GLES2Implementation* gl, GLuint program, GLuint index,
     GLsizei buf_size, GLsizei* length, char* name) {
   DCHECK_LE(0, buf_size);
-  if (!name) {
-    buf_size = 0;
-  }
   {
     base::AutoLock auto_lock(lock_);
     Program* info = GetProgramInfo(gl, program, kES3UniformBlocks);
     if (info) {
       const Program::UniformBlock* uniform_block = info->GetUniformBlock(index);
       if (uniform_block) {
-        if (buf_size == 0) {
-          if (length) {
-            *length = 0;
-          }
-        } else if (length || name) {
-          GLsizei max_size = std::min(
-              buf_size - 1, static_cast<GLsizei>(uniform_block->name.size()));
-          if (length) {
-            *length = max_size;
-          }
-          if (name) {
-            memcpy(name, uniform_block->name.data(), max_size);
-            name[max_size] = '\0';
-          }
-        }
+        FillNameAndLength(buf_size, length, name, uniform_block->name);
         return true;
       }
     }
@@ -1009,17 +989,7 @@
         if (type) {
           *type = varying->type;
         }
-        if (length || name) {
-          GLsizei max_size = std::min(
-              bufsize - 1, static_cast<GLsizei>(varying->name.size()));
-          if (length) {
-            *length = static_cast<GLsizei>(max_size);
-          }
-          if (name && bufsize > 0) {
-            memcpy(name, varying->name.c_str(), max_size);
-            name[max_size] = '\0';
-          }
-        }
+        FillNameAndLength(bufsize, length, name, varying->name);
         return true;
       }
     }
diff --git a/gpu/command_buffer/client/query_tracker.cc b/gpu/command_buffer/client/query_tracker.cc
index ef8a972..3b08a12a 100644
--- a/gpu/command_buffer/client/query_tracker.cc
+++ b/gpu/command_buffer/client/query_tracker.cc
@@ -78,8 +78,8 @@
     bucket = buckets_.back().get();
   }
 
-  size_t index_in_bucket = 0;
-  for (size_t i = 0; i < kSyncsPerBucket; i++) {
+  uint32_t index_in_bucket = 0;
+  for (uint32_t i = 0; i < kSyncsPerBucket; i++) {
     if (!bucket->in_use_query_syncs[i]) {
       index_in_bucket = i;
       break;
diff --git a/gpu/command_buffer/client/query_tracker.h b/gpu/command_buffer/client/query_tracker.h
index c6ef0a13..d407c50 100644
--- a/gpu/command_buffer/client/query_tracker.h
+++ b/gpu/command_buffer/client/query_tracker.h
@@ -33,7 +33,7 @@
 // Manages buckets of QuerySync instances in mapped memory.
 class GLES2_IMPL_EXPORT QuerySyncManager {
  public:
-  static const size_t kSyncsPerBucket = 256;
+  static const uint32_t kSyncsPerBucket = 256;
 
   struct GLES2_IMPL_EXPORT Bucket {
     Bucket(QuerySync* sync_mem, int32_t shm_id, uint32_t shm_offset);
diff --git a/gpu/command_buffer/client/query_tracker_unittest.cc b/gpu/command_buffer/client/query_tracker_unittest.cc
index a43c9519..515e52d 100644
--- a/gpu/command_buffer/client/query_tracker_unittest.cc
+++ b/gpu/command_buffer/client/query_tracker_unittest.cc
@@ -403,7 +403,7 @@
   const int32_t kToken = 46;
   const uint32_t kResult = 456;
 
-  const size_t kTestSize = 4000;
+  const uint32_t kTestSize = 4000;
   static_assert(kTestSize > QuerySyncManager::kSyncsPerBucket,
                 "We want to use more than one bucket");
   // Create lots of queries.
diff --git a/gpu/command_buffer/client/transfer_buffer_unittest.cc b/gpu/command_buffer/client/transfer_buffer_unittest.cc
index 245c7ce..002bda4 100644
--- a/gpu/command_buffer/client/transfer_buffer_unittest.cc
+++ b/gpu/command_buffer/client/transfer_buffer_unittest.cc
@@ -33,9 +33,9 @@
   static const int32_t kNumCommandEntries = 400;
   static const int32_t kCommandBufferSizeBytes =
       kNumCommandEntries * sizeof(CommandBufferEntry);
-  static const unsigned int kStartingOffset = 64;
-  static const unsigned int kAlignment = 4;
-  static const size_t kTransferBufferSize = 256;
+  static const uint32_t kStartingOffset = 64;
+  static const uint32_t kAlignment = 4;
+  static const uint32_t kTransferBufferSize = 256;
 
   TransferBufferTest()
       : transfer_buffer_id_(0) {
@@ -91,9 +91,9 @@
 #ifndef _MSC_VER
 const int32_t TransferBufferTest::kNumCommandEntries;
 const int32_t TransferBufferTest::kCommandBufferSizeBytes;
-const unsigned int TransferBufferTest::kStartingOffset;
-const unsigned int TransferBufferTest::kAlignment;
-const size_t TransferBufferTest::kTransferBufferSize;
+const uint32_t TransferBufferTest::kStartingOffset;
+const uint32_t TransferBufferTest::kAlignment;
+const uint32_t TransferBufferTest::kTransferBufferSize;
 #endif
 
 TEST_F(TransferBufferTest, Basic) {
@@ -159,7 +159,7 @@
   EXPECT_EQ(base::UnguessableToken(), transfer_buffer_->shared_memory_guid());
 
   // See that it gets reallocated.
-  unsigned int size = 0;
+  uint32_t size = 0;
   void* data = transfer_buffer_->AllocUpTo(1, &size);
   EXPECT_TRUE(data != nullptr);
   EXPECT_TRUE(transfer_buffer_->HaveBuffer());
@@ -206,7 +206,7 @@
   void* ptr = transfer_buffer_->Alloc(kTransferBufferSize + 1);
   EXPECT_TRUE(ptr == nullptr);
   // Check we if we try to allocate larger than max we get max.
-  unsigned int size_allocated = 0;
+  uint32_t size_allocated = 0;
   ptr = transfer_buffer_->AllocUpTo(
       kTransferBufferSize + 1, &size_allocated);
   ASSERT_TRUE(ptr != nullptr);
@@ -244,11 +244,11 @@
   static const int32_t kNumCommandEntries = 400;
   static const int32_t kCommandBufferSizeBytes =
       kNumCommandEntries * sizeof(CommandBufferEntry);
-  static const unsigned int kStartingOffset = 64;
-  static const unsigned int kAlignment = 4;
-  static const size_t kStartTransferBufferSize = 256;
-  static const size_t kMaxTransferBufferSize = 1024;
-  static const size_t kMinTransferBufferSize = 128;
+  static const uint32_t kStartingOffset = 64;
+  static const uint32_t kAlignment = 4;
+  static const uint32_t kStartTransferBufferSize = 256;
+  static const uint32_t kMaxTransferBufferSize = 1024;
+  static const uint32_t kMinTransferBufferSize = 128;
 
   TransferBufferExpandContractTest()
       : transfer_buffer_id_(0) {
@@ -321,11 +321,11 @@
 #ifndef _MSC_VER
 const int32_t TransferBufferExpandContractTest::kNumCommandEntries;
 const int32_t TransferBufferExpandContractTest::kCommandBufferSizeBytes;
-const unsigned int TransferBufferExpandContractTest::kStartingOffset;
-const unsigned int TransferBufferExpandContractTest::kAlignment;
-const size_t TransferBufferExpandContractTest::kStartTransferBufferSize;
-const size_t TransferBufferExpandContractTest::kMaxTransferBufferSize;
-const size_t TransferBufferExpandContractTest::kMinTransferBufferSize;
+const uint32_t TransferBufferExpandContractTest::kStartingOffset;
+const uint32_t TransferBufferExpandContractTest::kAlignment;
+const uint32_t TransferBufferExpandContractTest::kStartTransferBufferSize;
+const uint32_t TransferBufferExpandContractTest::kMaxTransferBufferSize;
+const uint32_t TransferBufferExpandContractTest::kMinTransferBufferSize;
 #endif
 
 TEST_F(TransferBufferExpandContractTest, ExpandWithSmallAllocations) {
@@ -352,7 +352,7 @@
       transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
 
   // Fill the free space.
-  unsigned int size_allocated = 0;
+  uint32_t size_allocated = 0;
   void* ptr = transfer_buffer_->AllocUpTo(transfer_buffer_->GetFreeSize(),
                                           &size_allocated);
   transfer_buffer_->FreePendingToken(ptr, token);
@@ -399,9 +399,9 @@
             transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
 
   // Fill the free space in two blocks.
-  unsigned int block_size_1 = transfer_buffer_->GetFreeSize() / 2;
-  unsigned int block_size_2 = transfer_buffer_->GetFreeSize() - block_size_1;
-  unsigned int size_allocated = 0;
+  uint32_t block_size_1 = transfer_buffer_->GetFreeSize() / 2;
+  uint32_t block_size_2 = transfer_buffer_->GetFreeSize() - block_size_1;
+  uint32_t size_allocated = 0;
   void* block1 = transfer_buffer_->AllocUpTo(block_size_1, &size_allocated);
   EXPECT_EQ(block_size_1, size_allocated);
   void* block2 = transfer_buffer_->AllocUpTo(block_size_2, &size_allocated);
@@ -448,7 +448,7 @@
             transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
 
   // Allocate one byte more than the free space to force expansion.
-  unsigned int size_allocated = 0;
+  uint32_t size_allocated = 0;
   ExpectCreateTransferBuffer(kStartTransferBufferSize * 2);
   void* ptr = transfer_buffer_->AllocUpTo(transfer_buffer_->GetFreeSize() + 1,
                                           &size_allocated);
@@ -456,7 +456,7 @@
 
   // Expand again.
   ExpectCreateTransferBuffer(kStartTransferBufferSize * 4);
-  unsigned int size_requested = transfer_buffer_->GetFreeSize() + 1;
+  uint32_t size_requested = transfer_buffer_->GetFreeSize() + 1;
   ptr = transfer_buffer_->AllocUpTo(size_requested, &size_allocated);
   ASSERT_TRUE(ptr != nullptr);
   EXPECT_EQ(size_requested, size_allocated);
@@ -500,7 +500,7 @@
   transfer_buffer_->FreePendingToken(ptr, token);
 
   // We shouldn't shrink before we reach the allocation threshold.
-  for (size_t allocated = kMaxTransferBufferSize - kStartingOffset;
+  for (uint32_t allocated = kMaxTransferBufferSize - kStartingOffset;
        allocated < (kStartTransferBufferSize + kStartingOffset) *
                        (TransferBuffer::kShrinkThreshold);) {
     ptr = transfer_buffer_->Alloc(kStartTransferBufferSize);
@@ -545,9 +545,9 @@
           &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
       .RetiresOnSaturation();
 
-  const size_t kSize1 = 256 - kStartingOffset;
-  const size_t kSize2 = 128 - kStartingOffset;
-  unsigned int size_allocated = 0;
+  const uint32_t kSize1 = 256 - kStartingOffset;
+  const uint32_t kSize2 = 128 - kStartingOffset;
+  uint32_t size_allocated = 0;
   void* ptr = transfer_buffer_->AllocUpTo(kSize1, &size_allocated);
   ASSERT_TRUE(ptr != nullptr);
   EXPECT_EQ(kSize2, size_allocated);
@@ -602,8 +602,8 @@
            DoAll(SetArgPointee<1>(-1), Return(scoped_refptr<gpu::Buffer>())))
       .RetiresOnSaturation();
 
-  const size_t kSize1 = 512 - kStartingOffset;
-  unsigned int size_allocated = 0;
+  const uint32_t kSize1 = 512 - kStartingOffset;
+  uint32_t size_allocated = 0;
   void* ptr = transfer_buffer_->AllocUpTo(kSize1, &size_allocated);
   ASSERT_TRUE(ptr == nullptr);
   EXPECT_FALSE(transfer_buffer_->HaveBuffer());
@@ -638,9 +638,9 @@
 }
 
 TEST_F(TransferBufferExpandContractTest, Shrink) {
-  unsigned int alloc_size = transfer_buffer_->GetFreeSize();
+  uint32_t alloc_size = transfer_buffer_->GetFreeSize();
   EXPECT_EQ(kStartTransferBufferSize - kStartingOffset, alloc_size);
-  unsigned int size_allocated = 0;
+  uint32_t size_allocated = 0;
   void* ptr = transfer_buffer_->AllocUpTo(alloc_size, &size_allocated);
 
   ASSERT_NE(ptr, nullptr);
@@ -649,13 +649,13 @@
   EXPECT_EQ(0u, transfer_buffer_->GetFreeSize());
 
   // Shrink once.
-  const unsigned int shrink_size1 = 64;
+  const uint32_t shrink_size1 = 64;
   EXPECT_LT(shrink_size1, alloc_size);
   transfer_buffer_->ShrinkLastBlock(shrink_size1 - kAlignment + 1);
   EXPECT_EQ(alloc_size - shrink_size1, transfer_buffer_->GetFreeSize());
 
   // Shrink again.
-  const unsigned int shrink_size2 = 32;
+  const uint32_t shrink_size2 = 32;
   EXPECT_LT(shrink_size2, shrink_size1);
   transfer_buffer_->ShrinkLastBlock(shrink_size2);
   EXPECT_EQ(alloc_size - shrink_size2, transfer_buffer_->GetFreeSize());
@@ -669,10 +669,10 @@
 
 TEST_F(TransferBufferTest, MultipleAllocsAndFrees) {
   // An arbitrary size, but is aligned so no padding needed.
-  constexpr size_t kArbitrarySize = 16;
+  constexpr uint32_t kArbitrarySize = 16;
 
   Initialize();
-  size_t original_free_size = transfer_buffer_->GetFreeSize();
+  uint32_t original_free_size = transfer_buffer_->GetFreeSize();
   EXPECT_EQ(transfer_buffer_->GetSize(), original_free_size);
   EXPECT_EQ(transfer_buffer_->GetFragmentedFreeSize(), original_free_size);
 
@@ -750,7 +750,7 @@
   // If an attempt is made to resize the transfer buffer while a result
   // pointer exists, we should hit a CHECK. Allocate just enough to force a
   // resize.
-  unsigned int size_allocated;
+  uint32_t size_allocated;
   ASSERT_DEATH(transfer_buffer_->AllocUpTo(transfer_buffer_->GetFreeSize() + 1,
                                            &size_allocated),
                "outstanding_result_pointer_");
@@ -761,7 +761,7 @@
   ScopedResultPtr<int> ptr(transfer_buffer_.get());
   // If an attempt is made to allocate any amount in the transfer buffer while a
   // result pointer exists, we should hit a DCHECK.
-  unsigned int size_allocated;
+  uint32_t size_allocated;
   ASSERT_DEATH(transfer_buffer_->AllocUpTo(transfer_buffer_->GetFreeSize() + 1,
                                            &size_allocated),
                "outstanding_result_pointer_");
diff --git a/gpu/command_buffer/client/webgpu_implementation_unittest.cc b/gpu/command_buffer/client/webgpu_implementation_unittest.cc
index 384b0fe..3238cc1 100644
--- a/gpu/command_buffer/client/webgpu_implementation_unittest.cc
+++ b/gpu/command_buffer/client/webgpu_implementation_unittest.cc
@@ -31,10 +31,10 @@
 class WebGPUImplementationTest : public testing::Test {
  protected:
   static const uint8_t kInitialValue = 0xBD;
-  static const int32_t kNumCommandEntries = 500;
-  static const int32_t kCommandBufferSizeBytes =
+  static const uint32_t kNumCommandEntries = 500;
+  static const uint32_t kCommandBufferSizeBytes =
       kNumCommandEntries * sizeof(CommandBufferEntry);
-  static const size_t kTransferBufferSize = 512;
+  static const uint32_t kTransferBufferSize = 512;
 
   static const GLint kMaxCombinedTextureImageUnits = 8;
   static const GLint kMaxTextureImageUnits = 8;
diff --git a/ios/chrome/OWNERS b/ios/chrome/OWNERS
index 6d6a2dc..06a12ae5 100644
--- a/ios/chrome/OWNERS
+++ b/ios/chrome/OWNERS
@@ -6,5 +6,8 @@
 # structural changes, please get a review from an OWNER.
 per-file BUILD.gn=*
 
+# Translation artifacts:
+per-file *.xtb=file://tools/translation/TRANSLATION_OWNERS
+
 # TEAM: ios-directory-owners@chromium.org
 # OS: iOS
diff --git a/ios/chrome/browser/sync/ios_chrome_synced_tab_delegate.mm b/ios/chrome/browser/sync/ios_chrome_synced_tab_delegate.mm
index 63735f3..2b9d553 100644
--- a/ios/chrome/browser/sync/ios_chrome_synced_tab_delegate.mm
+++ b/ios/chrome/browser/sync/ios_chrome_synced_tab_delegate.mm
@@ -79,6 +79,7 @@
 }
 
 GURL IOSChromeSyncedTabDelegate::GetFaviconURLAtIndex(int i) const {
+  DCHECK_GE(i, 0);
   NavigationItem* item = GetPossiblyPendingItemAtIndex(web_state_, i);
   return (item->GetFavicon().valid ? item->GetFavicon().url : GURL());
 }
diff --git a/ios/chrome/browser/tabs/tab_model_synced_window_delegate.mm b/ios/chrome/browser/tabs/tab_model_synced_window_delegate.mm
index 5365ff9..673288da 100644
--- a/ios/chrome/browser/tabs/tab_model_synced_window_delegate.mm
+++ b/ios/chrome/browser/tabs/tab_model_synced_window_delegate.mm
@@ -9,6 +9,7 @@
 #include "ios/chrome/browser/sessions/ios_chrome_session_tab_helper.h"
 #include "ios/chrome/browser/sync/ios_chrome_synced_tab_delegate.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
+#import "ios/web/public/navigation_manager.h"
 #import "ios/web/public/web_state/web_state.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -33,6 +34,13 @@
 }
 
 bool TabModelSyncedWindowDelegate::IsSessionRestoreInProgress() const {
+  for (int index = 0; index < web_state_list_->count(); ++index) {
+    const web::NavigationManager* navigation_manager =
+        web_state_list_->GetWebStateAt(index)->GetNavigationManager();
+    if (navigation_manager->IsRestoreSessionInProgress()) {
+      return true;
+    }
+  }
   return false;
 }
 
diff --git a/ios/chrome/browser/ui/settings/autofill_profile_table_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/autofill_profile_table_view_controller_unittest.mm
index b48d5519..e587f86c 100644
--- a/ios/chrome/browser/ui/settings/autofill_profile_table_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/settings/autofill_profile_table_view_controller_unittest.mm
@@ -81,7 +81,8 @@
 }
 
 // Adding a single address results in an address section.
-TEST_F(AutofillProfileTableViewControllerTest, TestOneProfile) {
+// TODO(crbug.com/919967): Reenable this test.
+TEST_F(AutofillProfileTableViewControllerTest, DISABLED_TestOneProfile) {
   AddProfile("https://www.example.com/", "John Doe", "1 Main Street");
   CreateController();
   CheckController();
@@ -93,7 +94,9 @@
 }
 
 // Deleting the only profile results in item deletion and section deletion.
-TEST_F(AutofillProfileTableViewControllerTest, TestOneProfileItemDeleted) {
+// TODO(crbug.com/919968): Reenable this test.
+TEST_F(AutofillProfileTableViewControllerTest,
+       DISABLED_TestOneProfileItemDeleted) {
   AddProfile("https://www.example.com/", "John Doe", "1 Main Street");
   CreateController();
   CheckController();
diff --git a/ios/web/navigation/navigation_manager_impl.h b/ios/web/navigation/navigation_manager_impl.h
index 698a554..194a76f6d 100644
--- a/ios/web/navigation/navigation_manager_impl.h
+++ b/ios/web/navigation/navigation_manager_impl.h
@@ -142,12 +142,6 @@
                                            NSString* state_object,
                                            ui::PageTransition transition) = 0;
 
-  // Returns true after session restoration has started, until the first
-  // post-restore navigation is finished. Returns true when first post-restore
-  // navigation is started, even though technically session restoration is
-  // complete.
-  virtual bool IsRestoreSessionInProgress() const = 0;
-
   // Sets the index of the pending navigation item. -1 means no navigation or a
   // new navigation.
   virtual void SetPendingItemIndex(int index) = 0;
diff --git a/ios/web/public/navigation_manager.h b/ios/web/public/navigation_manager.h
index 4c4e4100..09c1398 100644
--- a/ios/web/public/navigation_manager.h
+++ b/ios/web/public/navigation_manager.h
@@ -196,6 +196,12 @@
   virtual void Restore(int last_committed_item_index,
                        std::vector<std::unique_ptr<NavigationItem>> items) = 0;
 
+  // Returns true after session restoration has started, until the first
+  // post-restore navigation is finished. Returns true when first post-restore
+  // navigation is started, even though technically session restoration is
+  // complete.
+  virtual bool IsRestoreSessionInProgress() const = 0;
+
   // Registers a callback to be run when session restoration is completed.
   // If there is no in-progress session restoration, the callback is run
   // immediately.
diff --git a/ios/web/public/test/fakes/test_navigation_manager.h b/ios/web/public/test/fakes/test_navigation_manager.h
index a924ca4b..b94aade 100644
--- a/ios/web/public/test/fakes/test_navigation_manager.h
+++ b/ios/web/public/test/fakes/test_navigation_manager.h
@@ -48,6 +48,7 @@
   NavigationItemList GetForwardItems() const override;
   void Restore(int last_committed_item_index,
                std::vector<std::unique_ptr<NavigationItem>> items) override;
+  bool IsRestoreSessionInProgress() const override;
   void AddRestoreCompletionCallback(base::OnceClosure callback) override;
   void CopyStateFromAndPrune(const NavigationManager* source) override;
   bool CanPruneAllButLastCommittedItem() const override;
diff --git a/ios/web/public/test/fakes/test_navigation_manager.mm b/ios/web/public/test/fakes/test_navigation_manager.mm
index 62f93ba..3590e53 100644
--- a/ios/web/public/test/fakes/test_navigation_manager.mm
+++ b/ios/web/public/test/fakes/test_navigation_manager.mm
@@ -167,6 +167,10 @@
   NOTREACHED();
 }
 
+bool TestNavigationManager::IsRestoreSessionInProgress() const {
+  return false;
+}
+
 void TestNavigationManager::AddRestoreCompletionCallback(
     base::OnceClosure callback) {
   NOTREACHED();
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 41e534d..bdb60dc 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -1290,7 +1290,10 @@
       !IsWKInternalUrl(newURL) && !newURL.SchemeIs(url::kAboutScheme) &&
       _webView) {
     GURL documentOrigin = newURL.GetOrigin();
-    GURL committedOrigin = _webStateImpl->GetLastCommittedURL().GetOrigin();
+    web::NavigationItem* committedItem =
+        _webStateImpl->GetNavigationManager()->GetLastCommittedItem();
+    GURL committedOrigin =
+        committedItem ? committedItem->GetURL().GetOrigin() : GURL::EmptyGURL();
     DCHECK_EQ(documentOrigin, committedOrigin)
         << "Old and new URL detection system have a mismatch";
 
diff --git a/media/audio/BUILD.gn b/media/audio/BUILD.gn
index ae293df..d987050 100644
--- a/media/audio/BUILD.gn
+++ b/media/audio/BUILD.gn
@@ -272,7 +272,10 @@
       "cras/cras_unified.h",
     ]
     configs += [ ":libcras" ]
-    deps += [ "//chromeos:chromeos" ]
+    deps += [
+      "//chromeos",
+      "//chromeos/audio",
+    ]
   }
 
   if (use_pulseaudio) {
@@ -431,7 +434,10 @@
     ]
 
     if (!is_chromecast) {
-      deps += [ "//chromeos:chromeos" ]
+      deps += [
+        "//chromeos",
+        "//chromeos/audio",
+      ]
     }
 
     if (use_cras) {
diff --git a/media/base/BUILD.gn b/media/base/BUILD.gn
index c79d7af..5cfbf6c 100644
--- a/media/base/BUILD.gn
+++ b/media/base/BUILD.gn
@@ -374,6 +374,7 @@
 
   if (is_win) {
     deps += [ "//media/base/win" ]
+    public_deps += [ "//media/base/win:d3d11" ]
   }
 
   if (is_chromecast) {
@@ -456,6 +457,10 @@
     "//ui/gfx:test_support",
     "//url",
   ]
+
+  if (is_win) {
+    public_deps += [ "//media/base/win:d3d11_test_support" ]
+  }
 }
 
 source_set("unit_tests") {
diff --git a/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java b/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java
index 19fc077..92dfa25 100644
--- a/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java
+++ b/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java
@@ -546,6 +546,27 @@
     }
 
     /**
+     * Provision the current origin. Normally provisioning will be triggered
+     * automatically when MediaCrypto is needed (in the constructor).
+     * However, this is available to preprovision an origin separately.
+     * nativeOnProvisioningComplete() will be called indicating success/failure.
+     */
+    @CalledByNative
+    private void provision() {
+        // This should only be called if no MediaCrypto needed.
+        assert mMediaDrm != null;
+        assert !mRequiresMediaCrypto;
+
+        // Provision only works for origin isolated storage.
+        if (!mOriginSet) {
+            nativeOnProvisioningComplete(mNativeMediaDrmBridge, false);
+            return;
+        }
+
+        startProvisioning();
+    }
+
+    /**
      * Unprovision the current origin, a.k.a removing the cert for current origin.
      */
     @CalledByNative
@@ -1082,8 +1103,7 @@
         }
 
         MediaDrm.ProvisionRequest request = mMediaDrm.getProvisionRequest();
-        nativeOnStartProvisioning(
-                mNativeMediaDrmBridge, request.getDefaultUrl(), request.getData());
+        nativeOnProvisionRequest(mNativeMediaDrmBridge, request.getDefaultUrl(), request.getData());
     }
 
     /**
@@ -1141,18 +1161,25 @@
     }
 
     /*
-     *  Continue to createMediaCrypto() after provisioning.
+     *  Provisioning complete. Continue to createMediaCrypto() if required.
      *
      * @param success Whether provisioning has succeeded or not.
      */
     void onProvisioned(boolean success) {
+        if (!mRequiresMediaCrypto) {
+            // No MediaCrypto required, so notify provisioning complete.
+            nativeOnProvisioningComplete(mNativeMediaDrmBridge, success);
+            if (!success) {
+                release();
+            }
+            return;
+        }
+
         if (!success) {
             release();
             return;
         }
 
-        assert mRequiresMediaCrypto;
-
         if (!mOriginSet) {
             createMediaCrypto();
             return;
@@ -1409,8 +1436,9 @@
     private native void nativeOnMediaCryptoReady(
             long nativeMediaDrmBridge, MediaCrypto mediaCrypto);
 
-    private native void nativeOnStartProvisioning(
+    private native void nativeOnProvisionRequest(
             long nativeMediaDrmBridge, String defaultUrl, byte[] requestData);
+    private native void nativeOnProvisioningComplete(long nativeMediaDrmBridge, boolean success);
 
     private native void nativeOnPromiseResolved(long nativeMediaDrmBridge, long promiseId);
     private native void nativeOnPromiseResolvedWithSession(
diff --git a/media/base/android/media_drm_bridge.cc b/media/base/android/media_drm_bridge.cc
index c148b97..9d2d1f09 100644
--- a/media/base/android/media_drm_bridge.cc
+++ b/media/base/android/media_drm_bridge.cc
@@ -343,7 +343,7 @@
       std::move(storage), create_fetcher_cb, session_message_cb,
       session_closed_cb, session_keys_change_cb, session_expiration_update_cb));
 
-  if (media_drm_bridge->j_media_drm_.is_null())
+  if (!media_drm_bridge->j_media_drm_)
     return nullptr;
 
   return media_drm_bridge;
@@ -433,7 +433,7 @@
     }
   }
 
-  if (j_init_data.is_null()) {
+  if (!j_init_data) {
     j_init_data =
         base::android::ToJavaByteArray(env, init_data.data(), init_data.size());
   }
@@ -562,6 +562,17 @@
   return true;
 }
 
+void MediaDrmBridge::Provision(
+    base::OnceCallback<void(bool)> provisioning_complete_cb) {
+  DVLOG(1) << __func__;
+  DCHECK(provisioning_complete_cb);
+  DCHECK(!provisioning_complete_cb_);
+  provisioning_complete_cb_ = std::move(provisioning_complete_cb);
+
+  JNIEnv* env = AttachCurrentThread();
+  Java_MediaDrmBridge_provision(env, j_media_drm_);
+}
+
 void MediaDrmBridge::Unprovision() {
   DVLOG(1) << __func__;
 
@@ -633,7 +644,7 @@
                      base::Passed(CreateJavaObjectPtr(j_media_crypto.obj()))));
 }
 
-void MediaDrmBridge::OnStartProvisioning(
+void MediaDrmBridge::OnProvisionRequest(
     JNIEnv* env,
     const JavaParamRef<jobject>& j_media_drm,
     const JavaParamRef<jstring>& j_default_url,
@@ -649,6 +660,18 @@
                                 std::move(request_data)));
 }
 
+void MediaDrmBridge::OnProvisioningComplete(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& j_media_drm,
+    bool success) {
+  DVLOG(1) << __func__;
+
+  // This should only be called as result of a call to Provision().
+  DCHECK(provisioning_complete_cb_);
+  task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(std::move(provisioning_complete_cb_), success));
+}
+
 void MediaDrmBridge::OnPromiseResolved(JNIEnv* env,
                                        const JavaParamRef<jobject>& j_media_drm,
                                        jint j_promise_id) {
@@ -853,7 +876,7 @@
 
   // After the call to Java_MediaDrmBridge_destroy() Java won't call native
   // methods anymore, this is ensured by MediaDrmBridge.java.
-  if (!j_media_drm_.is_null())
+  if (j_media_drm_)
     Java_MediaDrmBridge_destroy(env, j_media_drm_);
 
   player_tracker_.NotifyCdmUnset();
diff --git a/media/base/android/media_drm_bridge.h b/media/base/android/media_drm_bridge.h
index fd9aff8..c801361 100644
--- a/media/base/android/media_drm_bridge.h
+++ b/media/base/android/media_drm_bridge.h
@@ -124,6 +124,11 @@
   // CdmContext implementation.
   MediaCryptoContext* GetMediaCryptoContext() override;
 
+  // Provision the origin bound with |this|. |provisioning_complete_cb| will be
+  // called asynchronously to indicate whether this was successful or not.
+  // MediaDrmBridge must be created with a valid origin ID.
+  void Provision(base::OnceCallback<void(bool)> provisioning_complete_cb);
+
   // Unprovision the origin bound with |this|. This will remove the cert for
   // current origin and leave the offline licenses in invalid state (offline
   // licenses can't be used anymore).
@@ -169,12 +174,19 @@
       const base::android::JavaParamRef<jobject>& j_media_crypto);
 
   // Called by Java when we need to send a provisioning request,
-  void OnStartProvisioning(
+  void OnProvisionRequest(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& j_media_drm,
       const base::android::JavaParamRef<jstring>& j_default_url,
       const base::android::JavaParamRef<jbyteArray>& j_request_data);
 
+  // Called by Java when provisioning is complete. This is only in response to a
+  // provision() request.
+  void OnProvisioningComplete(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& j_media_drm,
+      bool success);
+
   // Callbacks to resolve the promise for |promise_id|.
   void OnPromiseResolved(
       JNIEnv* env,
@@ -316,6 +328,9 @@
   // Non-null iff when a provision request is pending.
   std::unique_ptr<ProvisionFetcher> provision_fetcher_;
 
+  // The callback to be called when provisioning is complete.
+  base::OnceCallback<void(bool)> provisioning_complete_cb_;
+
   // Callbacks for firing session events.
   SessionMessageCB session_message_cb_;
   SessionClosedCB session_closed_cb_;
diff --git a/media/base/android/media_drm_bridge_unittest.cc b/media/base/android/media_drm_bridge_unittest.cc
index 2458dfd0..664854d7 100644
--- a/media/base/android/media_drm_bridge_unittest.cc
+++ b/media/base/android/media_drm_bridge_unittest.cc
@@ -6,14 +6,20 @@
 
 #include "base/android/build_info.h"
 #include "base/bind.h"
+#include "base/bind_helpers.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
 #include "media/base/android/media_drm_bridge.h"
 #include "media/base/provision_fetcher.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/widevine/cdm/widevine_cdm_common.h"
 
+using ::testing::_;
+using ::testing::StrictMock;
+
 namespace media {
 
 #define EXPECT_TRUE_IF_WIDEVINE_AVAILABLE(a)                              \
@@ -36,6 +42,7 @@
 const MediaDrmBridge::SecurityLevel kL1 = MediaDrmBridge::SECURITY_LEVEL_1;
 const MediaDrmBridge::SecurityLevel kL3 = MediaDrmBridge::SECURITY_LEVEL_3;
 const char kTestOrigin[] = "http://www.example.com";
+const char kEmptyOrigin[] = "";
 
 // Helper functions to avoid typing "MediaDrmBridge::" in tests.
 
@@ -47,21 +54,72 @@
 }
 
 namespace {
-// Mock ProvisionFetcher.
-class MockProvisionFetcher : public ProvisionFetcher {
+
+// This class is simply a wrapper that passes on calls to Retrieve() to another
+// implementation that is provided to the constructor. This is created as
+// MediaDrmBridge::CreateWithoutSessionSupport() requires the creation of a new
+// ProvisionFetcher each time it needs to retrieve a license from the license
+// server.
+class ProvisionFetcherWrapper : public ProvisionFetcher {
  public:
-  static std::unique_ptr<ProvisionFetcher> Create() {
-    return base::WrapUnique(new MockProvisionFetcher);
-  }
+  explicit ProvisionFetcherWrapper(ProvisionFetcher* provision_fetcher)
+      : provision_fetcher_(provision_fetcher) {}
 
   // ProvisionFetcher implementation.
   void Retrieve(const std::string& default_url,
                 const std::string& request_data,
-                const ResponseCB& response_cb) override {}
-};
-}  // namespace (anonymous)
+                const ResponseCB& response_cb) override {
+    provision_fetcher_->Retrieve(default_url, request_data, response_cb);
+  }
 
-TEST(MediaDrmBridgeTest, IsKeySystemSupported_Widevine) {
+ private:
+  ProvisionFetcher* provision_fetcher_;
+};
+
+}  // namespace
+
+class MediaDrmBridgeTest : public ProvisionFetcher, public testing::Test {
+ public:
+  MediaDrmBridgeTest() {}
+
+  void CreateWithoutSessionSupport(
+      const std::string& key_system,
+      const std::string& origin_id,
+      MediaDrmBridge::SecurityLevel security_level) {
+    media_drm_bridge_ = MediaDrmBridge::CreateWithoutSessionSupport(
+        key_system, origin_id, security_level,
+        base::BindRepeating(&MediaDrmBridgeTest::CreateProvisionFetcher,
+                            base::Unretained(this)));
+  }
+
+  // ProvisionFetcher implementation. Done as a mock method so we can properly
+  // check if |media_drm_bridge_| invokes it or not.
+  MOCK_METHOD3(Retrieve,
+               void(const std::string& default_url,
+                    const std::string& request_data,
+                    const ResponseCB& response_cb));
+
+  void Provision() {
+    media_drm_bridge_->Provision(base::BindOnce(
+        &MediaDrmBridgeTest::ProvisioningDone, base::Unretained(this)));
+  }
+
+  // MediaDrmBridge::Provision() requires a callback that is called when
+  // provisioning completes and indicates if it succeeds or not.
+  MOCK_METHOD1(ProvisioningDone, void(bool));
+
+ protected:
+  scoped_refptr<MediaDrmBridge> media_drm_bridge_;
+
+ private:
+  std::unique_ptr<ProvisionFetcher> CreateProvisionFetcher() {
+    return std::make_unique<ProvisionFetcherWrapper>(this);
+  }
+
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+};
+
+TEST_F(MediaDrmBridgeTest, IsKeySystemSupported_Widevine) {
   // TODO(xhwang): Enable when b/13564917 is fixed.
   // EXPECT_TRUE_IF_AVAILABLE(
   //     IsKeySystemSupportedWithType(kWidevineKeySystem, kAudioMp4));
@@ -85,7 +143,7 @@
 }
 
 // Invalid key system is NOT supported regardless whether MediaDrm is available.
-TEST(MediaDrmBridgeTest, IsKeySystemSupported_InvalidKeySystem) {
+TEST_F(MediaDrmBridgeTest, IsKeySystemSupported_InvalidKeySystem) {
   EXPECT_FALSE(MediaDrmBridge::IsKeySystemSupported(kInvalidKeySystem));
   EXPECT_FALSE(IsKeySystemSupportedWithType(kInvalidKeySystem, kAudioMp4));
   EXPECT_FALSE(IsKeySystemSupportedWithType(kInvalidKeySystem, kVideoMp4));
@@ -96,33 +154,81 @@
   EXPECT_FALSE(IsKeySystemSupportedWithType(kInvalidKeySystem, "audio/mp3"));
 }
 
-TEST(MediaDrmBridgeTest, CreateWithoutSessionSupport_Widevine) {
-  base::MessageLoop message_loop_;
-  EXPECT_TRUE_IF_WIDEVINE_AVAILABLE(MediaDrmBridge::CreateWithoutSessionSupport(
-      kWidevineKeySystem, kTestOrigin, kDefault,
-      base::Bind(&MockProvisionFetcher::Create)));
+TEST_F(MediaDrmBridgeTest, CreateWithoutSessionSupport_Widevine) {
+  CreateWithoutSessionSupport(kWidevineKeySystem, kTestOrigin, kDefault);
+  EXPECT_TRUE_IF_WIDEVINE_AVAILABLE(media_drm_bridge_);
 }
 
 // Invalid key system is NOT supported regardless whether MediaDrm is available.
-TEST(MediaDrmBridgeTest, CreateWithoutSessionSupport_InvalidKeySystem) {
-  base::MessageLoop message_loop_;
-  EXPECT_FALSE(MediaDrmBridge::CreateWithoutSessionSupport(
-      kInvalidKeySystem, kTestOrigin, kDefault,
-      base::Bind(&MockProvisionFetcher::Create)));
+TEST_F(MediaDrmBridgeTest, CreateWithoutSessionSupport_InvalidKeySystem) {
+  CreateWithoutSessionSupport(kInvalidKeySystem, kTestOrigin, kDefault);
+  EXPECT_FALSE(media_drm_bridge_);
 }
 
-TEST(MediaDrmBridgeTest, CreateWithSecurityLevel_Widevine) {
-  base::MessageLoop message_loop_;
-
+TEST_F(MediaDrmBridgeTest, CreateWithSecurityLevel_Widevine) {
   // We test "L3" fully. But for "L1" we don't check the result as it depends on
   // whether the test device supports "L1".
-  EXPECT_TRUE_IF_WIDEVINE_AVAILABLE(MediaDrmBridge::CreateWithoutSessionSupport(
-      kWidevineKeySystem, kTestOrigin, kL3,
-      base::Bind(&MockProvisionFetcher::Create)));
+  CreateWithoutSessionSupport(kWidevineKeySystem, kTestOrigin, kL3);
+  EXPECT_TRUE_IF_WIDEVINE_AVAILABLE(media_drm_bridge_);
 
-  MediaDrmBridge::CreateWithoutSessionSupport(
-      kWidevineKeySystem, kTestOrigin, kL1,
-      base::Bind(&MockProvisionFetcher::Create));
+  CreateWithoutSessionSupport(kWidevineKeySystem, kTestOrigin, kL1);
+}
+
+TEST_F(MediaDrmBridgeTest, Provision_Widevine) {
+  // Only test this if Widevine is supported. Otherwise
+  // CreateWithoutSessionSupport() will return null and it can't be tested.
+  if (!MediaDrmBridge::IsKeySystemSupported(kWidevineKeySystem)) {
+    VLOG(0) << "Widevine not supported on device.";
+    return;
+  }
+
+  // Provisioning requires the use of origin isolated storage, so skip this test
+  // if it's not supported.
+  if (!MediaDrmBridge::IsPerOriginProvisioningSupported()) {
+    VLOG(0) << "Origin isolated storage not supported on device.";
+    return;
+  }
+
+  // Calling Provision() later should trigger a provisioning request. As we
+  // can't pass the request to a license server,
+  // MockProvisionFetcher::Retrieve() simply drops the request and never
+  // responds. As a result, there should be a call to Retrieve() but not to
+  // ProvisioningDone() (CB passed to Provision()) as the provisioning never
+  // completes.
+  EXPECT_CALL(*this, Retrieve(_, _, _));
+  EXPECT_CALL(*this, ProvisioningDone(_)).Times(0);
+
+  // Create MediaDrmBridge. We only test "L3" as "L1" depends on whether the
+  // test device supports it or not.
+  CreateWithoutSessionSupport(kWidevineKeySystem, kTestOrigin, kL3);
+  EXPECT_TRUE(media_drm_bridge_);
+  Provision();
+
+  // ProvisioningDone() callback is executed asynchronously.
+  base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(MediaDrmBridgeTest, Provision_Widevine_NoOrigin) {
+  // Only test this if Widevine is supported. Otherwise
+  // CreateWithoutSessionSupport() will return null and it can't be tested.
+  if (!MediaDrmBridge::IsKeySystemSupported(kWidevineKeySystem)) {
+    VLOG(0) << "Widevine not supported on device.";
+    return;
+  }
+
+  // Calling Provision() later should fail as the origin is not provided (or
+  // origin isolated storage is not available). No provisioning request should
+  // be attempted.
+  EXPECT_CALL(*this, ProvisioningDone(false));
+
+  // Create MediaDrmBridge. We only test "L3" as "L1" depends on whether the
+  // test device supports it or not.
+  CreateWithoutSessionSupport(kWidevineKeySystem, kEmptyOrigin, kL3);
+  EXPECT_TRUE(media_drm_bridge_);
+  Provision();
+
+  // ProvisioningDone() callback is executed asynchronously.
+  base::RunLoop().RunUntilIdle();
 }
 
 }  // namespace media
diff --git a/media/base/mock_filters.cc b/media/base/mock_filters.cc
index 0cb8b411..249413d 100644
--- a/media/base/mock_filters.cc
+++ b/media/base/mock_filters.cc
@@ -37,6 +37,10 @@
   Resume(&renderer, timestamp, seek_cb);
 }
 
+MockMediaResource::MockMediaResource() = default;
+
+MockMediaResource::~MockMediaResource() = default;
+
 MockDemuxer::MockDemuxer() = default;
 
 MockDemuxer::~MockDemuxer() = default;
diff --git a/media/base/mock_filters.h b/media/base/mock_filters.h
index 680e2ee..6afb8e7 100644
--- a/media/base/mock_filters.h
+++ b/media/base/mock_filters.h
@@ -127,6 +127,18 @@
   DISALLOW_COPY_AND_ASSIGN(MockPipeline);
 };
 
+class MockMediaResource : public MediaResource {
+ public:
+  MockMediaResource();
+  ~MockMediaResource() override;
+
+  // MediaResource implementation.
+  MOCK_CONST_METHOD0(GetType, MediaResource::Type());
+  MOCK_METHOD0(GetAllStreams, std::vector<DemuxerStream*>());
+  MOCK_METHOD1(GetFirstStream, DemuxerStream*(DemuxerStream::Type type));
+  MOCK_CONST_METHOD0(GetMediaUrlParams, MediaUrlParams());
+};
+
 class MockDemuxer : public Demuxer {
  public:
   MockDemuxer();
diff --git a/media/base/win/BUILD.gn b/media/base/win/BUILD.gn
index 1950ff1b..b0965ee1 100644
--- a/media/base/win/BUILD.gn
+++ b/media/base/win/BUILD.gn
@@ -44,3 +44,25 @@
   # MediaFoundation is not available on Windows N, so must be delay loaded.
   all_dependent_configs = [ ":delay_load_mf" ]
 }
+
+source_set("d3d11") {
+  sources = [
+    "d3d11_create_device_cb.h",
+  ]
+  deps = [
+    "//base",
+  ]
+}
+
+source_set("d3d11_test_support") {
+  testonly = true
+  sources = [
+    "d3d11_mocks.cc",
+    "d3d11_mocks.h",
+  ]
+  deps = [
+    ":d3d11",
+    "//base",
+    "//testing/gmock",
+  ]
+}
diff --git a/media/gpu/windows/d3d11_create_device_cb.h b/media/base/win/d3d11_create_device_cb.h
similarity index 86%
rename from media/gpu/windows/d3d11_create_device_cb.h
rename to media/base/win/d3d11_create_device_cb.h
index 5b505298..3f9cf8f 100644
--- a/media/gpu/windows/d3d11_create_device_cb.h
+++ b/media/base/win/d3d11_create_device_cb.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef MEDIA_GPU_WINDOWS_D3D11_CREATE_DEVICE_CB_H_
-#define MEDIA_GPU_WINDOWS_D3D11_CREATE_DEVICE_CB_H_
+#ifndef MEDIA_BASE_WIN_D3D11_CREATE_DEVICE_CB_H_
+#define MEDIA_BASE_WIN_D3D11_CREATE_DEVICE_CB_H_
 
 #include <d3d11_1.h>
 #include <wrl/client.h>
@@ -30,4 +30,4 @@
                                     ID3D11DeviceContext**)>;
 }  // namespace media
 
-#endif  // MEDIA_GPU_WINDOWS_D3D11_CREATE_DEVICE_CB_H_
+#endif  // MEDIA_BASE_WIN_D3D11_CREATE_DEVICE_CB_H_
diff --git a/media/gpu/windows/d3d11_mocks.cc b/media/base/win/d3d11_mocks.cc
similarity index 97%
rename from media/gpu/windows/d3d11_mocks.cc
rename to media/base/win/d3d11_mocks.cc
index a32f299..a2e34df5 100644
--- a/media/gpu/windows/d3d11_mocks.cc
+++ b/media/base/win/d3d11_mocks.cc
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "media/gpu/windows/d3d11_mocks.h"
+#include "media/base/win/d3d11_mocks.h"
+
 namespace media {
 
 D3D11CreateDeviceMock::D3D11CreateDeviceMock() = default;
diff --git a/media/gpu/windows/d3d11_mocks.h b/media/base/win/d3d11_mocks.h
similarity index 99%
rename from media/gpu/windows/d3d11_mocks.h
rename to media/base/win/d3d11_mocks.h
index 6c4d01b..eacb856 100644
--- a/media/gpu/windows/d3d11_mocks.h
+++ b/media/base/win/d3d11_mocks.h
@@ -1,8 +1,9 @@
 // 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 MEDIA_GPU_WINDOWS_D3D11_MOCKS_H_
-#define MEDIA_GPU_WINDOWS_D3D11_MOCKS_H_
+
+#ifndef MEDIA_BASE_WIN_D3D11_MOCKS_H_
+#define MEDIA_BASE_WIN_D3D11_MOCKS_H_
 
 #include <d3d11.h>
 #include <d3d11_1.h>
@@ -11,7 +12,7 @@
 #include <wrl/implements.h>
 
 #include "base/win/iunknown_impl.h"
-#include "media/gpu/windows/d3d11_create_device_cb.h"
+#include "media/base/win/d3d11_create_device_cb.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 #define MOCK_STDCALL_METHOD0(Name, Types) \
@@ -1594,4 +1595,4 @@
 #undef MOCK_STDCALL_METHOD8
 #undef MOCK_STDCALL_METHOD9
 
-#endif  // MEDIA_GPU_WINDOWS_D3D11_MOCKS_H_
+#endif  // MEDIA_BASE_WIN_D3D11_MOCKS_H_
diff --git a/media/filters/decrypting_media_resource.cc b/media/filters/decrypting_media_resource.cc
index 8f783923..8a131d9f 100644
--- a/media/filters/decrypting_media_resource.cc
+++ b/media/filters/decrypting_media_resource.cc
@@ -29,6 +29,7 @@
       task_runner_(task_runner),
       weak_factory_(this) {
   DCHECK(media_resource);
+  DCHECK_EQ(MediaResource::STREAM, media_resource->GetType());
   DCHECK(cdm_context_);
   DCHECK(cdm_context_->GetDecryptor());
   DCHECK(cdm_context_->GetDecryptor()->CanAlwaysDecrypt());
diff --git a/media/gpu/BUILD.gn b/media/gpu/BUILD.gn
index 7d18871..4cb2e5c9 100644
--- a/media/gpu/BUILD.gn
+++ b/media/gpu/BUILD.gn
@@ -251,7 +251,6 @@
 
   if (is_win) {
     sources += [
-      "windows/d3d11_create_device_cb.h",
       "windows/d3d11_h264_accelerator.cc",
       "windows/d3d11_h264_accelerator.h",
       "windows/d3d11_picture_buffer.cc",
@@ -622,8 +621,6 @@
     sources += [
       "windows/d3d11_cdm_proxy_unittest.cc",
       "windows/d3d11_decryptor_unittest.cc",
-      "windows/d3d11_mocks.cc",
-      "windows/d3d11_mocks.h",
       "windows/d3d11_video_decoder_unittest.cc",
     ]
     libs = [ "dxguid.lib" ]
diff --git a/media/gpu/windows/d3d11_cdm_proxy.h b/media/gpu/windows/d3d11_cdm_proxy.h
index 0651f03..1fb77103f 100644
--- a/media/gpu/windows/d3d11_cdm_proxy.h
+++ b/media/gpu/windows/d3d11_cdm_proxy.h
@@ -16,8 +16,8 @@
 
 #include "base/callback.h"
 #include "base/memory/weak_ptr.h"
+#include "media/base/win/d3d11_create_device_cb.h"
 #include "media/gpu/media_gpu_export.h"
-#include "media/gpu/windows/d3d11_create_device_cb.h"
 
 namespace media {
 
diff --git a/media/gpu/windows/d3d11_cdm_proxy_unittest.cc b/media/gpu/windows/d3d11_cdm_proxy_unittest.cc
index f4887ece..ff24d6b 100644
--- a/media/gpu/windows/d3d11_cdm_proxy_unittest.cc
+++ b/media/gpu/windows/d3d11_cdm_proxy_unittest.cc
@@ -15,8 +15,8 @@
 #include "base/test/mock_callback.h"
 #include "base/test/scoped_task_environment.h"
 #include "media/base/callback_registry.h"
+#include "media/base/win/d3d11_mocks.h"
 #include "media/cdm/cdm_proxy_context.h"
-#include "media/gpu/windows/d3d11_mocks.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using Microsoft::WRL::ComPtr;
diff --git a/media/gpu/windows/d3d11_decryptor.h b/media/gpu/windows/d3d11_decryptor.h
index 2eb3ebff9..b8a1a761 100644
--- a/media/gpu/windows/d3d11_decryptor.h
+++ b/media/gpu/windows/d3d11_decryptor.h
@@ -11,9 +11,9 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "media/base/decryptor.h"
+#include "media/base/win/d3d11_create_device_cb.h"
 #include "media/cdm/cdm_proxy_context.h"
 #include "media/gpu/media_gpu_export.h"
-#include "media/gpu/windows/d3d11_create_device_cb.h"
 
 namespace media {
 
diff --git a/media/gpu/windows/d3d11_decryptor_unittest.cc b/media/gpu/windows/d3d11_decryptor_unittest.cc
index 134e9b5..f00dbec 100644
--- a/media/gpu/windows/d3d11_decryptor_unittest.cc
+++ b/media/gpu/windows/d3d11_decryptor_unittest.cc
@@ -13,8 +13,8 @@
 #include "base/stl_util.h"
 #include "media/base/decoder_buffer.h"
 #include "media/base/subsample_entry.h"
+#include "media/base/win/d3d11_mocks.h"
 #include "media/cdm/cdm_proxy_context.h"
-#include "media/gpu/windows/d3d11_mocks.h"
 
 using ::testing::_;
 using ::testing::AtLeast;
diff --git a/media/gpu/windows/d3d11_video_decoder.h b/media/gpu/windows/d3d11_video_decoder.h
index 46fa8d3..d1037e2 100644
--- a/media/gpu/windows/d3d11_video_decoder.h
+++ b/media/gpu/windows/d3d11_video_decoder.h
@@ -17,9 +17,9 @@
 #include "gpu/config/gpu_preferences.h"
 #include "media/base/callback_registry.h"
 #include "media/base/video_decoder.h"
+#include "media/base/win/d3d11_create_device_cb.h"
 #include "media/gpu/command_buffer_helper.h"
 #include "media/gpu/media_gpu_export.h"
-#include "media/gpu/windows/d3d11_create_device_cb.h"
 #include "media/gpu/windows/d3d11_h264_accelerator.h"
 #include "media/gpu/windows/d3d11_video_decoder_client.h"
 #include "media/gpu/windows/d3d11_vp9_accelerator.h"
diff --git a/media/gpu/windows/d3d11_video_decoder_unittest.cc b/media/gpu/windows/d3d11_video_decoder_unittest.cc
index 5e7a561..b351704 100644
--- a/media/gpu/windows/d3d11_video_decoder_unittest.cc
+++ b/media/gpu/windows/d3d11_video_decoder_unittest.cc
@@ -21,7 +21,7 @@
 #include "media/base/media_switches.h"
 #include "media/base/media_util.h"
 #include "media/base/test_helpers.h"
-#include "media/gpu/windows/d3d11_mocks.h"
+#include "media/base/win/d3d11_mocks.h"
 #include "media/gpu/windows/d3d11_video_decoder_impl.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/media/renderers/decrypting_renderer.cc b/media/renderers/decrypting_renderer.cc
index 3d26465d7..db7da79 100644
--- a/media/renderers/decrypting_renderer.cc
+++ b/media/renderers/decrypting_renderer.cc
@@ -52,6 +52,13 @@
   client_ = client;
   init_cb_ = std::move(init_cb);
 
+  // Using a DecryptingMediaResource when our MediaResource has a URL type will
+  // result in a crash.
+  if (media_resource_->GetType() == MediaResource::URL) {
+    InitializeRenderer(true);
+    return;
+  }
+
   bool has_encrypted_stream = HasEncryptedStream();
 
   // If we do not have a valid |cdm_context_| and there are encrypted streams we
@@ -158,6 +165,8 @@
     return;
   }
 
+  // |decrypting_media_resource_| is null when |media_resource_| has a URL type
+  // or when |cdm_context_| is null and there are no encrypted streams.
   MediaResource* const maybe_decrypting_media_resource =
       decrypting_media_resource_ ? decrypting_media_resource_.get()
                                  : media_resource_;
diff --git a/media/renderers/decrypting_renderer_unittest.cc b/media/renderers/decrypting_renderer_unittest.cc
index e87f7b00..a452173 100644
--- a/media/renderers/decrypting_renderer_unittest.cc
+++ b/media/renderers/decrypting_renderer_unittest.cc
@@ -45,8 +45,10 @@
         .WillRepeatedly(ReturnPointee(&use_aes_decryptor_));
     EXPECT_CALL(decryptor_, CancelDecrypt(_)).Times(AnyNumber());
     EXPECT_CALL(decryptor_, RegisterNewKeyCB(_, _)).Times(AnyNumber());
-    EXPECT_CALL(demuxer_, GetAllStreams())
+    EXPECT_CALL(media_resource_, GetAllStreams())
         .WillRepeatedly(Invoke(this, &DecryptingRendererTest::GetAllStreams));
+    EXPECT_CALL(media_resource_, GetType())
+        .WillRepeatedly(Return(MediaResource::STREAM));
   }
 
   ~DecryptingRendererTest() override {
@@ -88,7 +90,7 @@
   NullMediaLog null_media_log_;
   StrictMock<MockCdmContext> cdm_context_;
   StrictMock<MockDecryptor> decryptor_;
-  StrictMock<MockDemuxer> demuxer_;
+  StrictMock<MockMediaResource> media_resource_;
   StrictMock<MockRendererClient> renderer_client_;
   StrictMock<MockRenderer>* renderer_;
   std::unique_ptr<DecryptingRenderer> decrypting_renderer_;
@@ -103,7 +105,7 @@
       .WillOnce(RunCallback<2>(PIPELINE_OK));
   EXPECT_CALL(renderer_init_cb_, Run(PIPELINE_OK));
 
-  decrypting_renderer_->Initialize(&demuxer_, &renderer_client_,
+  decrypting_renderer_->Initialize(&media_resource_, &renderer_client_,
                                    renderer_init_cb_.Get());
   scoped_task_environment_.RunUntilIdle();
 
@@ -121,7 +123,7 @@
   EXPECT_CALL(renderer_init_cb_, Run(PIPELINE_OK));
 
   decrypting_renderer_->SetCdm(&cdm_context_, set_cdm_cb_.Get());
-  decrypting_renderer_->Initialize(&demuxer_, &renderer_client_,
+  decrypting_renderer_->Initialize(&media_resource_, &renderer_client_,
                                    renderer_init_cb_.Get());
   scoped_task_environment_.RunUntilIdle();
 
@@ -138,7 +140,7 @@
   EXPECT_CALL(renderer_init_cb_, Run(PIPELINE_OK));
   EXPECT_CALL(set_cdm_cb_, Run(true));
 
-  decrypting_renderer_->Initialize(&demuxer_, &renderer_client_,
+  decrypting_renderer_->Initialize(&media_resource_, &renderer_client_,
                                    renderer_init_cb_.Get());
   decrypting_renderer_->SetCdm(&cdm_context_, set_cdm_cb_.Get());
   scoped_task_environment_.RunUntilIdle();
@@ -150,7 +152,7 @@
   AddStream(DemuxerStream::AUDIO, /* encrypted = */ true);
   AddStream(DemuxerStream::VIDEO, /* encrypted = */ true);
 
-  decrypting_renderer_->Initialize(&demuxer_, &renderer_client_,
+  decrypting_renderer_->Initialize(&media_resource_, &renderer_client_,
                                    renderer_init_cb_.Get());
   scoped_task_environment_.RunUntilIdle();
 
@@ -167,7 +169,7 @@
   EXPECT_CALL(renderer_init_cb_, Run(PIPELINE_OK));
   EXPECT_CALL(set_cdm_cb_, Run(true));
 
-  decrypting_renderer_->Initialize(&demuxer_, &renderer_client_,
+  decrypting_renderer_->Initialize(&media_resource_, &renderer_client_,
                                    renderer_init_cb_.Get());
   decrypting_renderer_->SetCdm(&cdm_context_, set_cdm_cb_.Get());
   scoped_task_environment_.RunUntilIdle();
@@ -185,7 +187,7 @@
   EXPECT_CALL(renderer_init_cb_, Run(PIPELINE_OK));
   EXPECT_CALL(set_cdm_cb_, Run(true));
 
-  decrypting_renderer_->Initialize(&demuxer_, &renderer_client_,
+  decrypting_renderer_->Initialize(&media_resource_, &renderer_client_,
                                    renderer_init_cb_.Get());
   decrypting_renderer_->SetCdm(&cdm_context_, set_cdm_cb_.Get());
   scoped_task_environment_.RunUntilIdle();
@@ -204,7 +206,7 @@
   EXPECT_CALL(set_cdm_cb_, Run(true));
 
   decrypting_renderer_->SetCdm(&cdm_context_, set_cdm_cb_.Get());
-  decrypting_renderer_->Initialize(&demuxer_, &renderer_client_,
+  decrypting_renderer_->Initialize(&media_resource_, &renderer_client_,
                                    renderer_init_cb_.Get());
   scoped_task_environment_.RunUntilIdle();
 
@@ -222,7 +224,7 @@
   EXPECT_CALL(set_cdm_cb_, Run(true));
 
   decrypting_renderer_->SetCdm(&cdm_context_, set_cdm_cb_.Get());
-  decrypting_renderer_->Initialize(&demuxer_, &renderer_client_,
+  decrypting_renderer_->Initialize(&media_resource_, &renderer_client_,
                                    renderer_init_cb_.Get());
   scoped_task_environment_.RunUntilIdle();
 
@@ -239,7 +241,7 @@
   EXPECT_CALL(renderer_init_cb_, Run(PIPELINE_OK));
   EXPECT_CALL(set_cdm_cb_, Run(true));
 
-  decrypting_renderer_->Initialize(&demuxer_, &renderer_client_,
+  decrypting_renderer_->Initialize(&media_resource_, &renderer_client_,
                                    renderer_init_cb_.Get());
   decrypting_renderer_->SetCdm(&cdm_context_, set_cdm_cb_.Get());
   scoped_task_environment_.RunUntilIdle();
@@ -254,7 +256,7 @@
 
   EXPECT_CALL(renderer_init_cb_, Run(PIPELINE_ERROR_INITIALIZATION_FAILED));
 
-  decrypting_renderer_->Initialize(&demuxer_, &renderer_client_,
+  decrypting_renderer_->Initialize(&media_resource_, &renderer_client_,
                                    renderer_init_cb_.Get());
   scoped_task_environment_.RunUntilIdle();
 
@@ -263,4 +265,16 @@
   InitializeDecryptingRendererWithFalse();
 }
 
+TEST_F(DecryptingRendererTest, MediaResourceHasURLType) {
+  EXPECT_CALL(*renderer_, Initialize(_, _, _))
+      .WillOnce(RunCallback<2>(PIPELINE_OK));
+  EXPECT_CALL(renderer_init_cb_, Run(PIPELINE_OK));
+  EXPECT_CALL(media_resource_, GetType())
+      .WillRepeatedly(Return(MediaResource::URL));
+
+  decrypting_renderer_->Initialize(&media_resource_, &renderer_client_,
+                                   renderer_init_cb_.Get());
+  scoped_task_environment_.RunUntilIdle();
+}
+
 }  // namespace media
diff --git a/media/test/BUILD.gn b/media/test/BUILD.gn
index 83a7526..5bd9de49 100644
--- a/media/test/BUILD.gn
+++ b/media/test/BUILD.gn
@@ -210,6 +210,7 @@
     deps = [
       ":pipeline_integration_test_base",
       "//base",
+      "//base/test:test_support",
       "//media",
 
       # TODO(dalecurtis): Required since the gmock header is included in the
diff --git a/media/test/pipeline_integration_fuzzertest.cc b/media/test/pipeline_integration_fuzzertest.cc
index 1fc5f6e..d4e3b4d 100644
--- a/media/test/pipeline_integration_fuzzertest.cc
+++ b/media/test/pipeline_integration_fuzzertest.cc
@@ -12,6 +12,7 @@
 #include "base/command_line.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/test/test_timeouts.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/eme_constants.h"
@@ -240,6 +241,9 @@
   // Media pipeline checks command line arguments internally.
   base::CommandLine::Init(0, nullptr);
 
+  // |test| instances uses ScopedTaskEnvironment, which needs TestTimeouts.
+  TestTimeouts::Initialize();
+
   media::InitializeMediaLibrary();
 
   FuzzerVariant variant = PIPELINE_FUZZER_VARIANT;
diff --git a/net/nqe/network_quality_estimator.cc b/net/nqe/network_quality_estimator.cc
index 3a5aa69f..d21f6fd 100644
--- a/net/nqe/network_quality_estimator.cc
+++ b/net/nqe/network_quality_estimator.cc
@@ -81,96 +81,6 @@
   return request.url().is_valid() && request.url().SchemeIsHTTPOrHTTPS();
 }
 
-// Returns the suffix of the histogram that should be used for recording the
-// accuracy when the observed RTT is |observed_rtt|. The width of the intervals
-// are in exponentially increasing order.
-const char* GetHistogramSuffixObservedRTT(const base::TimeDelta& observed_rtt) {
-  const int32_t rtt_milliseconds = observed_rtt.InMilliseconds();
-  DCHECK_GE(rtt_milliseconds, 0);
-
-  // The values here should remain synchronized with the suffixes specified in
-  // histograms.xml.
-  static const char* const kSuffixes[] = {
-      "0_20",     "20_60",     "60_140",    "140_300",      "300_620",
-      "620_1260", "1260_2540", "2540_5100", "5100_Infinity"};
-  for (size_t i = 0; i < base::size(kSuffixes) - 1; ++i) {
-    if (rtt_milliseconds <= (20 * (2 << i) - 20))
-      return kSuffixes[i];
-  }
-  return kSuffixes[base::size(kSuffixes) - 1];
-}
-
-// Returns the suffix of the histogram that should be used for recording the
-// accuracy when the observed throughput in kilobits per second is
-// |observed_throughput_kbps|. The width of the intervals are in exponentially
-// increasing order.
-const char* GetHistogramSuffixObservedThroughput(
-    const int32_t& observed_throughput_kbps) {
-  DCHECK_GE(observed_throughput_kbps, 0);
-
-  // The values here should remain synchronized with the suffixes specified in
-  // histograms.xml.
-  static const char* const kSuffixes[] = {
-      "0_20",     "20_60",     "60_140",    "140_300",      "300_620",
-      "620_1260", "1260_2540", "2540_5100", "5100_Infinity"};
-  for (size_t i = 0; i < base::size(kSuffixes) - 1; ++i) {
-    if (observed_throughput_kbps <= (20 * (2 << i) - 20))
-      return kSuffixes[i];
-  }
-  return kSuffixes[base::size(kSuffixes) - 1];
-}
-
-void RecordRTTAccuracy(base::StringPiece prefix,
-                       int32_t metric,
-                       base::TimeDelta measuring_duration,
-                       base::TimeDelta observed_rtt) {
-  const std::string histogram_name =
-      base::StringPrintf("%s.EstimatedObservedDiff.%s.%d.%s", prefix.data(),
-                         metric >= 0 ? "Positive" : "Negative",
-                         static_cast<int32_t>(measuring_duration.InSeconds()),
-                         GetHistogramSuffixObservedRTT(observed_rtt));
-
-  base::HistogramBase* histogram = base::Histogram::FactoryGet(
-      histogram_name, 1, 10 * 1000 /* 10 seconds */, 50 /* Number of buckets */,
-      base::HistogramBase::kUmaTargetedHistogramFlag);
-  histogram->Add(std::abs(metric));
-}
-
-void RecordThroughputAccuracy(const char* prefix,
-                              int32_t metric,
-                              base::TimeDelta measuring_duration,
-                              int32_t observed_throughput_kbps) {
-  const std::string histogram_name = base::StringPrintf(
-      "%s.EstimatedObservedDiff.%s.%d.%s", prefix,
-      metric >= 0 ? "Positive" : "Negative",
-      static_cast<int32_t>(measuring_duration.InSeconds()),
-      GetHistogramSuffixObservedThroughput(observed_throughput_kbps));
-
-  base::HistogramBase* histogram = base::Histogram::FactoryGet(
-      histogram_name, 1, 1000 * 1000 /* 1 Gbps */, 50 /* Number of buckets */,
-      base::HistogramBase::kUmaTargetedHistogramFlag);
-  histogram->Add(std::abs(metric));
-}
-
-void RecordEffectiveConnectionTypeAccuracy(
-    const char* prefix,
-    int32_t metric,
-    base::TimeDelta measuring_duration,
-    EffectiveConnectionType observed_effective_connection_type) {
-  const std::string histogram_name =
-      base::StringPrintf("%s.EstimatedObservedDiff.%s.%d.%s", prefix,
-                         metric >= 0 ? "Positive" : "Negative",
-                         static_cast<int32_t>(measuring_duration.InSeconds()),
-                         DeprecatedGetNameForEffectiveConnectionType(
-                             observed_effective_connection_type));
-
-  base::HistogramBase* histogram = base::Histogram::FactoryGet(
-      histogram_name, 0, EFFECTIVE_CONNECTION_TYPE_LAST,
-      EFFECTIVE_CONNECTION_TYPE_LAST /* Number of buckets */,
-      base::HistogramBase::kUmaTargetedHistogramFlag);
-  histogram->Add(std::abs(metric));
-}
-
 nqe::internal::NetworkID DoGetCurrentNetworkID() {
   // It is possible that the connection type changed between when
   // GetConnectionType() was called and when the API to determine the
@@ -297,11 +207,6 @@
                  base::Unretained(this)),
       tick_clock_));
 
-  // Record accuracy after a 15 second interval. The values used here must
-  // remain in sync with the suffixes specified in
-  // tools/metrics/histograms/histograms.xml.
-  accuracy_recording_intervals_.push_back(base::TimeDelta::FromSeconds(15));
-
   GatherEstimatesForNextConnectionType();
 }
 
@@ -350,11 +255,6 @@
   NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
 }
 
-const std::vector<base::TimeDelta>&
-NetworkQualityEstimator::GetAccuracyRecordingIntervals() const {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  return accuracy_recording_intervals_;
-}
 
 void NetworkQualityEstimator::NotifyStartTransaction(
     const URLRequest& request) {
@@ -373,20 +273,6 @@
     ComputeEffectiveConnectionType();
     effective_connection_type_at_last_main_frame_ = effective_connection_type_;
     estimated_quality_at_last_main_frame_ = network_quality_;
-
-    // Post the tasks which will run in the future and record the estimation
-    // accuracy based on the observations received between now and the time of
-    // task execution. Posting the task at different intervals makes it
-    // possible to measure the accuracy by comparing the estimate with the
-    // observations received over intervals of varying durations.
-    for (const base::TimeDelta& measuring_delay :
-         GetAccuracyRecordingIntervals()) {
-      base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-          FROM_HERE,
-          base::Bind(&NetworkQualityEstimator::RecordAccuracyAfterMainFrame,
-                     weak_ptr_factory_.GetWeakPtr(), measuring_delay),
-          measuring_delay);
-    }
   } else {
     MaybeComputeEffectiveConnectionType();
   }
@@ -502,93 +388,6 @@
   throughput_analyzer_->NotifyBytesRead(request);
 }
 
-void NetworkQualityEstimator::RecordAccuracyAfterMainFrame(
-    base::TimeDelta measuring_duration) const {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK_EQ(0, measuring_duration.InMilliseconds() % 1000);
-  DCHECK(ContainsValue(GetAccuracyRecordingIntervals(), measuring_duration));
-
-  const base::TimeTicks now = tick_clock_->NowTicks();
-
-  // Return if the time since |last_main_frame_request_| is less than
-  // |measuring_duration|. This may happen if another main frame request started
-  // during last |measuring_duration|. Returning here ensures that we do not
-  // take inaccurate readings.
-  if (now - last_main_frame_request_ < measuring_duration)
-    return;
-
-  // Return if the time since |last_main_frame_request_| is off by a factor of
-  // 2. This can happen if the task is executed much later than its scheduled
-  // time. Returning here ensures that we do not take inaccurate readings.
-  if (now - last_main_frame_request_ > 2 * measuring_duration)
-    return;
-
-  // Do not record accuracy if there was a connection change since the last main
-  // frame request.
-  if (last_main_frame_request_ <= last_connection_change_)
-    return;
-
-  base::TimeDelta recent_http_rtt;
-  if (!GetRecentRTT(nqe::internal::OBSERVATION_CATEGORY_HTTP,
-                    last_main_frame_request_, &recent_http_rtt, nullptr)) {
-    recent_http_rtt = nqe::internal::InvalidRTT();
-  }
-
-  if (estimated_quality_at_last_main_frame_.http_rtt() !=
-          nqe::internal::InvalidRTT() &&
-      recent_http_rtt != nqe::internal::InvalidRTT()) {
-    const int estimated_observed_diff_milliseconds =
-        estimated_quality_at_last_main_frame_.http_rtt().InMilliseconds() -
-        recent_http_rtt.InMilliseconds();
-
-    RecordRTTAccuracy("NQE.Accuracy.HttpRTT",
-                      estimated_observed_diff_milliseconds, measuring_duration,
-                      recent_http_rtt);
-  }
-
-  base::TimeDelta recent_transport_rtt;
-  if (estimated_quality_at_last_main_frame_.transport_rtt() !=
-          nqe::internal::InvalidRTT() &&
-      GetRecentRTT(nqe::internal::OBSERVATION_CATEGORY_TRANSPORT,
-                   last_main_frame_request_, &recent_transport_rtt, nullptr)) {
-    const int estimated_observed_diff_milliseconds =
-        estimated_quality_at_last_main_frame_.transport_rtt().InMilliseconds() -
-        recent_transport_rtt.InMilliseconds();
-
-    RecordRTTAccuracy("NQE.Accuracy.TransportRTT",
-                      estimated_observed_diff_milliseconds, measuring_duration,
-                      recent_transport_rtt);
-  }
-
-  int32_t recent_downstream_throughput_kbps;
-  if (estimated_quality_at_last_main_frame_.downstream_throughput_kbps() !=
-          nqe::internal::INVALID_RTT_THROUGHPUT &&
-      GetRecentDownlinkThroughputKbps(last_main_frame_request_,
-                                      &recent_downstream_throughput_kbps)) {
-    const int estimated_observed_diff =
-        estimated_quality_at_last_main_frame_.downstream_throughput_kbps() -
-        recent_downstream_throughput_kbps;
-
-    RecordThroughputAccuracy("NQE.Accuracy.DownstreamThroughputKbps",
-                             estimated_observed_diff, measuring_duration,
-                             recent_downstream_throughput_kbps);
-  }
-
-  EffectiveConnectionType recent_effective_connection_type =
-      GetRecentEffectiveConnectionType(last_main_frame_request_);
-  if (effective_connection_type_at_last_main_frame_ !=
-          EFFECTIVE_CONNECTION_TYPE_UNKNOWN &&
-      recent_effective_connection_type != EFFECTIVE_CONNECTION_TYPE_UNKNOWN) {
-    const int estimated_observed_diff =
-        static_cast<int>(effective_connection_type_at_last_main_frame_) -
-        static_cast<int>(recent_effective_connection_type);
-
-    RecordEffectiveConnectionTypeAccuracy(
-        "NQE.Accuracy.EffectiveConnectionType", estimated_observed_diff,
-        measuring_duration, recent_effective_connection_type);
-  }
-}
-
 void NetworkQualityEstimator::NotifyRequestCompleted(const URLRequest& request,
                                                      int net_error) {
   TRACE_EVENT0(NetTracingCategory(),
diff --git a/net/nqe/network_quality_estimator.h b/net/nqe/network_quality_estimator.h
index d3baccc7..bf40a20 100644
--- a/net/nqe/network_quality_estimator.h
+++ b/net/nqe/network_quality_estimator.h
@@ -292,11 +292,6 @@
       const base::TimeTicks& start_time,
       int32_t* kbps) const WARN_UNUSED_RESULT;
 
-  // Returns the list of intervals at which the accuracy of network quality
-  // prediction should be recorded. Virtualized for testing.
-  virtual const std::vector<base::TimeDelta>& GetAccuracyRecordingIntervals()
-      const;
-
   // Overrides the tick clock used by |this| for testing.
   void SetTickClockForTesting(const base::TickClock* tick_clock);
 
@@ -533,10 +528,6 @@
   // Tick clock used by the network quality estimator.
   const base::TickClock* tick_clock_;
 
-  // Intervals after the main frame request arrives at which accuracy of network
-  // quality prediction is recorded.
-  std::vector<base::TimeDelta> accuracy_recording_intervals_;
-
   // Time when last connection change was observed.
   base::TimeTicks last_connection_change_;
 
diff --git a/net/nqe/network_quality_estimator_test_util.cc b/net/nqe/network_quality_estimator_test_util.cc
index d4e0849..2ceaab0 100644
--- a/net/nqe/network_quality_estimator_test_util.cc
+++ b/net/nqe/network_quality_estimator_test_util.cc
@@ -56,7 +56,6 @@
           net_log->bound().net_log()),
       net_log_(std::move(net_log)),
       current_network_type_(NetworkChangeNotifier::CONNECTION_UNKNOWN),
-      accuracy_recording_intervals_set_(false),
       embedded_test_server_(base::FilePath(kTestFilePath)),
       suppress_notifications_for_testing_(suppress_notifications_for_testing) {
   SetUseLocalHostRequestsForTesting(allow_local_host_requests_for_tests);
@@ -74,7 +73,6 @@
     : NetworkQualityEstimator(std::move(params), net_log->bound().net_log()),
       net_log_(std::move(net_log)),
       current_network_type_(NetworkChangeNotifier::CONNECTION_UNKNOWN),
-      accuracy_recording_intervals_set_(false),
       embedded_test_server_(base::FilePath(kTestFilePath)),
       suppress_notifications_for_testing_(false) {
 }
@@ -256,20 +254,6 @@
       start_time, observation_category, percentile, observations_count);
 }
 
-void TestNetworkQualityEstimator::SetAccuracyRecordingIntervals(
-    const std::vector<base::TimeDelta>& accuracy_recording_intervals) {
-  accuracy_recording_intervals_set_ = true;
-  accuracy_recording_intervals_ = accuracy_recording_intervals;
-}
-
-const std::vector<base::TimeDelta>&
-TestNetworkQualityEstimator::GetAccuracyRecordingIntervals() const {
-  if (accuracy_recording_intervals_set_)
-    return accuracy_recording_intervals_;
-
-  return NetworkQualityEstimator::GetAccuracyRecordingIntervals();
-}
-
 int TestNetworkQualityEstimator::GetEntriesCount(NetLogEventType type) const {
   TestNetLogEntry::List entries;
   net_log_->GetEntries(&entries);
diff --git a/net/nqe/network_quality_estimator_test_util.h b/net/nqe/network_quality_estimator_test_util.h
index cb8bc2c..bf614c3 100644
--- a/net/nqe/network_quality_estimator_test_util.h
+++ b/net/nqe/network_quality_estimator_test_util.h
@@ -187,12 +187,6 @@
     end_to_end_rtt_observation_count_at_last_ect_computation_ = count;
   }
 
-  void SetAccuracyRecordingIntervals(
-      const std::vector<base::TimeDelta>& accuracy_recording_intervals);
-
-  const std::vector<base::TimeDelta>& GetAccuracyRecordingIntervals()
-      const override;
-
   // Returns the number of entries in |net_log_| that have type set to |type|.
   int GetEntriesCount(NetLogEventType type) const;
 
@@ -260,9 +254,6 @@
   NetworkChangeNotifier::ConnectionType current_network_type_;
   std::string current_network_id_;
 
-  bool accuracy_recording_intervals_set_;
-  std::vector<base::TimeDelta> accuracy_recording_intervals_;
-
   // If set, GetRecentHttpRTT() would return one of the set values.
   // |start_time_null_http_rtt_| is returned if the |start_time| is null.
   // Otherwise, |recent_http_rtt_| is returned.
diff --git a/net/nqe/network_quality_estimator_unittest.cc b/net/nqe/network_quality_estimator_unittest.cc
index 09e1f1d..9263799 100644
--- a/net/nqe/network_quality_estimator_unittest.cc
+++ b/net/nqe/network_quality_estimator_unittest.cc
@@ -2056,182 +2056,6 @@
       NETWORK_QUALITY_OBSERVATION_SOURCE_TRANSPORT_CACHED_ESTIMATE, 2);
 }
 
-#if defined(OS_IOS)
-// Flaky on iOS when |accuracy_recording_delay| is non-zero.
-#define MAYBE_RecordAccuracy DISABLED_RecordAccuracy
-#else
-#define MAYBE_RecordAccuracy RecordAccuracy
-#endif
-// Tests if the NQE accuracy metrics are recorded properly.
-TEST_F(NetworkQualityEstimatorTest, MAYBE_RecordAccuracy) {
-  const int expected_rtt_msec = 500;
-  const int expected_downstream_throughput_kbps = 2000;
-
-  const base::TimeDelta accuracy_recording_delays[] = {
-      base::TimeDelta::FromSeconds(0), base::TimeDelta::FromSeconds(1),
-  };
-
-  const struct {
-    base::TimeDelta rtt;
-    base::TimeDelta recent_rtt;
-    int32_t downstream_throughput_kbps;
-    int32_t recent_downstream_throughput_kbps;
-    EffectiveConnectionType effective_connection_type;
-    EffectiveConnectionType recent_effective_connection_type;
-  } tests[] = {
-      {base::TimeDelta::FromMilliseconds(expected_rtt_msec),
-       base::TimeDelta::FromMilliseconds(expected_rtt_msec),
-       expected_downstream_throughput_kbps, expected_downstream_throughput_kbps,
-       EFFECTIVE_CONNECTION_TYPE_3G, EFFECTIVE_CONNECTION_TYPE_3G},
-      {
-          base::TimeDelta::FromMilliseconds(expected_rtt_msec + 1000),
-          base::TimeDelta::FromMilliseconds(expected_rtt_msec),
-          expected_downstream_throughput_kbps - 1,
-          expected_downstream_throughput_kbps, EFFECTIVE_CONNECTION_TYPE_2G,
-          EFFECTIVE_CONNECTION_TYPE_3G,
-      },
-      {
-          base::TimeDelta::FromMilliseconds(expected_rtt_msec - 400),
-          base::TimeDelta::FromMilliseconds(expected_rtt_msec),
-          expected_downstream_throughput_kbps + 1,
-          expected_downstream_throughput_kbps, EFFECTIVE_CONNECTION_TYPE_4G,
-          EFFECTIVE_CONNECTION_TYPE_3G,
-      },
-  };
-
-  for (const auto& accuracy_recording_delay : accuracy_recording_delays) {
-    for (const auto& test : tests) {
-      base::SimpleTestTickClock tick_clock;
-      tick_clock.Advance(base::TimeDelta::FromSeconds(1));
-
-      std::map<std::string, std::string> variation_params;
-      TestNetworkQualityEstimator estimator(variation_params);
-
-      estimator.SetTickClockForTesting(&tick_clock);
-      estimator.SimulateNetworkChange(
-          NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test-1");
-      tick_clock.Advance(base::TimeDelta::FromSeconds(1));
-
-      std::vector<base::TimeDelta> accuracy_recording_intervals;
-      accuracy_recording_intervals.push_back(accuracy_recording_delay);
-      estimator.SetAccuracyRecordingIntervals(accuracy_recording_intervals);
-
-      // RTT is higher than threshold. Network is slow.
-      // Network was predicted to be slow and actually was slow.
-      estimator.SetStartTimeNullHttpRtt(test.rtt);
-      estimator.set_recent_http_rtt(test.recent_rtt);
-      estimator.set_rtt_estimate_internal(test.recent_rtt);
-      estimator.SetStartTimeNullTransportRtt(test.rtt);
-      estimator.set_recent_transport_rtt(test.recent_rtt);
-      estimator.set_start_time_null_downlink_throughput_kbps(
-          test.downstream_throughput_kbps);
-      estimator.set_recent_downlink_throughput_kbps(
-          test.recent_downstream_throughput_kbps);
-
-      base::HistogramTester histogram_tester;
-
-      TestDelegate test_delegate;
-      TestURLRequestContext context(true);
-      context.set_network_quality_estimator(&estimator);
-      context.Init();
-
-      // Start a main-frame request which should cause network quality estimator
-      // to record accuracy UMA.
-      std::unique_ptr<URLRequest> request(
-          context.CreateRequest(estimator.GetEchoURL(), DEFAULT_PRIORITY,
-                                &test_delegate, TRAFFIC_ANNOTATION_FOR_TESTS));
-      request->SetLoadFlags(request->load_flags() | LOAD_MAIN_FRAME_DEPRECATED);
-      request->Start();
-      test_delegate.RunUntilComplete();
-
-      if (accuracy_recording_delay != base::TimeDelta()) {
-        tick_clock.Advance(accuracy_recording_delay);
-
-        // Sleep for some time to ensure that the delayed task is posted.
-        base::PlatformThread::Sleep(accuracy_recording_delay * 2);
-        base::RunLoop().RunUntilIdle();
-      }
-
-      const int rtt_diff = std::abs(test.rtt.InMilliseconds() -
-                                    test.recent_rtt.InMilliseconds());
-      const int kbps_diff = std::abs(test.downstream_throughput_kbps -
-                                     test.recent_downstream_throughput_kbps);
-      const int ect_diff = std::abs(test.effective_connection_type -
-                                    test.recent_effective_connection_type);
-
-      const std::string rtt_sign_suffix_with_zero_samples =
-          test.rtt.InMilliseconds() - test.recent_rtt.InMilliseconds() >= 0
-              ? "Negative"
-              : "Positive";
-      const std::string kbps_sign_suffix_with_zero_samples =
-          test.downstream_throughput_kbps -
-                      test.recent_downstream_throughput_kbps >=
-                  0
-              ? "Negative"
-              : "Positive";
-
-      const std::string rtt_sign_suffix_with_one_sample =
-          rtt_sign_suffix_with_zero_samples == "Positive" ? "Negative"
-                                                          : "Positive";
-      const std::string ect_sign_suffix_with_zero_samples =
-          test.rtt.InMilliseconds() - test.recent_rtt.InMilliseconds() > 0
-              ? "Positive"
-              : "Negative";
-
-      const std::string kbps_sign_suffix_with_one_sample =
-          kbps_sign_suffix_with_zero_samples == "Positive" ? "Negative"
-                                                           : "Positive";
-      const std::string ect_sign_suffix_with_one_sample =
-          ect_sign_suffix_with_zero_samples == "Positive" ? "Negative"
-                                                          : "Positive";
-      const std::string interval_value =
-          base::IntToString(accuracy_recording_delay.InSeconds());
-
-      histogram_tester.ExpectUniqueSample(
-          "NQE.Accuracy.DownstreamThroughputKbps.EstimatedObservedDiff." +
-              kbps_sign_suffix_with_one_sample + "." + interval_value +
-              ".1260_2540",
-          kbps_diff, 1);
-      histogram_tester.ExpectTotalCount(
-          "NQE.Accuracy.DownstreamThroughputKbps.EstimatedObservedDiff." +
-              kbps_sign_suffix_with_zero_samples + "." + interval_value +
-              ".1260_2540",
-          0);
-
-      histogram_tester.ExpectUniqueSample(
-          "NQE.Accuracy.EffectiveConnectionType.EstimatedObservedDiff." +
-              ect_sign_suffix_with_one_sample + "." + interval_value + ".3G",
-          ect_diff, 1);
-      histogram_tester.ExpectTotalCount(
-          "NQE.Accuracy.EffectiveConnectionType.EstimatedObservedDiff." +
-              ect_sign_suffix_with_zero_samples + "." + interval_value + ".3G",
-          0);
-
-      histogram_tester.ExpectUniqueSample(
-          "NQE.Accuracy.HttpRTT.EstimatedObservedDiff." +
-              rtt_sign_suffix_with_one_sample + "." + interval_value +
-              ".300_620",
-          rtt_diff, 1);
-      histogram_tester.ExpectTotalCount(
-          "NQE.Accuracy.HttpRTT.EstimatedObservedDiff." +
-              rtt_sign_suffix_with_zero_samples + "." + interval_value +
-              ".300_620",
-          0);
-
-      histogram_tester.ExpectUniqueSample(
-          "NQE.Accuracy.TransportRTT.EstimatedObservedDiff." +
-              rtt_sign_suffix_with_one_sample + "." + interval_value +
-              ".300_620",
-          rtt_diff, 1);
-      histogram_tester.ExpectTotalCount(
-          "NQE.Accuracy.TransportRTT.EstimatedObservedDiff." +
-              rtt_sign_suffix_with_zero_samples + "." + interval_value +
-              ".300_620",
-          0);
-    }
-  }
-}
-
 TEST_F(NetworkQualityEstimatorTest, TestRecordNetworkIDAvailability) {
   base::HistogramTester histogram_tester;
   TestNetworkQualityEstimator estimator;
diff --git a/sandbox/linux/seccomp-bpf-helpers/baseline_policy_android.cc b/sandbox/linux/seccomp-bpf-helpers/baseline_policy_android.cc
index fc0647f..a4124ba 100644
--- a/sandbox/linux/seccomp-bpf-helpers/baseline_policy_android.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/baseline_policy_android.cc
@@ -212,7 +212,8 @@
                     AnyOf(option == SO_SNDTIMEO,
                           option == SO_RCVTIMEO,
                           option == SO_SNDBUF,
-                          option == SO_REUSEADDR)),
+                          option == SO_REUSEADDR,
+                          option == SO_PASSCRED)),
               Allow())
            .Else(BaselinePolicy::EvaluateSyscall(sysno));
   }
diff --git a/services/identity/BUILD.gn b/services/identity/BUILD.gn
index 22a9e114b..c6aee55 100644
--- a/services/identity/BUILD.gn
+++ b/services/identity/BUILD.gn
@@ -44,6 +44,7 @@
     "//components/signin/core/browser:internals",
     "//components/signin/core/browser:internals_test_support",
     "//components/signin/core/browser:shared",
+    "//components/signin/core/browser:test_support",
     "//components/sync_preferences:test_support",
     "//mojo/public/cpp/bindings",
     "//services/identity/public/cpp",
diff --git a/services/identity/public/cpp/DEPS b/services/identity/public/cpp/DEPS
index 5634299..849f6fb 100644
--- a/services/identity/public/cpp/DEPS
+++ b/services/identity/public/cpp/DEPS
@@ -1,6 +1,8 @@
 include_rules = [
   "+components/prefs/testing_pref_service.h",
+  "+components/signin/core/browser/account_fetcher_service.h",
   "+components/signin/core/browser/account_info.h",
+  "+components/signin/core/browser/fake_account_fetcher_service.h",
   "+components/signin/core/browser/fake_gaia_cookie_manager_service.h",
   "+components/signin/core/browser/gaia_cookie_manager_service.h",
   "+components/signin/core/browser/account_consistency_method.h",
diff --git a/services/identity/public/cpp/accounts_mutator.h b/services/identity/public/cpp/accounts_mutator.h
index 4c19abe..cc67ed3 100644
--- a/services/identity/public/cpp/accounts_mutator.h
+++ b/services/identity/public/cpp/accounts_mutator.h
@@ -5,7 +5,10 @@
 #ifndef SERVICES_IDENTITY_PUBLIC_CPP_ACCOUNTS_MUTATOR_H_
 #define SERVICES_IDENTITY_PUBLIC_CPP_ACCOUNTS_MUTATOR_H_
 
+#include <string>
+
 #include "base/macros.h"
+#include "components/signin/core/browser/signin_metrics.h"
 
 namespace identity {
 
@@ -16,6 +19,18 @@
   AccountsMutator() = default;
   virtual ~AccountsMutator() = default;
 
+  // Removes the account given by |account_id|. Also revokes the token
+  // server-side if needed.
+  virtual void RemoveAccount(
+      const std::string& account_id,
+      signin_metrics::SourceForRefreshTokenOperation source =
+          signin_metrics::SourceForRefreshTokenOperation::kUnknown) = 0;
+
+  // Removes all accounts.
+  virtual void RemoveAllAccounts(
+      signin_metrics::SourceForRefreshTokenOperation source =
+          signin_metrics::SourceForRefreshTokenOperation::kUnknown) = 0;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(AccountsMutator);
 };
diff --git a/services/identity/public/cpp/accounts_mutator_impl.cc b/services/identity/public/cpp/accounts_mutator_impl.cc
index 0ccd96e..55d6799 100644
--- a/services/identity/public/cpp/accounts_mutator_impl.cc
+++ b/services/identity/public/cpp/accounts_mutator_impl.cc
@@ -5,14 +5,28 @@
 #include "services/identity/public/cpp/accounts_mutator_impl.h"
 
 #include "base/logging.h"
+#include "components/signin/core/browser/account_info.h"
+#include "components/signin/core/browser/profile_oauth2_token_service.h"
 
 namespace identity {
 
 AccountsMutatorImpl::AccountsMutatorImpl(
-    ProfileOAuth2TokenService* token_service) {
-  DCHECK(token_service);
+    ProfileOAuth2TokenService* token_service)
+    : token_service_(token_service) {
+  DCHECK(token_service_);
 }
 
 AccountsMutatorImpl::~AccountsMutatorImpl() {}
 
+void AccountsMutatorImpl::RemoveAccount(
+    const std::string& account_id,
+    signin_metrics::SourceForRefreshTokenOperation source) {
+  token_service_->RevokeCredentials(account_id, source);
+}
+
+void AccountsMutatorImpl::RemoveAllAccounts(
+    signin_metrics::SourceForRefreshTokenOperation source) {
+  token_service_->RevokeAllCredentials(source);
+}
+
 }  // namespace identity
diff --git a/services/identity/public/cpp/accounts_mutator_impl.h b/services/identity/public/cpp/accounts_mutator_impl.h
index 94e1a39..21f1bc1b 100644
--- a/services/identity/public/cpp/accounts_mutator_impl.h
+++ b/services/identity/public/cpp/accounts_mutator_impl.h
@@ -6,6 +6,7 @@
 #define SERVICES_IDENTITY_PUBLIC_CPP_ACCOUNTS_MUTATOR_IMPL_H_
 
 #include "base/macros.h"
+#include "components/signin/core/browser/signin_metrics.h"
 #include "services/identity/public/cpp/accounts_mutator.h"
 
 class ProfileOAuth2TokenService;
@@ -18,7 +19,21 @@
   explicit AccountsMutatorImpl(ProfileOAuth2TokenService* token_service);
   ~AccountsMutatorImpl() override;
 
+  // Removes the account given by |account_id|. Also revokes the token
+  // server-side if needed.
+  void RemoveAccount(
+      const std::string& account_id,
+      signin_metrics::SourceForRefreshTokenOperation source =
+          signin_metrics::SourceForRefreshTokenOperation::kUnknown) override;
+
+  // Removes all accounts.
+  void RemoveAllAccounts(
+      signin_metrics::SourceForRefreshTokenOperation source =
+          signin_metrics::SourceForRefreshTokenOperation::kUnknown) override;
+
  private:
+  ProfileOAuth2TokenService* token_service_;
+
   DISALLOW_COPY_AND_ASSIGN(AccountsMutatorImpl);
 };
 
diff --git a/services/identity/public/cpp/accounts_mutator_impl_unittest.cc b/services/identity/public/cpp/accounts_mutator_impl_unittest.cc
index 3e923d0..8393844a 100644
--- a/services/identity/public/cpp/accounts_mutator_impl_unittest.cc
+++ b/services/identity/public/cpp/accounts_mutator_impl_unittest.cc
@@ -5,13 +5,24 @@
 #include "services/identity/public/cpp/accounts_mutator_impl.h"
 
 #include "base/message_loop/message_loop.h"
+#include "components/signin/core/browser/account_fetcher_service.h"
+#include "components/signin/core/browser/account_tracker_service.h"
+#include "components/signin/core/browser/fake_account_fetcher_service.h"
 #include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
+#include "components/signin/core/browser/test_signin_client.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "services/identity/public/cpp/accounts_mutator_impl.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
 
+const char kTestGaiaId[] = "gaia-id-test_user@test.com";
+const char kTestGaiaId2[] = "gaia-id-test_user-2@test.com";
+const char kTestEmail[] = "test_user@test.com";
+const char kTestEmail2[] = "test_user@test-2.com";
+const char kRefreshToken[] = "refresh_token";
+const char kRefreshToken2[] = "refresh_token_2";
+
 // Class that observes updates from ProfileOAuth2TokenService.
 class TestTokenServiceObserver : public OAuth2TokenService::Observer {
  public:
@@ -21,18 +32,42 @@
   }
   ~TestTokenServiceObserver() override { token_service_->RemoveObserver(this); }
 
+  void set_on_refresh_tokens_available_callback(
+      base::RepeatingCallback<void(const std::string&)> callback) {
+    on_refresh_tokens_available_callback_ = std::move(callback);
+  }
+
+  void set_on_refresh_tokens_revoked_callback(
+      base::RepeatingCallback<void(const std::string&)> callback) {
+    on_refresh_tokens_revoked_callback_ = std::move(callback);
+  }
+
   void set_on_refresh_tokens_loaded_callback(base::OnceClosure callback) {
     on_refresh_tokens_loaded_callback_ = std::move(callback);
   }
 
  private:
   // OAuth2TokenService::Observer:
+  void OnRefreshTokenAvailable(const std::string& account_id) override {
+    if (on_refresh_tokens_available_callback_)
+      std::move(on_refresh_tokens_available_callback_).Run(account_id);
+  }
+
+  void OnRefreshTokenRevoked(const std::string& account_id) override {
+    if (on_refresh_tokens_revoked_callback_)
+      std::move(on_refresh_tokens_revoked_callback_).Run(account_id);
+  }
+
   void OnRefreshTokensLoaded() override {
     if (on_refresh_tokens_loaded_callback_)
       std::move(on_refresh_tokens_loaded_callback_).Run();
   }
 
   OAuth2TokenService* token_service_;
+  base::RepeatingCallback<void(const std::string&)>
+      on_refresh_tokens_available_callback_;
+  base::RepeatingCallback<void(const std::string&)>
+      on_refresh_tokens_revoked_callback_;
   base::OnceClosure on_refresh_tokens_loaded_callback_;
 };
 
@@ -42,14 +77,37 @@
 class AccountsMutatorImplTest : public testing::Test {
  public:
   AccountsMutatorImplTest()
-      : token_service_(&pref_service_),
+      : signin_client_(&pref_service_),
+        token_service_(&pref_service_),
         token_service_observer_(&token_service_),
         accounts_mutator_(&token_service_) {
     ProfileOAuth2TokenService::RegisterProfilePrefs(pref_service_.registry());
+
+    AccountTrackerService::RegisterPrefs(pref_service_.registry());
+    account_tracker_service_.Initialize(&pref_service_, base::FilePath());
+
+    AccountFetcherService::RegisterPrefs(pref_service_.registry());
+    account_fetcher_ = std::make_unique<FakeAccountFetcherService>();
+    account_fetcher_->Initialize(&signin_client_, &token_service_,
+                                 &account_tracker_service_,
+                                 std::make_unique<TestImageDecoder>());
+
+    // Need to enable network fetches so that AccountFetcherService will talk
+    // to the AccountTrackerService to remove the account when revoking tokens.
+    account_fetcher_->EnableNetworkFetchesForTest();
+  }
+
+  ~AccountsMutatorImplTest() override {
+    account_fetcher_->Shutdown();
+    account_fetcher_.reset();
   }
 
   FakeProfileOAuth2TokenService* token_service() { return &token_service_; }
 
+  AccountTrackerService* account_tracker_service() {
+    return &account_tracker_service_;
+  }
+
   TestTokenServiceObserver* token_service_observer() {
     return &token_service_observer_;
   }
@@ -59,7 +117,10 @@
  private:
   base::MessageLoop message_loop_;
   sync_preferences::TestingPrefServiceSyncable pref_service_;
+  TestSigninClient signin_client_;
   FakeProfileOAuth2TokenService token_service_;
+  AccountTrackerService account_tracker_service_;
+  std::unique_ptr<FakeAccountFetcherService> account_fetcher_;
   TestTokenServiceObserver token_service_observer_;
   AccountsMutatorImpl accounts_mutator_;
 
@@ -70,4 +131,94 @@
   // Should not crash.
 }
 
+// Test that attempting to remove an existing account should result in firing
+// the right callbacks from AccountTrackerService or ProfileOAuth2TokenService.
+TEST_F(AccountsMutatorImplTest, RemoveAccount_ExistingAccount) {
+  // First of all add the account to the account tracker service.
+  base::RunLoop run_loop;
+  token_service_observer()->set_on_refresh_tokens_available_callback(
+      base::BindRepeating([](base::RunLoop* loop,
+                             const std::string& account_id) { loop->Quit(); },
+                          base::Unretained(&run_loop)));
+
+  // TODO(crbug.com/907901): Migrate this to
+  // AccountsMutator::AddOrUpdateAccount() once available.
+  std::string account_id =
+      account_tracker_service()->SeedAccountInfo(kTestGaiaId, kTestEmail);
+  token_service()->UpdateCredentials(account_id, kRefreshToken);
+  run_loop.Run();
+
+  EXPECT_TRUE(token_service()->RefreshTokenIsAvailable(account_id));
+  EXPECT_FALSE(token_service()->RefreshTokenHasError(account_id));
+  EXPECT_EQ(account_tracker_service()->GetAccounts().size(), 1U);
+
+  // Now remove the account that we just added.
+  base::RunLoop run_loop2;
+  token_service_observer()->set_on_refresh_tokens_revoked_callback(
+      base::BindRepeating(
+          [](base::RunLoop* loop, const std::string& expected_id,
+             const std::string& removed_account_id) {
+            EXPECT_EQ(removed_account_id, expected_id);
+            loop->Quit();
+          },
+          base::Unretained(&run_loop2), account_id));
+
+  accounts_mutator()->RemoveAccount(account_id);
+  run_loop2.Run();
+
+  EXPECT_FALSE(token_service()->RefreshTokenIsAvailable(account_id));
+  EXPECT_FALSE(token_service()->RefreshTokenHasError(account_id));
+  EXPECT_EQ(account_tracker_service()->GetAccounts().size(), 0U);
+}
+
+// Test that attempting to remove all accounts removes all the tokens from the
+// PO2TS and every account from the AccountTrackerService.
+TEST_F(AccountsMutatorImplTest, RemoveAllAccounts) {
+  // First of all the first account to the account tracker service.
+  base::RunLoop run_loop;
+  token_service_observer()->set_on_refresh_tokens_available_callback(
+      base::BindRepeating([](base::RunLoop* loop,
+                             const std::string& account_id) { loop->Quit(); },
+                          base::Unretained(&run_loop)));
+
+  // TODO(crbug.com/907901): Migrate this to
+  // AccountsMutator::AddOrUpdateAccount() once available.
+  std::string account_id =
+      account_tracker_service()->SeedAccountInfo(kTestGaiaId, kTestEmail);
+  token_service()->UpdateCredentials(account_id, kRefreshToken);
+  run_loop.Run();
+
+  EXPECT_TRUE(token_service()->RefreshTokenIsAvailable(account_id));
+  EXPECT_FALSE(token_service()->RefreshTokenHasError(account_id));
+  EXPECT_EQ(account_tracker_service()->GetAccounts().size(), 1U);
+
+  // Now add the second account.
+  base::RunLoop run_loop2;
+  token_service_observer()->set_on_refresh_tokens_available_callback(
+      base::BindRepeating([](base::RunLoop* loop,
+                             const std::string& account_id) { loop->Quit(); },
+                          base::Unretained(&run_loop2)));
+
+  // TODO(crbug.com/907901): Migrate this to
+  // AccountsMutator::AddOrUpdateAccount() once available.
+  std::string account_id2 =
+      account_tracker_service()->SeedAccountInfo(kTestGaiaId2, kTestEmail2);
+  token_service()->UpdateCredentials(account_id2, kRefreshToken2);
+  run_loop2.Run();
+
+  EXPECT_TRUE(token_service()->RefreshTokenIsAvailable(account_id2));
+  EXPECT_FALSE(token_service()->RefreshTokenHasError(account_id2));
+  EXPECT_EQ(account_tracker_service()->GetAccounts().size(), 2U);
+
+  // Now remove everything and check that there are no lingering accounts, nor
+  // refresh tokens associated to |kTestGaiaId| and |kTestGaiaId2| afterwards.
+  base::RunLoop run_loop3;
+  accounts_mutator()->RemoveAllAccounts();
+  run_loop3.RunUntilIdle();
+
+  EXPECT_FALSE(token_service()->RefreshTokenIsAvailable(kTestGaiaId));
+  EXPECT_FALSE(token_service()->RefreshTokenIsAvailable(kTestGaiaId2));
+  EXPECT_EQ(account_tracker_service()->GetAccounts().size(), 0U);
+}
+
 }  // namespace identity
diff --git a/services/identity/public/cpp/identity_manager.cc b/services/identity/public/cpp/identity_manager.cc
index 2e68396a..1fce2e3 100644
--- a/services/identity/public/cpp/identity_manager.cc
+++ b/services/identity/public/cpp/identity_manager.cc
@@ -250,6 +250,10 @@
   return account_tracker_service_;
 }
 
+GaiaCookieManagerService* IdentityManager::GetGaiaCookieManagerService() {
+  return gaia_cookie_manager_service_;
+}
+
 void IdentityManager::SetPrimaryAccountSynchronouslyForTests(
     const std::string& gaia_id,
     const std::string& email_address,
diff --git a/services/identity/public/cpp/identity_manager.h b/services/identity/public/cpp/identity_manager.h
index 9e6a990..e016bd4 100644
--- a/services/identity/public/cpp/identity_manager.h
+++ b/services/identity/public/cpp/identity_manager.h
@@ -30,11 +30,12 @@
 namespace chromeos {
 class ChromeSessionManager;
 class UserSessionManager;
-}
+}  // namespace chromeos
 
 namespace network {
 class SharedURLLoaderFactory;
-}
+class TestURLLoaderFactory;
+}  // namespace network
 
 // Necessary to declare these classes as friends.
 class ArcSupportHostTest;
@@ -44,6 +45,7 @@
 class AccountsMutator;
 class PrimaryAccountMutator;
 enum class ClearPrimaryAccountPolicy;
+struct CookieParams;
 
 // Gives access to information about the user's Google identities. See
 // ./README.md for detailed documentation.
@@ -330,6 +332,11 @@
 
   friend void DisableAccessTokenFetchRetries(IdentityManager* identity_manager);
 
+  friend void SetCookieAccounts(
+      IdentityManager* identity_manager,
+      network::TestURLLoaderFactory* test_url_loader_factory,
+      const std::vector<identity::CookieParams>& cookie_accounts);
+
   // These clients needs to call SetPrimaryAccountSynchronously().
   friend ArcSupportHostTest;
   friend arc::ArcTermsOfServiceDefaultNegotiatorTest;
@@ -340,6 +347,7 @@
   SigninManagerBase* GetSigninManager();
   ProfileOAuth2TokenService* GetTokenService();
   AccountTrackerService* GetAccountTrackerService();
+  GaiaCookieManagerService* GetGaiaCookieManagerService();
 
   // Sets the primary account info synchronously with both the IdentityManager
   // and its backing SigninManager/ProfileOAuth2TokenService instances.
diff --git a/services/identity/public/cpp/identity_test_utils.cc b/services/identity/public/cpp/identity_test_utils.cc
index 529f678..ee759236 100644
--- a/services/identity/public/cpp/identity_test_utils.cc
+++ b/services/identity/public/cpp/identity_test_utils.cc
@@ -310,6 +310,33 @@
   return identity_manager->GetTokenService()->AreAllCredentialsLoaded();
 }
 
+void SetCookieAccounts(IdentityManager* identity_manager,
+                       network::TestURLLoaderFactory* test_url_loader_factory,
+                       const std::vector<CookieParams>& cookie_accounts) {
+  // Convert |cookie_accounts| to the format list_accounts_test_utils wants.
+  std::vector<signin::CookieParams> gaia_cookie_accounts;
+  for (const CookieParams& params : cookie_accounts) {
+    gaia_cookie_accounts.push_back({params.email, params.gaia_id,
+                                    /*valid=*/true, /*signed_out=*/false,
+                                    /*verified=*/true});
+  }
+
+  base::RunLoop run_loop;
+  OneShotIdentityManagerObserver cookie_observer(
+      identity_manager, run_loop.QuitClosure(),
+      IdentityManagerEvent::ACCOUNTS_IN_COOKIE_UPDATED);
+
+  signin::SetListAccountsResponseWithParams(gaia_cookie_accounts,
+                                            test_url_loader_factory);
+
+  GaiaCookieManagerService* cookie_manager =
+      identity_manager->GetGaiaCookieManagerService();
+  cookie_manager->set_list_accounts_stale_for_testing(true);
+  cookie_manager->ListAccounts(nullptr, nullptr);
+
+  run_loop.Run();
+}
+
 void SetCookieAccounts(FakeGaiaCookieManagerService* cookie_manager,
                        IdentityManager* identity_manager,
                        const std::vector<CookieParams>& cookie_accounts) {
diff --git a/services/identity/public/cpp/identity_test_utils.h b/services/identity/public/cpp/identity_test_utils.h
index 29ef957..23267bf 100644
--- a/services/identity/public/cpp/identity_test_utils.h
+++ b/services/identity/public/cpp/identity_test_utils.h
@@ -13,6 +13,10 @@
 class FakeGaiaCookieManagerService;
 class GoogleServiceAuthError;
 
+namespace network {
+class TestURLLoaderFactory;
+}
+
 // Test-related utilities that don't fit in either IdentityTestEnvironment or
 // IdentityManager itself. NOTE: Using these utilities directly is discouraged,
 // but sometimes necessary during conversion. Use IdentityTestEnvironment if
@@ -61,14 +65,12 @@
 // Sets a special invalid refresh token for the primary account (which must
 // already be set). Blocks until the refresh token is set.
 // NOTE: See disclaimer at top of file re: direct usage.
-void SetInvalidRefreshTokenForPrimaryAccount(
-    IdentityManager* identity_manager);
+void SetInvalidRefreshTokenForPrimaryAccount(IdentityManager* identity_manager);
 
 // Removes any refresh token for the primary account, if present. Blocks until
 // the refresh token is removed.
 // NOTE: See disclaimer at top of file re: direct usage.
-void RemoveRefreshTokenForPrimaryAccount(
-    IdentityManager* identity_manager);
+void RemoveRefreshTokenForPrimaryAccount(IdentityManager* identity_manager);
 
 // Makes the primary account (which must not already be set) available for the
 // given email address, generating a GAIA ID and refresh token that correspond
@@ -77,9 +79,8 @@
 // the primary account is available. Returns the AccountInfo of the
 // newly-available account.
 // NOTE: See disclaimer at top of file re: direct usage.
-AccountInfo MakePrimaryAccountAvailable(
-    IdentityManager* identity_manager,
-    const std::string& email);
+AccountInfo MakePrimaryAccountAvailable(IdentityManager* identity_manager,
+                                        const std::string& email);
 
 // Clears the primary account if present, with |policy| used to determine
 // whether to keep or remove all accounts. On non-ChromeOS, results in the
@@ -125,6 +126,13 @@
 // Puts the given accounts into the Gaia cookie, replacing any previous
 // accounts. Blocks until the accounts have been set.
 // NOTE: See disclaimer at top of file re: direct usage.
+void SetCookieAccounts(IdentityManager* identity_manager,
+                       network::TestURLLoaderFactory* test_url_loader_factory,
+                       const std::vector<CookieParams>& cookie_accounts);
+
+// Same as above, but takes a FakeGaiaCookieManagerService.
+// TODO(https://crbug.com/1379770): Delete this overload once FakeGCMS has been
+// eliminated.
 void SetCookieAccounts(FakeGaiaCookieManagerService* cookie_manager,
                        IdentityManager* identity_manager,
                        const std::vector<CookieParams>& cookie_accounts);
diff --git a/services/network/public/mojom/BUILD.gn b/services/network/public/mojom/BUILD.gn
index c394d43f..e263027 100644
--- a/services/network/public/mojom/BUILD.gn
+++ b/services/network/public/mojom/BUILD.gn
@@ -48,22 +48,6 @@
   ]
 }
 
-# UDP socket interface relies on mojo.common.mojom.ReadOnlyBuffer, which is
-# mapped to base::span<const uint8_t>. ReadOnlyBufffer doesn't yet work with
-# lazy serialization, so this needs to be in a separate target that doesn't have
-# support_lazy_serialization = true.
-mojom("udp_socket_interface") {
-  sources = [
-    "udp_socket.mojom",
-  ]
-
-  public_deps = [
-    ":mojom_ip_address",
-    ":mutable_network_traffic_annotation_interface",
-    "//mojo/public/mojom/base:read_only_buffer",
-  ]
-}
-
 # This target is split from "mojom" target as the lazy serialization may
 # cause problems. See https://crbug.com/822732.
 mojom("websocket_mojom") {
@@ -85,11 +69,6 @@
 }
 
 mojom("mojom") {
-  # URLLoader & URLLoaderFactory are used in-process in the browser when
-  # navigation uses URLLoader (NavigationMojoResponse) and in the renderer
-  # when Service Worker uses direct communication (S13nServiceWorker).
-  support_lazy_serialization = true
-
   sources = [
     "cookie_manager.mojom",
     "cors.mojom",
@@ -118,6 +97,7 @@
     "ssl_config.mojom",
     "tcp_socket.mojom",
     "tls_socket.mojom",
+    "udp_socket.mojom",
     "url_loader.mojom",
     "url_loader_factory.mojom",
   ]
@@ -126,7 +106,6 @@
     ":data_pipe_interfaces",
     ":mojom_ip_address",
     ":mutable_network_traffic_annotation_interface",
-    ":udp_socket_interface",
     ":websocket_mojom",
     "//components/content_settings/core/common:mojo_bindings",
     "//mojo/public/mojom/base",
diff --git a/services/service_manager/sandbox/mac/audio.sb b/services/service_manager/sandbox/mac/audio.sb
index f00e926..c7a6d57 100644
--- a/services/service_manager/sandbox/mac/audio.sb
+++ b/services/service_manager/sandbox/mac/audio.sb
@@ -8,17 +8,19 @@
 (allow file-read*
   (path (user-homedir-path "/Library/Caches/com.apple.coreaudio.components.plist"))
   (regex (user-homedir-path #"/Library/Preferences/com.apple.coreaudio.*"))
-  (subpath (user-homedir-path "/Library/Audio/Plug-Ins"))
   (subpath "/Library/Audio/Plug-Ins")
   (subpath "/Library/QuickTime")
   (subpath "/System/Library/Components")
-  (subpath "/System/Library/Extensions"))
+  (subpath "/System/Library/Extensions")
+  (subpath (user-homedir-path "/Library/Audio/Plug-Ins"))
+)
 
 (allow device-microphone)
 
 (allow iokit-open
   (iokit-user-client-class "IOAudioControlUserClient")
-  (iokit-user-client-class "IOAudioEngineUserClient"))
+  (iokit-user-client-class "IOAudioEngineUserClient")
+)
 
 (allow ipc-posix-shm-read* ipc-posix-shm-write-data
   (ipc-posix-name-regex #"^AudioIO"))
@@ -27,19 +29,22 @@
 (allow mach-lookup
   (global-name "com.apple.audio.SystemSoundServer-OSX")
   (global-name "com.apple.audio.VDCAssistant")
+  (global-name "com.apple.audio.audiohald")
   (global-name "com.apple.audio.coreaudiod")
-  (global-name "com.apple.audio.audiohald"))
+)
 
 (if (>= os-version 1013)
   (allow mach-lookup
     (global-name "com.apple.audio.AudioComponentRegistrar")
-    (xpc-service-name "com.apple.audio.SandboxHelper")))
+    (xpc-service-name "com.apple.audio.SandboxHelper")
+  ))
 
 ; sysctls.
 (allow sysctl-read
-  (sysctl-name "hw.optional.avx2_0")
   (sysctl-name "hw.optional.avx1_0")
-  (sysctl-name "hw.optional.sse4_2")
-  (sysctl-name "hw.optional.sse4_1")
+  (sysctl-name "hw.optional.avx2_0")
+  (sysctl-name "hw.optional.sse2")
   (sysctl-name "hw.optional.sse3")
-  (sysctl-name "hw.optional.sse2"))
+  (sysctl-name "hw.optional.sse4_1")
+  (sysctl-name "hw.optional.sse4_2")
+)
diff --git a/services/service_manager/sandbox/mac/common.sb b/services/service_manager/sandbox/mac/common.sb
index 2280ebf..160308b 100644
--- a/services/service_manager/sandbox/mac/common.sb
+++ b/services/service_manager/sandbox/mac/common.sb
@@ -50,11 +50,13 @@
     (allow file-read-data
       (subpath "/Library/Fonts")
       (subpath "/System/Library/Fonts")
-      (subpath (user-homedir-path "/Library/Fonts")))
+      (subpath (user-homedir-path "/Library/Fonts"))
+    )
     (allow mach-lookup
+      ; https://crbug.com/756145, https://crbug.com/786615
+      (global-name "com.apple.FontObjectsServer")
       (global-name "com.apple.fonts")
-      ; crbug.com/756145, crbug.com/786615
-      (global-name "com.apple.FontObjectsServer"))
+    )
     (if (< os-version 1012)
       (allow mach-lookup (global-name "com.apple.FontServer")))
     ; To allow accessing downloaded and other hidden fonts in
@@ -84,7 +86,8 @@
 
 (allow mach-lookup
   (browser-service-name "FieldTrialMemoryServer")
-  (browser-service-name "rohitfork"))
+  (browser-service-name "rohitfork")
+)
 
 ; Allow realpath() to work.
 (allow file-read-metadata (subpath "/"))
@@ -97,7 +100,8 @@
   (subpath "/System/Library/Frameworks")
   (subpath "/System/Library/Preferences/Logging")
   (subpath "/System/Library/PrivateFrameworks")
-  (subpath "/usr/lib"))
+  (subpath "/usr/lib")
+)
 
 ; Reads from /etc.
 ; This is read by CFPrefs calling getpwuid in a loop. libinfo then fails to
@@ -115,7 +119,8 @@
 (allow file-read-data
   (path "/dev/null")
   (path "/dev/random")
-  (path "/dev/urandom"))
+  (path "/dev/urandom")
+)
 
 (if (>= os-version 1013)
   (begin (allow file-read* (subpath "/private/var/db/timezone"))
@@ -126,29 +131,32 @@
 
 ; Reads from /Library.
 (allow file-read-data
-  (path "/Library/Preferences/.GlobalPreferences.plist"))
+  (path "/Library/Preferences/.GlobalPreferences.plist")
+)
 
 ; Reads from /System.
 (allow file-read-data
+  (path "/System/Library/CoreServices/SystemVersion.plist")
   (path "/System/Library/CoreServices/checkfixlist")
-  (path "/System/Library/CoreServices/SystemVersion.plist"))
+)
 
 ; Reads from /usr.
 (allow file-read-data
-  (subpath "/usr/share/icu"))
+  (subpath "/usr/share/icu")
+)
 
 ; Access to the home directory.
 (allow file-read-data
   (path (user-homedir-path "/Library/Preferences/.GlobalPreferences.plist"))
-  (regex (user-homedir-path #"/Library/Preferences/ByHost/.GlobalPreferences.*")))
+  (regex (user-homedir-path #"/Library/Preferences/ByHost/.GlobalPreferences.*"))
+)
 
 ; Mach IPC needed by all Chromium Helper instances.
 (allow mach-lookup
-  ; crbug.com/792229
-  (global-name "com.apple.logd")
+  (global-name "com.apple.logd")  ; https://crbug.com/792229
   (global-name "com.apple.system.logger")
-  ; crbug.com/792228
-  (global-name "com.apple.system.opendirectoryd.libinfo"))
+  (global-name "com.apple.system.opendirectoryd.libinfo")  ; https://crbug.com/792228
+)
 
 ; sysctls permitted.
 (allow sysctl-read
@@ -169,7 +177,8 @@
   (sysctl-name "kern.osrelease")
   (sysctl-name "kern.ostype")
   (sysctl-name "kern.osversion")
-  (sysctl-name (string-append "kern.proc.pid." (param current-pid)))
   (sysctl-name "kern.usrstack64")
   (sysctl-name "kern.version")
-  (sysctl-name "sysctl.proc_cputype"))
+  (sysctl-name "sysctl.proc_cputype")
+  (sysctl-name (string-append "kern.proc.pid." (param current-pid)))
+)
diff --git a/services/service_manager/sandbox/mac/gpu_v2.sb b/services/service_manager/sandbox/mac/gpu_v2.sb
index fd9a44b..dfcde52 100644
--- a/services/service_manager/sandbox/mac/gpu_v2.sb
+++ b/services/service_manager/sandbox/mac/gpu_v2.sb
@@ -11,9 +11,10 @@
   (global-name "com.apple.cvmsServ")
   (global-name "com.apple.system.notification_center")
   (global-name "com.apple.tsm.uiserver")
-  (global-name "com.apple.windowserver.active"))
+  (global-name "com.apple.windowserver.active")
+)
 
-; Needed for WebGL - crbug.com/75343
+; Needed for WebGL - https://crbug.com/75343
 (allow iokit-open
   (iokit-connection "IOAccelerator")
   (iokit-user-client-class "AGPMClient")
@@ -23,8 +24,9 @@
   (iokit-user-client-class "IOFramebufferSharedUserClient")
   (iokit-user-client-class "IOHIDParamUserClient")
   (iokit-user-client-class "IOSurfaceRootUserClient")
-  (iokit-user-client-class "IOSurfaceSendRight"))
+  (iokit-user-client-class "IOSurfaceSendRight")
   (iokit-user-client-class "RootDomainUserClient")
+)
 
 (allow ipc-posix-shm-read-data
   (ipc-posix-name "apple.shm.notification_center"))
diff --git a/services/service_manager/sandbox/mac/nacl_loader.sb b/services/service_manager/sandbox/mac/nacl_loader.sb
index 3ed0c34..96776174 100644
--- a/services/service_manager/sandbox/mac/nacl_loader.sb
+++ b/services/service_manager/sandbox/mac/nacl_loader.sb
@@ -20,7 +20,8 @@
 
 (allow iokit-open
   (iokit-user-client-class "IOSurfaceSendRight")
-  (iokit-user-client-class "RootDomainUserClient"))
+  (iokit-user-client-class "RootDomainUserClient")
+)
 
 (allow file-read-data
   (subpath "/usr/share/locale")
@@ -28,8 +29,10 @@
   (path (string-append
           (user-homedir-path "/Library/Preferences/")
           (param bundle-id)
-          ".plist")))
+          ".plist"))
+)
 
 (allow mach-lookup
+  (global-name "com.apple.PowerManagement.control")
   (global-name "com.apple.system.notification_center")
-  (global-name "com.apple.PowerManagement.control"))
+)
diff --git a/services/service_manager/sandbox/mac/pdf_compositor.sb b/services/service_manager/sandbox/mac/pdf_compositor.sb
index fc09869..7d6e320 100644
--- a/services/service_manager/sandbox/mac/pdf_compositor.sb
+++ b/services/service_manager/sandbox/mac/pdf_compositor.sb
@@ -16,5 +16,5 @@
 
 ; Reads from /System.
 (allow file-read-data
-  ; https://crbug.com/822218
-  (subpath "/System/Library/ColorSync/Profiles"))
+  (subpath "/System/Library/ColorSync/Profiles")  ; https://crbug.com/822218
+)
diff --git a/services/service_manager/sandbox/mac/ppapi.sb b/services/service_manager/sandbox/mac/ppapi.sb
index 341656f0..6c0ca29 100644
--- a/services/service_manager/sandbox/mac/ppapi.sb
+++ b/services/service_manager/sandbox/mac/ppapi.sb
@@ -16,22 +16,25 @@
 
 ; Mach lookups.
 (allow mach-lookup
-  (global-name "com.apple.windowserver.active"))
+  (global-name "com.apple.windowserver.active")
+)
 
 ; IOKit
 (allow iokit-open
-  (iokit-registry-entry-class "IOSurfaceRootUserClient"))
+  (iokit-registry-entry-class "IOSurfaceRootUserClient")
+)
 
 ; Reads from home dir.
 (allow file-read-data
-  (path (user-homedir-path "/Library/Preferences/com.apple.universalaccess.plist")))
+  (path (user-homedir-path "/Library/Preferences/com.apple.universalaccess.plist"))
+)
 
 ; Reads from /System.
 (allow file-read-data
   (path "/System/Library/Colors/System.clr/System.clr")
+  (subpath "/System/Library/ColorSync/Profiles")  ; https://crbug.com/822218
   (subpath "/System/Library/CoreServices/SystemAppearance.bundle")
-  ; https://crbug.com/822218
-  (subpath "/System/Library/ColorSync/Profiles"))
+)
 
 ; Allow the ppapi plugin binaries to be loaded.
 (if (param-defined? ppapi-plugin-0)
diff --git a/services/service_manager/sandbox/mac/renderer.sb b/services/service_manager/sandbox/mac/renderer.sb
index 4211576..0e3db5f74 100644
--- a/services/service_manager/sandbox/mac/renderer.sb
+++ b/services/service_manager/sandbox/mac/renderer.sb
@@ -11,12 +11,14 @@
 ; Reads from the home directory.
 (allow file-read-data
   (path (user-homedir-path "/.CFUserTextEncoding"))
-  (path (user-homedir-path "/Library/Preferences/com.apple.universalaccess.plist")))
+  (path (user-homedir-path "/Library/Preferences/com.apple.universalaccess.plist"))
+)
 
 ; Reads of /dev devices.
 (allow file-read-data
   (path "/dev/autofs_nowait")
-  (path "/dev/fd"))
+  (path "/dev/fd")
+)
 
 ; Reads of signed Mach-O blobs created by the CVMS server.
 ; https://crbug.com/850021
@@ -24,7 +26,8 @@
   (allow file-read*
     (extension "com.apple.cvms.kernel")
     (prefix "/private/tmp/cvmsCodeSignObj")
-    (subpath "/private/var/db/CVMS")))
+    (subpath "/private/var/db/CVMS")
+  ))
 
 (allow file-write-data
   (require-all
@@ -43,30 +46,31 @@
   (subpath "/System/Library/CoreServices/SystemAppearance.bundle")
   (subpath "/System/Library/CoreServices/SystemVersion.bundle")
   (subpath "/System/Library/Extensions")  ; https://crbug.com/847518
-  (subpath "/System/Library/LinguisticData"))
+  (subpath "/System/Library/LinguisticData")
+)
 
 ; Reads from /Library.
 (allow file-read-data
-  (subpath "/Library/GPUBundles"))  ; https://crbug.com/850021
+  (subpath "/Library/GPUBundles")  ; https://crbug.com/850021
+)
 
 ; IOKit
 (allow iokit-open
   (iokit-registry-entry-class "IOSurfaceRootUserClient")
-  (iokit-registry-entry-class "RootDomainUserClient"))
+  (iokit-registry-entry-class "RootDomainUserClient")
+)
 
 ; POSIX IPC
 (allow ipc-posix-shm-read-data
   (ipc-posix-name "apple.cfprefs.317580v1")
   (ipc-posix-name "apple.cfprefs.daemonv1")
-  ; crbug.com/792217
-  (ipc-posix-name "apple.shm.notification_center"))
+  (ipc-posix-name "apple.shm.notification_center")  ; https://crbug.com/792217
+)
 
 ; mach IPC
 (allow mach-lookup
-  ; crbug.com/792257
-  (global-name "com.apple.distributed_notifications@Uv3")
+  (global-name "com.apple.cvmsServ")  ; https://crbug.com/850021
+  (global-name "com.apple.distributed_notifications@Uv3")  ; https://crbug.com/792257
   (global-name "com.apple.lsd.mapdb")
-  ; https://crbug.com/850021
-  (global-name "com.apple.cvmsServ")
-  ; crbug.com/792217
-  (global-name "com.apple.system.notification_center"))
+  (global-name "com.apple.system.notification_center")  ; https://crbug.com/792217
+)
diff --git a/services/viz/public/cpp/compositing/struct_traits_unittest.cc b/services/viz/public/cpp/compositing/struct_traits_unittest.cc
index f5ca930..e78a1c1 100644
--- a/services/viz/public/cpp/compositing/struct_traits_unittest.cc
+++ b/services/viz/public/cpp/compositing/struct_traits_unittest.cc
@@ -794,7 +794,7 @@
           base::nullopt,
           SurfaceId(FrameSinkId(1337, 1234),
                     LocalSurfaceId(1234, base::UnguessableToken::Create()))),
-      SK_ColorYELLOW, false);
+      SK_ColorYELLOW, false, false);
 
   std::unique_ptr<RenderPass> output;
   mojo::test::SerializeAndDeserialize<mojom::RenderPass>(&input, &output);
@@ -939,7 +939,7 @@
       render_pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
   primary_surface_quad->SetNew(
       sqs, rect3, rect3, SurfaceRange(fallback_surface_id, primary_surface_id),
-      SK_ColorBLUE, false);
+      SK_ColorBLUE, false, false);
 
   const gfx::Rect rect4(1234, 5678, 9101112, 13141516);
   const ResourceId resource_id4(1337);
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index ebecf79..69ed19b 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -3867,7 +3867,8 @@
           "dimension_sets": [
             {
               "device_type": "kevin",
-              "os": "ChromeOS"
+              "os": "ChromeOS",
+              "pool": "chrome-cros-dut"
             }
           ]
         },
@@ -3879,7 +3880,8 @@
           "dimension_sets": [
             {
               "device_type": "kevin",
-              "os": "ChromeOS"
+              "os": "ChromeOS",
+              "pool": "chrome-cros-dut"
             }
           ]
         },
@@ -3891,7 +3893,8 @@
           "dimension_sets": [
             {
               "device_type": "kevin",
-              "os": "ChromeOS"
+              "os": "ChromeOS",
+              "pool": "chrome-cros-dut"
             }
           ]
         },
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 98806c4..f478284 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -810,6 +810,21 @@
       },
       {
         "args": [
+          "--test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.net_unittests.filter",
+          "--qemu-require-kvm"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1"
+            }
+          ]
+        },
+        "test": "net_unittests"
+      },
+      {
+        "args": [
           "--qemu-require-kvm"
         ],
         "swarming": {
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index ad96c94..b2fd564 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -664,10 +664,8 @@
   'net_unittests': {
     'remove_from': [
       # chromium.fyi
-      'fuchsia-fyi-arm64-rel',  # https://crbug.com/847915
-      'fuchsia-fyi-x64-dbg',  # https://crbug.com/844416 (and 847915)
-      # chromium.linux
-      'Fuchsia x64',  # https://crbug.com/847915
+      'fuchsia-fyi-arm64-rel',  # https://crbug.com/877248
+      'fuchsia-fyi-x64-dbg',  # https://crbug.com/844416
     ],
     'modifications': {
       # chromium.clang
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 7e261240..11f17c4 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -1410,6 +1410,9 @@
               # devices running an OS version at or above the LKGM. For now,
               # just accept any OS version.
               'device_type': 'kevin',
+              # Special pool is needed for the devices since they also run
+              # swarmbucket builds.
+              'pool': 'chrome-cros-dut',
             },
           ],
         },
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 67051f86..a8f7de00 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1382,25 +1382,6 @@
             ]
         }
     ],
-    "DataReductionProxyBrotliHoldback": [
-        {
-            "platforms": [
-                "android",
-                "windows",
-                "mac",
-                "chromeos",
-                "linux"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "DataReductionProxyBrotliHoldback"
-                    ]
-                }
-            ]
-        }
-    ],
     "DataReductionProxyFREPromo": [
         {
             "platforms": [
@@ -1859,21 +1840,6 @@
             ]
         }
     ],
-    "ExtendedShellExtensionsEnumeration": [
-        {
-            "platforms": [
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "ExtendedShellExtensionsEnumeration"
-                    ]
-                }
-            ]
-        }
-    ],
     "ExtensionContentVerification": [
         {
             "platforms": [
diff --git a/third_party/blink/public/blink_resources.grd b/third_party/blink/public/blink_resources.grd
index 42047241c..b2e7eac 100644
--- a/third_party/blink/public/blink_resources.grd
+++ b/third_party/blink/public/blink_resources.grd
@@ -51,6 +51,7 @@
       <!-- Layered API scripts. Should be consistent with kLayeredAPIResources
            in renderer/core/script/layered_api.cc -->
       <include name="IDR_LAYERED_API_ASYNC_LOCAL_STORAGE_INDEX_JS" file="../renderer/core/script/resources/layered_api/async-local-storage/index.js" type="BINDATA" skip_minify="true"/>
+      <include name="IDR_LAYERED_API_ASYNC_LOCAL_STORAGE_IDB_UTILS_JS" file="../renderer/core/script/resources/layered_api/async-local-storage/idb_utils.js" type="BINDATA" skip_minify="true"/>
       <include name="IDR_LAYERED_API_BLANK_INDEX_JS" file="../renderer/core/script/resources/layered_api/blank/index.js" type="BINDATA" skip_minify="true"/>
       <include name="IDR_LAYERED_API_VIRTUAL_SCROLLER_INDEX_JS" file="../renderer/core/script/resources/layered_api/virtual-scroller/index.js" type="BINDATA" skip_minify="true"/>
       <include name="IDR_LAYERED_API_VIRTUAL_SCROLLER_ITEM_SOURCE_JS" file="../renderer/core/script/resources/layered_api/virtual-scroller/item-source.js" type="BINDATA" skip_minify="true"/>
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc
index 9f45d48..b3bbbb81 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -286,9 +286,10 @@
 
 void WebViewImpl::SetPrerendererClient(
     WebPrerendererClient* prerenderer_client) {
-  DCHECK(page_);
-  ProvidePrerendererClientTo(*page_, MakeGarbageCollected<PrerendererClient>(
-                                         *page_, prerenderer_client));
+  DCHECK(AsView().page);
+  ProvidePrerendererClientTo(*AsView().page,
+                             MakeGarbageCollected<PrerendererClient>(
+                                 *AsView().page, prerenderer_client));
 }
 
 WebViewImpl::WebViewImpl(WebViewClient* client,
@@ -341,27 +342,29 @@
   Page::PageClients page_clients;
   page_clients.chrome_client = chrome_client_.Get();
 
-  page_ =
+  AsView().page =
       Page::CreateOrdinary(page_clients, opener ? opener->GetPage() : nullptr);
-  CoreInitializer::GetInstance().ProvideModulesToPage(*page_, AsView().client);
+  CoreInitializer::GetInstance().ProvideModulesToPage(*AsView().page,
+                                                      AsView().client);
   SetIsHidden(is_hidden, /*is_initial_state=*/true);
 
   // When not compositing, keep the Page in the loop so that it will paint all
   // content into the root layer, as multiple layers can only be used when
   // compositing them together later.
   if (does_composite_)
-    page_->GetSettings().SetAcceleratedCompositingEnabled(true);
+    AsView().page->GetSettings().SetAcceleratedCompositingEnabled(true);
 
   dev_tools_emulator_ = DevToolsEmulator::Create(this);
 
   AllInstances().insert(this);
 
   page_importance_signals_.SetObserver(client);
-  resize_viewport_anchor_ = MakeGarbageCollected<ResizeViewportAnchor>(*page_);
+  resize_viewport_anchor_ =
+      MakeGarbageCollected<ResizeViewportAnchor>(*AsView().page);
 }
 
 WebViewImpl::~WebViewImpl() {
-  DCHECK(!page_);
+  DCHECK(!AsView().page);
 }
 
 WebDevToolsAgentImpl* WebViewImpl::MainFrameDevToolsAgentImpl() {
@@ -370,19 +373,20 @@
 }
 
 WebLocalFrameImpl* WebViewImpl::MainFrameImpl() const {
-  return page_ && page_->MainFrame() && page_->MainFrame()->IsLocalFrame()
-             ? WebLocalFrameImpl::FromFrame(page_->DeprecatedLocalMainFrame())
+  Page* page = AsView().page.Get();
+  return page && page->MainFrame() && page->MainFrame()->IsLocalFrame()
+             ? WebLocalFrameImpl::FromFrame(page->DeprecatedLocalMainFrame())
              : nullptr;
 }
 
 bool WebViewImpl::TabKeyCyclesThroughElements() const {
-  DCHECK(page_);
-  return page_->TabKeyCyclesThroughElements();
+  DCHECK(AsView().page);
+  return AsView().page->TabKeyCyclesThroughElements();
 }
 
 void WebViewImpl::SetTabKeyCyclesThroughElements(bool value) {
-  if (page_)
-    page_->SetTabKeyCyclesThroughElements(value);
+  if (AsView().page)
+    AsView().page->SetTabKeyCyclesThroughElements(value);
 }
 
 void WebViewImpl::HandleMouseLeave(LocalFrame& main_frame,
@@ -406,21 +410,18 @@
   // Take capture on a mouse down on a plugin so we can send it mouse events.
   // If the hit node is a plugin but a scrollbar is over it don't start mouse
   // capture because it will interfere with the scrollbar receiving events.
-  if (event.button == WebMouseEvent::Button::kLeft &&
-      page_->MainFrame()->IsLocalFrame()) {
+  if (event.button == WebMouseEvent::Button::kLeft) {
     HitTestLocation location(
-        page_->DeprecatedLocalMainFrame()->View()->ConvertFromRootFrame(
-            event.PositionInWidget()));
-    HitTestResult result(page_->DeprecatedLocalMainFrame()
-                             ->GetEventHandler()
-                             .HitTestResultAtLocation(location));
+        main_frame.View()->ConvertFromRootFrame(event.PositionInWidget()));
+    HitTestResult result(
+        main_frame.GetEventHandler().HitTestResultAtLocation(location));
     result.SetToShadowHostIfInRestrictedShadowRoot();
     Node* hit_node = result.InnerNodeOrImageMapImage();
 
     if (!result.GetScrollbar() && hit_node && hit_node->GetLayoutObject() &&
         hit_node->GetLayoutObject()->IsEmbeddedObject()) {
       mouse_capture_node_ = hit_node;
-      page_->DeprecatedLocalMainFrame()->Client()->SetMouseCapture(true);
+      main_frame.Client()->SetMouseCapture(true);
       TRACE_EVENT_ASYNC_BEGIN0("input", "capturing mouse", this);
     }
   }
@@ -465,7 +466,7 @@
   if (!MainFrameImpl() || !MainFrameImpl()->GetFrameView())
     return;
 
-  page_->GetContextMenuController().ClearContextMenu();
+  AsView().page->GetContextMenuController().ClearContextMenu();
 
   WebMouseEvent transformed_event =
       TransformWebMouseEvent(MainFrameImpl()->GetFrameView(), event);
@@ -478,7 +479,7 @@
   if (result.InnerNodeOrImageMapImage())
     target_frame = result.InnerNodeOrImageMapImage()->GetDocument().GetFrame();
   else
-    target_frame = page_->GetFocusController().FocusedOrMainFrame();
+    target_frame = AsView().page->GetFocusController().FocusedOrMainFrame();
 
   if (!target_frame->IsLocalFrame())
     return;
@@ -567,8 +568,10 @@
   // Hit test across all frames and do touch adjustment as necessary for the
   // event type.
   GestureEventWithHitTestResults targeted_event =
-      page_->DeprecatedLocalMainFrame()->GetEventHandler().TargetGestureEvent(
-          scaled_event);
+      AsView()
+          .page->DeprecatedLocalMainFrame()
+          ->GetEventHandler()
+          .TargetGestureEvent(scaled_event);
 
   // Handle link highlighting outside the main switch to avoid getting lost in
   // the complicated set of cases handled below.
@@ -612,7 +615,7 @@
       if (!MainFrameImpl() || !MainFrameImpl()->GetFrameView())
         break;
 
-      page_->GetContextMenuController().ClearContextMenu();
+      AsView().page->GetContextMenuController().ClearContextMenu();
       {
         ContextMenuAllowedScope scope;
         event_result =
@@ -1037,7 +1040,8 @@
     const GestureEventWithHitTestResults& targeted_tap_event) {
   TRACE_EVENT0("input", "WebViewImpl::bestTapNode");
 
-  if (!page_ || !page_->MainFrame())
+  Page* page = AsView().page.Get();
+  if (!page || !page->MainFrame())
     return nullptr;
 
   Node* best_touch_node = targeted_tap_event.GetHitTestResult().InnerNode();
@@ -1057,11 +1061,11 @@
     return nullptr;
 
   Node* cursor_defining_ancestor = FindCursorDefiningAncestor(
-      best_touch_node, page_->DeprecatedLocalMainFrame());
+      best_touch_node, page->DeprecatedLocalMainFrame());
   // We show a highlight on tap only when the current node shows a hand cursor
   if (!cursor_defining_ancestor ||
       !ShowsHandCursor(cursor_defining_ancestor,
-                       page_->DeprecatedLocalMainFrame())) {
+                       page->DeprecatedLocalMainFrame())) {
     return nullptr;
   }
 
@@ -1074,10 +1078,10 @@
     best_touch_node = cursor_defining_ancestor;
     cursor_defining_ancestor = FindCursorDefiningAncestor(
         LayoutTreeBuilderTraversal::Parent(*best_touch_node),
-        page_->DeprecatedLocalMainFrame());
+        page->DeprecatedLocalMainFrame());
   } while (cursor_defining_ancestor &&
            ShowsHandCursor(cursor_defining_ancestor,
-                           page_->DeprecatedLocalMainFrame()));
+                           page->DeprecatedLocalMainFrame()));
 
   return best_touch_node;
 }
@@ -1286,7 +1290,8 @@
 }
 
 Frame* WebViewImpl::FocusedCoreFrame() const {
-  return page_ ? page_->GetFocusController().FocusedOrMainFrame() : nullptr;
+  Page* page = AsView().page.Get();
+  return page ? page->GetFocusController().FocusedOrMainFrame() : nullptr;
 }
 
 // WebWidget ------------------------------------------------------------------
@@ -1295,12 +1300,13 @@
   DCHECK(AllInstances().Contains(this));
   AllInstances().erase(this);
 
-  if (page_) {
-    // Initiate shutdown for the entire frameset.  This will cause a lot of
-    // notifications to be sent.
-    page_->WillBeDestroyed();
-    page_.Clear();
-  }
+  // We don't want Close() to happen twice do we??
+  CHECK(AsView().page);
+
+  // Initiate shutdown for the entire frameset.  This will cause a lot of
+  // notifications to be sent.
+  AsView().page->WillBeDestroyed();
+  AsView().page.Clear();
 
   // Reset the delegate to prevent notifications being sent as we're being
   // deleted.
@@ -1520,7 +1526,7 @@
 
 void WebViewImpl::SetSuppressFrameRequestsWorkaroundFor704763Only(
     bool suppress_frame_requests) {
-  page_->Animator().SetSuppressFrameRequestsWorkaroundFor704763Only(
+  AsView().page->Animator().SetSuppressFrameRequestsWorkaroundFor704763Only(
       suppress_frame_requests);
 }
 void WebViewImpl::BeginFrame(base::TimeTicks last_frame_time) {
@@ -1533,7 +1539,7 @@
 
   DocumentLifecycle::AllowThrottlingScope throttling_scope(
       MainFrameImpl()->GetFrame()->GetDocument()->Lifecycle());
-  PageWidgetDelegate::Animate(*page_, last_frame_time);
+  PageWidgetDelegate::Animate(*AsView().page, last_frame_time);
 }
 
 void WebViewImpl::RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) {
@@ -1553,8 +1559,8 @@
   DocumentLifecycle::AllowThrottlingScope throttling_scope(
       MainFrameImpl()->GetFrame()->GetDocument()->Lifecycle());
 
-  PageWidgetDelegate::UpdateLifecycle(*page_, *MainFrameImpl()->GetFrame(),
-                                      requested_update, reason);
+  PageWidgetDelegate::UpdateLifecycle(
+      *AsView().page, *MainFrameImpl()->GetFrame(), requested_update, reason);
   if (requested_update == LifecycleUpdate::kLayout)
     return;
 
@@ -1607,7 +1613,7 @@
   // WebView, and it is painting into the recording of its parent.
   DCHECK(!IsAcceleratedCompositingActive());
   PageWidgetDelegate::PaintContent(canvas, rect,
-                                   *page_->DeprecatedLocalMainFrame());
+                                   *AsView().page->DeprecatedLocalMainFrame());
 }
 
 void WebViewImpl::CompositeAndReadbackAsync(
@@ -1817,23 +1823,24 @@
 }
 
 void WebViewImpl::SetCursorVisibilityState(bool is_visible) {
-  if (page_)
-    page_->SetIsCursorVisible(is_visible);
+  if (AsView().page)
+    AsView().page->SetIsCursorVisible(is_visible);
 }
 
 void WebViewImpl::MouseCaptureLost() {
   TRACE_EVENT_ASYNC_END0("input", "capturing mouse", this);
   mouse_capture_node_ = nullptr;
-  if (page_->DeprecatedLocalMainFrame())
-    page_->DeprecatedLocalMainFrame()->Client()->SetMouseCapture(false);
+  if (AsView().page->DeprecatedLocalMainFrame())
+    AsView().page->DeprecatedLocalMainFrame()->Client()->SetMouseCapture(false);
 }
 
 void WebViewImpl::SetFocus(bool enable) {
   if (enable)
-    page_->GetFocusController().SetActive(true);
-  page_->GetFocusController().SetFocused(enable);
+    AsView().page->GetFocusController().SetActive(true);
+  AsView().page->GetFocusController().SetFocused(enable);
   if (enable) {
-    LocalFrame* focused_frame = page_->GetFocusController().FocusedFrame();
+    LocalFrame* focused_frame =
+        AsView().page->GetFocusController().FocusedFrame();
     if (focused_frame) {
       Element* element = focused_frame->GetDocument()->FocusedElement();
       if (element && focused_frame->Selection()
@@ -1861,12 +1868,13 @@
     CancelPagePopup();
 
     // Clear focus on the currently focused frame if any.
-    if (!page_)
+    if (!AsView().page)
       return;
 
-    LocalFrame* frame = page_->MainFrame() && page_->MainFrame()->IsLocalFrame()
-                            ? page_->DeprecatedLocalMainFrame()
-                            : nullptr;
+    LocalFrame* frame =
+        AsView().page->MainFrame() && AsView().page->MainFrame()->IsLocalFrame()
+            ? ToLocalFrame(AsView().page->MainFrame())
+            : nullptr;
     if (!frame)
       return;
 
@@ -1954,7 +1962,7 @@
 WebSettingsImpl* WebViewImpl::SettingsImpl() {
   if (!web_settings_) {
     web_settings_ = std::make_unique<WebSettingsImpl>(
-        &page_->GetSettings(), dev_tools_emulator_.Get());
+        &AsView().page->GetSettings(), dev_tools_emulator_.Get());
   }
   DCHECK(web_settings_);
   return web_settings_.get();
@@ -1965,21 +1973,24 @@
 }
 
 WebString WebViewImpl::PageEncoding() const {
-  if (!page_)
+  if (!AsView().page)
     return WebString();
 
-  if (!page_->MainFrame()->IsLocalFrame())
+  if (!AsView().page->MainFrame()->IsLocalFrame())
     return WebString();
 
+  LocalFrame* main_frame = ToLocalFrame(AsView().page->MainFrame());
+
   // FIXME: Is this check needed?
-  if (!page_->DeprecatedLocalMainFrame()->GetDocument()->Loader())
+  if (!main_frame->GetDocument()->Loader())
     return WebString();
 
-  return page_->DeprecatedLocalMainFrame()->GetDocument()->EncodingName();
+  return main_frame->GetDocument()->EncodingName();
 }
 
 WebFrame* WebViewImpl::MainFrame() {
-  return WebFrame::FromFrame(page_ ? page_->MainFrame() : nullptr);
+  Page* page = AsView().page.Get();
+  return WebFrame::FromFrame(page ? page->MainFrame() : nullptr);
 }
 
 WebLocalFrame* WebViewImpl::FocusedFrame() {
@@ -2014,7 +2025,7 @@
 }
 
 void WebViewImpl::SetInitialFocus(bool reverse) {
-  if (!page_)
+  if (!AsView().page)
     return;
   Frame* frame = GetPage()->GetFocusController().FocusedOrMainFrame();
   if (frame->IsLocalFrame()) {
@@ -2294,16 +2305,16 @@
     if (compositor_device_scale_factor_override_) {
       // Adjust the page's DSF so that DevicePixelRatio becomes
       // m_zoomFactorForDeviceScaleFactor.
-      GetPage()->SetDeviceScaleFactorDeprecated(
+      AsView().page->SetDeviceScaleFactorDeprecated(
           zoom_factor_for_device_scale_factor_ /
           compositor_device_scale_factor_override_);
       zoom_factor *= compositor_device_scale_factor_override_;
     } else {
-      GetPage()->SetDeviceScaleFactorDeprecated(1.f);
+      AsView().page->SetDeviceScaleFactorDeprecated(1.f);
       zoom_factor *= zoom_factor_for_device_scale_factor_;
     }
   }
-  PropagateZoomFactorToLocalFrameRoots(page_->MainFrame(), zoom_factor);
+  PropagateZoomFactorToLocalFrameRoots(AsView().page->MainFrame(), zoom_factor);
 
   return zoom_level_;
 }
@@ -2612,9 +2623,9 @@
 }
 
 WebSize WebViewImpl::ContentsPreferredMinimumSize() {
-  Document* document = page_->MainFrame()->IsLocalFrame()
-                           ? page_->DeprecatedLocalMainFrame()->GetDocument()
-                           : nullptr;
+  if (!AsView().page->MainFrame()->IsLocalFrame())
+    return WebSize();
+  Document* document = ToLocalFrame(AsView().page->MainFrame())->GetDocument();
   if (!document || !document->GetLayoutView() || !document->documentElement() ||
       !document->documentElement()->GetLayoutBox())
     return WebSize();
@@ -2803,8 +2814,10 @@
 }
 
 void WebViewImpl::PerformCustomContextMenuAction(unsigned action) {
-  if (page_)
-    page_->GetContextMenuController().CustomContextMenuItemSelected(action);
+  if (AsView().page) {
+    AsView().page->GetContextMenuController().CustomContextMenuItemSelected(
+        action);
+  }
 }
 
 void WebViewImpl::ShowContextMenu(WebMenuSourceType source_type) {
@@ -2824,7 +2837,7 @@
 }
 
 void WebViewImpl::DidCloseContextMenu() {
-  LocalFrame* frame = page_->GetFocusController().FocusedFrame();
+  LocalFrame* frame = AsView().page->GetFocusController().FocusedFrame();
   if (frame)
     frame->Selection().SetCaretBlinkingSuspended(false);
 }
@@ -2839,16 +2852,13 @@
 SkColor WebViewImpl::BackgroundColor() const {
   if (background_color_override_enabled_)
     return background_color_override_;
-  if (!page_)
-    return BaseBackgroundColor().Rgb();
-  if (!page_->MainFrame())
-    return BaseBackgroundColor().Rgb();
-  if (!page_->MainFrame()->IsLocalFrame())
-    return BaseBackgroundColor().Rgb();
-  LocalFrameView* view = page_->DeprecatedLocalMainFrame()->View();
-  if (!view)
-    return BaseBackgroundColor().Rgb();
-  return view->DocumentBackgroundColor().Rgb();
+  Page* page = AsView().page.Get();
+  if (page && page->MainFrame() && page->MainFrame()->IsLocalFrame()) {
+    LocalFrameView* view = ToLocalFrame(page->MainFrame())->View();
+    if (view)
+      return view->DocumentBackgroundColor().Rgb();
+  }
+  return BaseBackgroundColor().Rgb();
 }
 
 Color WebViewImpl::BaseBackgroundColor() const {
@@ -2902,8 +2912,9 @@
 
 void WebViewImpl::UpdateBaseBackgroundColor() {
   Color color = BaseBackgroundColor();
-  if (page_->MainFrame() && page_->MainFrame()->IsLocalFrame()) {
-    LocalFrameView* view = page_->DeprecatedLocalMainFrame()->View();
+  if (AsView().page->MainFrame() &&
+      AsView().page->MainFrame()->IsLocalFrame()) {
+    LocalFrameView* view = ToLocalFrame(AsView().page->MainFrame())->View();
     view->SetBaseBackgroundColor(color);
     view->UpdateBaseBackgroundColorRecursively(color);
   }
@@ -2925,11 +2936,11 @@
 }
 
 void WebViewImpl::SetWindowFeatures(const WebWindowFeatures& features) {
-  page_->SetWindowFeatures(features);
+  AsView().page->SetWindowFeatures(features);
 }
 
 void WebViewImpl::SetOpenedByDOM() {
-  page_->SetOpenedByDOM();
+  AsView().page->SetOpenedByDOM();
 }
 
 void WebViewImpl::SetSelectionColors(unsigned active_background_color,
@@ -3040,9 +3051,9 @@
 }
 
 void WebViewImpl::SetMainFrameOverlayColor(SkColor color) {
-  DCHECK(page_->MainFrame());
-  if (page_->MainFrame()->IsLocalFrame())
-    ToLocalFrame(page_->MainFrame())->SetMainFrameColorOverlay(color);
+  DCHECK(AsView().page->MainFrame());
+  if (AsView().page->MainFrame()->IsLocalFrame())
+    ToLocalFrame(AsView().page->MainFrame())->SetMainFrameColorOverlay(color);
 }
 
 WebPageImportanceSignals* WebViewImpl::PageImportanceSignals() {
@@ -3050,7 +3061,7 @@
 }
 
 Element* WebViewImpl::FocusedElement() const {
-  LocalFrame* frame = page_->GetFocusController().FocusedFrame();
+  LocalFrame* frame = AsView().page->GetFocusController().FocusedFrame();
   if (!frame)
     return nullptr;
 
@@ -3063,16 +3074,13 @@
 
 HitTestResult WebViewImpl::HitTestResultForRootFramePos(
     const LayoutPoint& pos_in_root_frame) {
-  if (!page_->MainFrame()->IsLocalFrame())
+  if (!AsView().page->MainFrame()->IsLocalFrame())
     return HitTestResult();
+  LocalFrame* main_frame = ToLocalFrame(AsView().page->MainFrame());
   HitTestLocation location(
-      page_->DeprecatedLocalMainFrame()->View()->ConvertFromRootFrame(
-          pos_in_root_frame));
-  HitTestResult result =
-      page_->DeprecatedLocalMainFrame()
-          ->GetEventHandler()
-          .HitTestResultAtLocation(
-              location, HitTestRequest::kReadOnly | HitTestRequest::kActive);
+      main_frame->View()->ConvertFromRootFrame(pos_in_root_frame));
+  HitTestResult result = main_frame->GetEventHandler().HitTestResultAtLocation(
+      location, HitTestRequest::kReadOnly | HitTestRequest::kActive);
   result.SetToShadowHostIfInRestrictedShadowRoot();
   return result;
 }
@@ -3080,7 +3088,7 @@
 WebHitTestResult WebViewImpl::HitTestResultForTap(
     const gfx::Point& tap_point_window_pos,
     const WebSize& tap_area) {
-  if (!page_->MainFrame()->IsLocalFrame())
+  if (!AsView().page->MainFrame()->IsLocalFrame())
     return HitTestResult();
 
   WebGestureEvent tap_event(
@@ -3095,9 +3103,9 @@
   WebGestureEvent scaled_event =
       TransformWebGestureEvent(MainFrameImpl()->GetFrameView(), tap_event);
 
+  LocalFrame* main_frame = ToLocalFrame(AsView().page->MainFrame());
   HitTestResult result =
-      page_->DeprecatedLocalMainFrame()
-          ->GetEventHandler()
+      main_frame->GetEventHandler()
           .HitTestResultForGestureEvent(
               scaled_event, HitTestRequest::kReadOnly | HitTestRequest::kActive)
           .GetHitTestResult();
@@ -3236,7 +3244,7 @@
         layer_tree_view_->CompositorAnimationHost());
   }
 
-  page_->LayerTreeViewInitialized(*layer_tree_view_, nullptr);
+  AsView().page->LayerTreeViewInitialized(*layer_tree_view_, nullptr);
   // We don't yet have a page loaded at this point of the initialization of
   // WebViewImpl, so don't allow cc to commit any frames Blink might
   // try to create in the meantime.
@@ -3382,15 +3390,15 @@
 }
 
 void WebViewImpl::AddAutoplayFlags(int32_t value) {
-  page_->AddAutoplayFlags(value);
+  AsView().page->AddAutoplayFlags(value);
 }
 
 void WebViewImpl::ClearAutoplayFlags() {
-  page_->ClearAutoplayFlags();
+  AsView().page->ClearAutoplayFlags();
 }
 
 int32_t WebViewImpl::AutoplayFlagsForTest() {
-  return page_->AutoplayFlags();
+  return AsView().page->AutoplayFlags();
 }
 
 void WebViewImpl::DeferMainFrameUpdateForTesting() {
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.h b/third_party/blink/renderer/core/exported/web_view_impl.h
index b6ba2a2..cd9421f 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.h
+++ b/third_party/blink/renderer/core/exported/web_view_impl.h
@@ -236,7 +236,7 @@
 
   // Returns the page object associated with this view. This may be null when
   // the page is shutting down, but will be valid at all other times.
-  Page* GetPage() const { return page_.Get(); }
+  Page* GetPage() const { return AsView().page.Get(); }
 
   WebDevToolsAgentImpl* MainFrameDevToolsAgentImpl();
 
@@ -555,6 +555,7 @@
 
     // Can be null (e.g. unittests, shared workers, etc.)
     WebViewClient* client;
+    Persistent<Page> page;
   } as_view_;
 
   // These member variables should not be accessed within calls to WebView
@@ -576,8 +577,6 @@
   // The upper bound on the size when auto-resizing.
   IntSize max_auto_size_;
 
-  Persistent<Page> page_;
-
   // An object that can be used to manipulate m_page->settings() without linking
   // against WebCore. This is lazily allocated the first time GetWebSettings()
   // is called.
diff --git a/third_party/blink/renderer/core/html/canvas/image_data.cc b/third_party/blink/renderer/core/html/canvas/image_data.cc
index d39416e..c7fb8027 100644
--- a/third_party/blink/renderer/core/html/canvas/image_data.cc
+++ b/third_party/blink/renderer/core/html/canvas/image_data.cc
@@ -355,9 +355,14 @@
     return image_data;
   }
 
+  base::CheckedNumeric<uint32_t> area = image->Size().Area();
+  area *= 4;
+
+  if (!area.IsValid())
+    return nullptr;
   // Create image data with f32 storage
-  DOMFloat32Array* f32_array = ImageData::AllocateAndValidateFloat32Array(
-      image->Size().Area() * 4, nullptr);
+  DOMFloat32Array* f32_array =
+      ImageData::AllocateAndValidateFloat32Array(area.ValueOrDie(), nullptr);
   if (!f32_array)
     return nullptr;
   image_info = image_info.makeColorType(kRGBA_F32_SkColorType);
@@ -823,10 +828,13 @@
     return data_transform_successful;
   }
 
+  base::CheckedNumeric<uint32_t> area = size_.Area();
+  if (!area.IsValid())
+    return false;
   bool data_transform_successful =
       skcms_Transform(src_data, src_pixel_format, src_alpha_format,
                       src_profile_ptr, converted_pixels, dst_pixel_format,
-                      dst_alpha_format, dst_profile_ptr, size_.Area());
+                      dst_alpha_format, dst_profile_ptr, area.ValueOrDie());
   return data_transform_successful;
 }
 
diff --git a/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc b/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc
index a24a466..9599733 100644
--- a/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc
+++ b/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc
@@ -707,8 +707,9 @@
   }
 
   // Copy / color convert the pixels
-  scoped_refptr<ArrayBuffer> pixels_buffer = ArrayBuffer::CreateOrNull(
-      src_rect.Size().Area(), parsed_options.color_params.BytesPerPixel());
+  scoped_refptr<ArrayBuffer> pixels_buffer =
+      ArrayBuffer::CreateOrNull(SafeCast<uint32_t>(src_rect.Size().Area()),
+                                parsed_options.color_params.BytesPerPixel());
   if (!pixels_buffer)
     return;
   unsigned byte_length = pixels_buffer->ByteLength();
diff --git a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
index cbeae23..47db6d2 100644
--- a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
@@ -971,7 +971,7 @@
 void InspectorNetworkAgent::DidReceiveData(unsigned long identifier,
                                            DocumentLoader* loader,
                                            const char* data,
-                                           size_t data_length) {
+                                           uint64_t data_length) {
   String request_id = IdentifiersFactory::RequestId(loader, identifier);
 
   if (data) {
@@ -986,7 +986,7 @@
   }
 
   GetFrontend()->dataReceived(
-      request_id, CurrentTimeTicksInSeconds(), data_length,
+      request_id, CurrentTimeTicksInSeconds(), static_cast<int>(data_length),
       static_cast<int>(
           resources_data_->GetAndClearPendingEncodedDataLength(request_id)));
 }
diff --git a/third_party/blink/renderer/core/inspector/inspector_network_agent.h b/third_party/blink/renderer/core/inspector/inspector_network_agent.h
index e1cdcc16..e37e634 100644
--- a/third_party/blink/renderer/core/inspector/inspector_network_agent.h
+++ b/third_party/blink/renderer/core/inspector/inspector_network_agent.h
@@ -109,7 +109,7 @@
   void DidReceiveData(unsigned long identifier,
                       DocumentLoader*,
                       const char* data,
-                      size_t data_length);
+                      uint64_t data_length);
   void DidReceiveBlob(unsigned long identifier,
                       DocumentLoader*,
                       scoped_refptr<BlobDataHandle>);
diff --git a/third_party/blink/renderer/core/inspector/inspector_trace_events.cc b/third_party/blink/renderer/core/inspector/inspector_trace_events.cc
index ec37fc3b..0069c74c 100644
--- a/third_party/blink/renderer/core/inspector/inspector_trace_events.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_trace_events.cc
@@ -131,7 +131,7 @@
 void InspectorTraceEvents::DidReceiveData(unsigned long identifier,
                                           DocumentLoader* loader,
                                           const char* data,
-                                          int encoded_data_length) {
+                                          uint64_t encoded_data_length) {
   LocalFrame* frame = loader ? loader->GetFrame() : nullptr;
   TRACE_EVENT_INSTANT1("devtools.timeline", "ResourceReceivedData",
                        TRACE_EVENT_SCOPE_THREAD, "data",
@@ -820,13 +820,13 @@
     DocumentLoader* loader,
     unsigned long identifier,
     LocalFrame* frame,
-    int encoded_data_length) {
+    uint64_t encoded_data_length) {
   String request_id = IdentifiersFactory::RequestId(loader, identifier);
 
   std::unique_ptr<TracedValue> value = TracedValue::Create();
   value->SetString("requestId", request_id);
   value->SetString("frame", IdentifiersFactory::FrameId(frame));
-  value->SetInteger("encodedDataLength", encoded_data_length);
+  value->SetDouble("encodedDataLength", encoded_data_length);
   return value;
 }
 
diff --git a/third_party/blink/renderer/core/inspector/inspector_trace_events.h b/third_party/blink/renderer/core/inspector/inspector_trace_events.h
index b52199f..92a8ae8 100644
--- a/third_party/blink/renderer/core/inspector/inspector_trace_events.h
+++ b/third_party/blink/renderer/core/inspector/inspector_trace_events.h
@@ -96,7 +96,7 @@
   void DidReceiveData(unsigned long identifier,
                       DocumentLoader*,
                       const char* data,
-                      int data_length);
+                      uint64_t data_length);
   void DidFinishLoading(unsigned long identifier,
                         DocumentLoader*,
                         TimeTicks monotonic_finish_time,
@@ -286,7 +286,7 @@
 std::unique_ptr<TracedValue> Data(DocumentLoader*,
                                   unsigned long identifier,
                                   LocalFrame*,
-                                  int encoded_data_length);
+                                  uint64_t encoded_data_length);
 }
 
 namespace inspector_resource_finish_event {
diff --git a/third_party/blink/renderer/core/inspector/network_resources_data.cc b/third_party/blink/renderer/core/inspector/network_resources_data.cc
index 87485fc..838eae7 100644
--- a/third_party/blink/renderer/core/inspector/network_resources_data.cc
+++ b/third_party/blink/renderer/core/inspector/network_resources_data.cc
@@ -298,10 +298,10 @@
 
 void NetworkResourcesData::MaybeAddResourceData(const String& request_id,
                                                 const char* data,
-                                                size_t data_length) {
+                                                uint64_t data_length) {
   if (ResourceData* resource_data =
           PrepareToAddResourceData(request_id, data_length)) {
-    resource_data->AppendData(data, data_length);
+    resource_data->AppendData(data, SafeCast<size_t>(data_length));
   }
 }
 
diff --git a/third_party/blink/renderer/core/inspector/network_resources_data.h b/third_party/blink/renderer/core/inspector/network_resources_data.h
index eda26619..3ae0ffe0 100644
--- a/third_party/blink/renderer/core/inspector/network_resources_data.h
+++ b/third_party/blink/renderer/core/inspector/network_resources_data.h
@@ -229,7 +229,7 @@
                           bool base64_encoded = false);
   void MaybeAddResourceData(const String& request_id,
                             const char* data,
-                            size_t data_length);
+                            uint64_t data_length);
   void MaybeDecodeDataToContent(const String& request_id);
   void AddResource(const String& request_id, Resource*);
   ResourceData const* Data(const String& request_id);
diff --git a/third_party/blink/renderer/core/layout/layout_frame_set.cc b/third_party/blink/renderer/core/layout/layout_frame_set.cc
index 3c5b5402..b43680c 100644
--- a/third_party/blink/renderer/core/layout/layout_frame_set.cc
+++ b/third_party/blink/renderer/core/layout/layout_frame_set.cc
@@ -138,7 +138,7 @@
       if (grid[i].IsAbsolute()) {
         long long temp_product =
             static_cast<long long>(grid_layout[i]) * remaining_fixed;
-        grid_layout[i] = temp_product / total_fixed;
+        grid_layout[i] = static_cast<int>(temp_product / total_fixed);
         remaining_len -= grid_layout[i];
       }
     }
@@ -158,7 +158,7 @@
       if (grid[i].IsPercentage()) {
         long long temp_product =
             static_cast<long long>(grid_layout[i]) * remaining_percent;
-        grid_layout[i] = temp_product / total_percent;
+        grid_layout[i] = static_cast<int>(temp_product / total_percent);
         remaining_len -= grid_layout[i];
       }
     }
@@ -208,7 +208,7 @@
         if (grid[i].IsPercentage()) {
           long long temp_product =
               static_cast<long long>(grid_layout[i]) * remaining_percent;
-          change_percent = temp_product / total_percent;
+          change_percent = static_cast<int>(temp_product / total_percent);
           grid_layout[i] += change_percent;
           remaining_len -= change_percent;
         }
@@ -224,7 +224,7 @@
         if (grid[i].IsAbsolute()) {
           long long temp_product =
               static_cast<long long>(grid_layout[i]) * remaining_fixed;
-          change_fixed = temp_product / total_fixed;
+          change_fixed = static_cast<int>(temp_product / total_fixed);
           grid_layout[i] += change_fixed;
           remaining_len -= change_fixed;
         }
diff --git a/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc b/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc
index 5eaf546..3c1515378 100644
--- a/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc
+++ b/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc
@@ -486,10 +486,14 @@
   // (-2, 3, 140, 100) is first clipped by container's overflow clip, to
   // (40, 10, 50, 80), then is added by container's offset in LayoutView
   // (222, 111).
-  // TODO(crbug.com/600039): rect.X() should be 262 (left + border-left), but is
-  // offset by extra horizontal border-widths because of layout error.
-  CheckPaintInvalidationVisualRect(*target, GetLayoutView(),
-                                   LayoutRect(322, 121, 50, 80));
+
+  LayoutRect expectation(262, 121, 50, 80);
+  if (!RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    // TODO(crbug.com/600039): rect.X() should be 262 (left + border-left), but
+    // is offset by extra horizontal border-widths because of layout error.
+    expectation = LayoutRect(322, 121, 50, 80);
+  }
+  CheckPaintInvalidationVisualRect(*target, GetLayoutView(), expectation);
 
   LayoutRect container_local_visual_rect = container->LocalVisualRect();
   // Because container has overflow clip, its visual overflow doesn't include
@@ -503,11 +507,13 @@
   EXPECT_TRUE(container->MapToVisualRectInAncestorSpace(container, rect));
   EXPECT_EQ(LayoutRect(0, 0, 110, 120), rect);
 
-  // TODO(crbug.com/600039): rect.x() should be 222 (left), but is offset by
-  // extra horizontal
-  // border-widths because of layout error.
-  CheckPaintInvalidationVisualRect(*container, GetLayoutView(),
-                                   LayoutRect(282, 111, 110, 120));
+  expectation = LayoutRect(222, 111, 110, 120);
+  if (!RuntimeEnabledFeatures::LayoutNGEnabled()) {
+    // TODO(crbug.com/600039): rect.x() should be 222 (left), but is offset by
+    // extra horizontal border-widths because of layout error.
+    expectation = LayoutRect(282, 111, 110, 120);
+  }
+  CheckPaintInvalidationVisualRect(*container, GetLayoutView(), expectation);
 }
 
 TEST_P(VisualRectMappingTest, ContainerOverflowHidden) {
diff --git a/third_party/blink/renderer/core/loader/progress_tracker.cc b/third_party/blink/renderer/core/loader/progress_tracker.cc
index 1e0088c4..245a64bd 100644
--- a/third_party/blink/renderer/core/loader/progress_tracker.cc
+++ b/third_party/blink/renderer/core/loader/progress_tracker.cc
@@ -166,7 +166,7 @@
 }
 
 void ProgressTracker::IncrementProgress(unsigned long identifier,
-                                        size_t length) {
+                                        uint64_t length) {
   ProgressItem* item = progress_items_.at(identifier);
   if (!item)
     return;
diff --git a/third_party/blink/renderer/core/loader/progress_tracker.h b/third_party/blink/renderer/core/loader/progress_tracker.h
index 4ff4e18..55a339c 100644
--- a/third_party/blink/renderer/core/loader/progress_tracker.h
+++ b/third_party/blink/renderer/core/loader/progress_tracker.h
@@ -67,7 +67,7 @@
 
   void WillStartLoading(unsigned long identifier, ResourceLoadPriority);
   void IncrementProgress(unsigned long identifier, const ResourceResponse&);
-  void IncrementProgress(unsigned long identifier, size_t);
+  void IncrementProgress(unsigned long identifier, uint64_t);
   void CompleteProgress(unsigned long identifier);
 
  private:
diff --git a/third_party/blink/renderer/core/script/layered_api.cc b/third_party/blink/renderer/core/script/layered_api.cc
index 7b406f0..434f7b75 100644
--- a/third_party/blink/renderer/core/script/layered_api.cc
+++ b/third_party/blink/renderer/core/script/layered_api.cc
@@ -28,6 +28,8 @@
 
     {"async-local-storage/index.js",
      IDR_LAYERED_API_ASYNC_LOCAL_STORAGE_INDEX_JS},
+    {"async-local-storage/idb_utils.js",
+     IDR_LAYERED_API_ASYNC_LOCAL_STORAGE_IDB_UTILS_JS},
 
     {"virtual-scroller/index.js", IDR_LAYERED_API_VIRTUAL_SCROLLER_INDEX_JS},
     {"virtual-scroller/item-source.js",
diff --git a/third_party/blink/renderer/core/script/resources/layered_api/async-local-storage/.eslintrc.js b/third_party/blink/renderer/core/script/resources/layered_api/async-local-storage/.eslintrc.js
new file mode 100644
index 0000000..3b99401
--- /dev/null
+++ b/third_party/blink/renderer/core/script/resources/layered_api/async-local-storage/.eslintrc.js
@@ -0,0 +1,346 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module.exports = {
+  root: true,
+  env: {
+    es6: true,
+    browser: true
+  },
+  parserOptions: {
+    sourceType: 'module',
+    ecmaVersion: 2019
+  },
+  rules: {
+    'for-direction': 'error',
+    'getter-return': 'error',
+    'no-async-promise-executor': 'error',
+    'no-await-in-loop': 'error',
+    'no-compare-neg-zero': 'error',
+    'no-cond-assign': ['error', 'except-parens'],
+    'no-console': 'error',
+    'no-constant-condition': ['error', {checkLoops: false}],
+    'no-control-regex': 'error',
+    'no-debugger': 'error',
+    'no-dupe-args': 'error',
+    'no-dupe-keys': 'error',
+    'no-duplicate-case': 'error',
+    'no-empty': 'error',
+    'no-empty-character-class': 'error',
+    'no-ex-assign': 'error',
+    'no-extra-boolean-cast': 'error',
+    'no-extra-parens': [
+      'error',
+      'all',
+      {
+        conditionalAssign: false,
+        nestedBinaryExpressions: false,
+        returnAssign: false
+      }
+    ],
+    'no-extra-semi': 'error',
+    'no-func-assign': 'error',
+    'no-inner-declarations': 'off',
+    'no-invalid-regexp': 'error',
+    'no-irregular-whitespace': 'error',
+    'no-misleading-character-class': 'error',
+    'no-obj-calls': 'error',
+    'no-prototype-builtins': 'error',
+    'no-regex-spaces': 'error',
+    'no-sparse-arrays': 'error',
+    'no-template-curly-in-string': 'error',
+    'no-unexpected-multiline': 'error',
+    'no-unreachable': 'error',
+    'no-unsafe-finally': 'off',
+    'no-unsafe-negation': 'error',
+    'use-isnan': 'error',
+    'valid-typeof': 'error',
+    'accessor-pairs': 'error',
+    'array-callback-return': 'error',
+    'block-scoped-var': 'off',
+    'class-methods-use-this': 'off',
+    'complexity': 'off',
+    'consistent-return': 'error',
+    'curly': ['error', 'all'],
+    'default-case': 'off',
+    'dot-location': ['error', 'property'],
+    'dot-notation': 'error',
+    'eqeqeq': 'error',
+    'guard-for-in': 'off',
+    'no-alert': 'error',
+    'no-caller': 'error',
+    'no-case-declarations': 'error',
+    'no-div-regex': 'off',
+    'no-else-return': 'error',
+    'no-empty-function': 'off',
+    'no-empty-pattern': 'error',
+    'no-eq-null': 'error',
+    'no-eval': 'error',
+    'no-extend-native': 'error',
+    'no-extra-bind': 'error',
+    'no-extra-label': 'error',
+    'no-fallthrough': 'error',
+    'no-floating-decimal': 'error',
+    'no-global-assign': 'error',
+    'no-implicit-coercion': 'error',
+    'no-implicit-globals': 'error',
+    'no-implied-eval': 'error',
+    'no-invalid-this': 'error',
+    'no-iterator': 'error',
+    'no-labels': ['error', {allowLoop: true}],
+    'no-lone-blocks': 'error',
+    'no-loop-func': 'error',
+    'no-magic-numbers': ['error', {ignore: [0, 1]}],
+    'no-multi-spaces': 'error',
+    'no-multi-str': 'error',
+    'no-new': 'error',
+    'no-new-func': 'error',
+    'no-new-wrappers': 'error',
+    'no-octal': 'error',
+    'no-octal-escape': 'error',
+    'no-param-reassign': 'off',
+    'no-process-env': 'error',
+    'no-proto': 'error',
+    'no-redeclare': 'error',
+    'no-restricted-properties': 'off',
+    'no-return-assign': ['error', 'except-parens'],
+    'no-return-await': 'error',
+    'no-script-url': 'off',
+    'no-self-assign': 'error',
+    'no-self-compare': 'error',
+    'no-sequences': 'error',
+    'no-throw-literal': 'error',
+    'no-unmodified-loop-condition': 'error',
+    'no-unused-expressions': 'error',
+    'no-unused-labels': 'error',
+    'no-useless-call': 'error',
+    'no-useless-concat': 'error',
+    'no-useless-escape': 'error',
+    'no-useless-return': 'error',
+    'no-void': 'error',
+    'no-warning-comments': 'off',
+    'no-with': 'error',
+    'prefer-promise-reject-errors': 'error',
+    'radix': ['error', 'as-needed'],
+    'require-await': 'off',
+    'vars-on-top': 'off',
+    'wrap-iife': ['error', 'outside'],
+    'yoda': ['error', 'never'],
+    'strict': ['error', 'global'],
+    'init-declarations': 'off',
+    'no-delete-var': 'error',
+    'no-label-var': 'error',
+    'no-restricted-globals': 'off',
+    'no-shadow': 'error',
+    'no-shadow-restricted-names': 'error',
+    'no-undef': 'error',
+    'no-undef-init': 'error',
+    'no-undefined': 'off',
+    'no-unused-vars': 'error',
+    'no-use-before-define': ['error', 'nofunc'],
+    'callback-return': 'off',
+    'global-require': 'error',
+    'handle-callback-err': 'error',
+    'no-buffer-constructor': 'error',
+    'no-mixed-requires': ['error', true],
+    'no-new-require': 'error',
+    'no-path-concat': 'error',
+    'no-process-exit': 'error',
+    'no-restricted-modules': 'off',
+    'no-sync': 'off',
+    'array-bracket-newline': ['error', {multiline: true}],
+    'array-bracket-spacing': ['error', 'never'],
+    'array-element-newline': 'off',
+    'block-spacing': ['error', 'always'],
+    'brace-style': [
+      'error',
+      '1tbs',
+      {allowSingleLine: false}
+    ],
+    camelcase: ['error', {properties: 'always'}],
+    'capitalized-comments': 'off',
+    'comma-dangle': ['error', 'always-multiline'],
+    'comma-spacing': [
+      'error',
+      {
+        before: false,
+        after: true
+      }
+    ],
+    'comma-style': ['error', 'last'],
+    'computed-property-spacing': ['error', 'never'],
+    'consistent-this': 'off',
+    'eol-last': 'error',
+    'func-call-spacing': ['error', 'never'],
+    'func-name-matching': 'error',
+    'func-names': 'off',
+    'func-style': ['error', 'declaration'],
+    'function-paren-newline': 'off',
+    'id-blacklist': 'off',
+    'id-length': 'off',
+    'id-match': 'off',
+    indent: [
+      'error',
+      2,
+      {
+        SwitchCase: 1,
+        CallExpression: {arguments: 2},
+        FunctionExpression: {parameters: 'first'},
+        ignoredNodes: ['ConditionalExpression']
+      }
+    ],
+    'jsx-quotes': 'off',
+    'key-spacing': [
+      'error',
+      {
+        beforeColon: false,
+        afterColon: true,
+        mode: 'strict'
+      }
+    ],
+    'keyword-spacing': [
+      'error',
+      {
+        before: true,
+        after: true
+      }
+    ],
+    'line-comment-position': 'off',
+    'linebreak-style': ['error', 'unix'],
+    'lines-around-comment': 'off',
+    'max-depth': 'off',
+    'max-len': 'off',
+    'max-lines': 'off',
+    'max-nested-callbacks': 'off',
+    'max-params': 'off',
+    'max-statements': 'off',
+    'max-statements-per-line': ['error', {max: 1}],
+    'multiline-ternary': ['error', 'always-multiline'],
+    'new-cap': 'error',
+    'new-parens': 'error',
+    'newline-per-chained-call': 'off',
+    'no-array-constructor': 'error',
+    'no-bitwise': 'off',
+    'no-continue': 'off',
+    'no-inline-comments': 'off',
+    'no-lonely-if': 'error',
+    'no-mixed-operators': [
+      'error',
+      {
+        groups: [
+          ['&', '|', '^', '~', '<<', '>>', '>>>'],
+          ['==', '!=', '===', '!==', '>', '>=', '<', '<='],
+          ['&&', '||'],
+          ['in', 'instanceof']
+        ]
+      }
+    ],
+    'no-mixed-spaces-and-tabs': 'error',
+    'no-multi-assign': 'off',
+    'no-multiple-empty-lines': 'error',
+    'no-negated-condition': 'off',
+    'no-nested-ternary': 'error',
+    'no-new-object': 'error',
+    'no-plusplus': 'off',
+    'no-restricted-syntax': 'off',
+    'no-tabs': 'error',
+    'no-ternary': 'off',
+    'no-trailing-spaces': 'error',
+    'no-underscore-dangle': 'off',
+    'no-unneeded-ternary': 'error',
+    'no-whitespace-before-property': 'error',
+    'nonblock-statement-body-position': 'error',
+    'object-curly-newline': ['error', {consistent: true}],
+    'object-curly-spacing': ['error', 'never'],
+    'object-property-newline': 'off',
+    'one-var': ['error', 'never'],
+    'one-var-declaration-per-line': ['error', 'initializations'],
+    'operator-assignment': ['error', 'always'],
+    'operator-linebreak': ['error', 'after'],
+    'padded-blocks': ['error', 'never'],
+    'padding-line-between-statements': 'off',
+    'quote-props': ['error', 'as-needed'],
+    quotes: [
+      'error',
+      'single',
+      {
+        avoidEscape: true,
+        allowTemplateLiterals: true
+      }
+    ],
+    semi: ['error', 'always'],
+    'semi-spacing': 'error',
+    'semi-style': 'error',
+    'sort-keys': 'off',
+    'sort-vars': 'off',
+    'space-before-blocks': ['error', 'always'],
+    'space-before-function-paren': [
+      'error',
+      {
+        anonymous: 'always',
+        named: 'never'
+      }
+    ],
+    'space-in-parens': ['error', 'never'],
+    'space-infix-ops': 'error',
+    'space-unary-ops': [
+      'error',
+      {
+        words: true,
+        nonwords: false
+      }
+    ],
+    'spaced-comment': ['error', 'always'],
+    'switch-colon-spacing': 'error',
+    'template-tag-spacing': 'error',
+    'unicode-bom': 'error',
+    'wrap-regex': 'off',
+    'arrow-body-style': 'off',
+    'arrow-parens': ['error', 'as-needed'],
+    'arrow-spacing': 'error',
+    'constructor-super': 'error',
+    'generator-star-spacing': ['error', 'after'],
+    'no-class-assign': 'error',
+    'no-confusing-arrow': 'off',
+    'no-const-assign': 'error',
+    'no-dupe-class-members': 'error',
+    'no-duplicate-imports': 'error',
+    'no-new-symbol': 'error',
+    'no-restricted-imports': 'off',
+    'no-this-before-super': 'error',
+    'no-useless-computed-key': 'error',
+    'no-useless-constructor': 'error',
+    'no-useless-rename': 'error',
+    'no-var': 'error',
+    'object-shorthand': 'error',
+    'prefer-arrow-callback': 'error',
+    'prefer-const': ['error', {ignoreReadBeforeAssign: true}],
+    'prefer-destructuring': [
+      'error',
+      {
+        VariableDeclarator: {
+          array: false,
+          object: true
+        },
+        AssignmentExpression: {
+          array: false,
+          object: false
+        }
+      },
+      {
+        enforceForRenamedProperties: false
+      }
+    ],
+    'prefer-numeric-literals': 'error',
+    'prefer-rest-params': 'error',
+    'prefer-spread': 'error',
+    'prefer-template': 'off',
+    'require-yield': 'error',
+    'rest-spread-spacing': 'error',
+    'sort-imports': 'off',
+    'symbol-description': 'error',
+    'template-curly-spacing': ['error', 'never'],
+    'yield-star-spacing': ['error', 'after']
+  }
+};
diff --git a/third_party/blink/renderer/core/script/resources/layered_api/async-local-storage/README.chromium b/third_party/blink/renderer/core/script/resources/layered_api/async-local-storage/README.chromium
deleted file mode 100644
index 4119a837..0000000
--- a/third_party/blink/renderer/core/script/resources/layered_api/async-local-storage/README.chromium
+++ /dev/null
@@ -1,12 +0,0 @@
-Name: async-local-storage Layered API
-URL: https://github.com/valdrinkoshi/virtual-list
-Version: 4bfe22c2d424e3451acfcf809585336f389f6397
-Security Critical: no
-
-Description:
-Temporarily, the files under this directory are authored by Chromium Authors
-on a github repository, and then imported to Chromium repository directly here,
-until a long-term Layered API development plan is settled.
-
-Local Modifications:
-None (except for renaming to index.js)
diff --git a/third_party/blink/renderer/core/script/resources/layered_api/async-local-storage/idb_utils.js b/third_party/blink/renderer/core/script/resources/layered_api/async-local-storage/idb_utils.js
new file mode 100644
index 0000000..13ae8af
--- /dev/null
+++ b/third_party/blink/renderer/core/script/resources/layered_api/async-local-storage/idb_utils.js
@@ -0,0 +1,69 @@
+// Copyright 2019 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.
+
+export function promiseForRequest(request) {
+  return new Promise((resolve, reject) => {
+    request.onsuccess = () => resolve(request.result);
+    request.onerror = () => reject(request.error);
+  });
+}
+
+export function promiseForTransaction(transaction) {
+  return new Promise((resolve, reject) => {
+    transaction.oncomplete = () => resolve();
+    transaction.onabort = () => reject(transaction.error);
+    transaction.onerror = () => reject(transaction.error);
+  });
+}
+
+export function throwForDisallowedKey(key) {
+  if (!isAllowedAsAKey(key)) {
+    throw new DOMException(
+        'The given value is not allowed as a key', 'DataError');
+  }
+}
+
+function isAllowedAsAKey(value) {
+  if (typeof value === 'number' || typeof value === 'string') {
+    return true;
+  }
+
+  if (Array.isArray(value)) {
+    return true;
+  }
+
+  if (isDate(value)) {
+    return true;
+  }
+
+  if (ArrayBuffer.isView(value)) {
+    return true;
+  }
+
+  if (isArrayBuffer(value)) {
+    return true;
+  }
+
+  return false;
+}
+
+function isDate(value) {
+  try {
+    Date.prototype.getTime.call(value);
+    return true;
+  } catch {
+    return false;
+  }
+}
+
+const byteLengthGetter =
+    Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, 'byteLength').get;
+function isArrayBuffer(value) {
+  try {
+    byteLengthGetter.call(value);
+    return true;
+  } catch {
+    return false;
+  }
+}
diff --git a/third_party/blink/renderer/core/script/resources/layered_api/async-local-storage/index.js b/third_party/blink/renderer/core/script/resources/layered_api/async-local-storage/index.js
index 7937f21..620c6d7 100644
--- a/third_party/blink/renderer/core/script/resources/layered_api/async-local-storage/index.js
+++ b/third_party/blink/renderer/core/script/resources/layered_api/async-local-storage/index.js
@@ -1,10 +1,27 @@
+// Copyright 2019 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 {promiseForRequest, throwForDisallowedKey, promiseForTransaction} from './idb_utils.js';
+
 // TODOs/spec-noncompliances:
 // - Susceptible to tampering of built-in prototypes and globals. We want to
 //   work on tooling to ameliorate that.
 
 // TODO: Use private fields when those ship.
-const databaseName = new WeakMap();
-const databasePromise = new WeakMap();
+// In the meantime we use this hard-to-understand, but effective, pattern:
+// http://2ality.com/2016/01/private-data-classes.html#keeping-private-data-in-weakmaps
+// Of note, the weak map entries will live only as long as the corresponding StorageArea instances.
+//
+// Cheatsheet:
+// x.#y      <--->  _y.get(x)
+// x.#y = z  <--->  _y.set(x, z)
+
+const _databaseName = new WeakMap();
+const _databasePromise = new WeakMap();
+
+const DEFAULT_STORAGE_AREA_NAME = 'default';
+const DEFAULT_IDB_STORE_NAME = 'store';
 
 if (!self.isSecureContext) {
   throw new DOMException(
@@ -14,8 +31,8 @@
 
 export class StorageArea {
   constructor(name) {
-    databasePromise.set(this, null);
-    databaseName.set(this, `async-local-storage:${name}`);
+    _databasePromise.set(this, null);
+    _databaseName.set(this, `async-local-storage:${name}`);
   }
 
   async set(key, value) {
@@ -28,11 +45,7 @@
         store.put(value, key);
       }
 
-      return new Promise((resolve, reject) => {
-        transaction.oncomplete = () => resolve();
-        transaction.onabort = () => reject(transaction.error);
-        transaction.onerror = () => reject(transaction.error);
-      });
+      return promiseForTransaction(transaction);
     });
   }
 
@@ -40,12 +53,7 @@
     throwForDisallowedKey(key);
 
     return performDatabaseOperation(this, 'readonly', (transaction, store) => {
-      const request = store.get(key);
-
-      return new Promise((resolve, reject) => {
-        request.onsuccess = () => resolve(request.result);
-        request.onerror = () => reject(request.error);
-      });
+      return promiseForRequest(store.get(key));
     });
   }
 
@@ -54,43 +62,34 @@
 
     return performDatabaseOperation(this, 'readwrite', (transaction, store) => {
       store.delete(key);
-
-      return new Promise((resolve, reject) => {
-        transaction.oncomplete = () => resolve();
-        transaction.onabort = () => reject(transaction.error);
-        transaction.onerror = () => reject(transaction.error);
-      });
+      return promiseForTransaction(transaction);
     });
   }
 
   async clear() {
-    if (!databasePromise.has(this)) {
-      return Promise.reject(new TypeError('Invalid this value'));
+    if (!_databasePromise.has(this)) {
+      throw new TypeError('Invalid this value');
     }
 
-    if (databasePromise.get(this) !== null) {
-      return databasePromise.get(this).then(
-          () => {
-            databasePromise.set(this, null);
-            return deleteDatabase(databaseName.get(this));
-          },
-          () => {
-            databasePromise.set(this, null);
-            return deleteDatabase(databaseName.get(this));
-          });
+    const databasePromise = _databasePromise.get(this);
+    if (databasePromise !== null) {
+      // Don't try to delete, and clear the promise, while we're opening the database; wait for that
+      // first.
+      try {
+        await databasePromise;
+      } catch {
+        // If the database failed to initialize, then that's fine, we'll still try to delete it.
+      }
+
+      _databasePromise.set(this, null);
     }
 
-    return deleteDatabase(databaseName.get(this));
+    return promiseForRequest(self.indexedDB.deleteDatabase(_databaseName.get(this)));
   }
 
   async keys() {
     return performDatabaseOperation(this, 'readonly', (transaction, store) => {
-      const request = store.getAllKeys(undefined);
-
-      return new Promise((resolve, reject) => {
-        request.onsuccess = () => resolve(request.result);
-        request.onerror = () => reject(request.error);
-      });
+      return promiseForRequest(store.getAllKeys(undefined));
     });
   }
 
@@ -122,108 +121,61 @@
   }
 
   get backingStore() {
-    if (!databasePromise.has(this)) {
+    if (!_databasePromise.has(this)) {
       throw new TypeError('Invalid this value');
     }
 
-    return {database: databaseName.get(this), store: 'store', version: 1};
+    return {
+      database: _databaseName.get(this),
+      store: DEFAULT_IDB_STORE_NAME,
+      version: 1,
+    };
   }
 }
 
-export const storage = new StorageArea('default');
+export const storage = new StorageArea(DEFAULT_STORAGE_AREA_NAME);
 
-function performDatabaseOperation(area, mode, steps) {
-  if (!databasePromise.has(area)) {
-    return Promise.reject(new TypeError('Invalid this value'));
+async function performDatabaseOperation(area, mode, steps) {
+  if (!_databasePromise.has(area)) {
+    throw new TypeError('Invalid this value');
   }
 
-  if (databasePromise.get(area) === null) {
+  if (_databasePromise.get(area) === null) {
     initializeDatabasePromise(area);
   }
 
-  return databasePromise.get(area).then(database => {
-    const transaction = database.transaction('store', mode);
-    const store = transaction.objectStore('store');
+  const database = await _databasePromise.get(area);
+  const transaction = database.transaction(DEFAULT_IDB_STORE_NAME, mode);
+  const store = transaction.objectStore(DEFAULT_IDB_STORE_NAME);
 
-    return steps(transaction, store);
-  });
+  return steps(transaction, store);
 }
 
 function initializeDatabasePromise(area) {
-  databasePromise.set(area, new Promise((resolve, reject) => {
-    const request = self.indexedDB.open(databaseName.get(area), 1);
+  _databasePromise.set(
+      area, new Promise((resolve, reject) => {
+        const request = self.indexedDB.open(_databaseName.get(area), 1);
 
-    request.onsuccess = () => {
-      const database = request.result;
-      database.onclose = () => databasePromise.set(area, null);
-      database.onversionchange = () => {
-        database.close();
-        databasePromise.set(area, null);
-      };
-      resolve(database);
-    };
+        request.onsuccess = () => {
+          const database = request.result;
+          database.onclose = () => _databasePromise.set(area, null);
+          database.onversionchange = () => {
+            database.close();
+            _databasePromise.set(area, null);
+          };
+          resolve(database);
+        };
 
-    request.onerror = () => reject(request.error);
+        request.onerror = () => reject(request.error);
 
-    request.onupgradeneeded = () => {
-      try {
-        request.result.createObjectStore('store');
-      } catch (e) {
-        reject(e);
-      }
-    };
-  }));
-}
-
-function isAllowedAsAKey(value) {
-  if (typeof value === 'number' || typeof value === 'string') {
-    return true;
-  }
-
-  if (Array.isArray(value)) {
-    return true;
-  }
-
-  if (isDate(value)) {
-    return true;
-  }
-
-  if (ArrayBuffer.isView(value)) {
-    return true;
-  }
-
-  if (isArrayBuffer(value)) {
-    return true;
-  }
-
-  return false;
-}
-
-function isDate(value) {
-  try {
-    Date.prototype.getTime.call(value);
-    return true;
-  } catch {
-    return false;
-  }
-}
-
-const byteLengthGetter =
-    Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, 'byteLength').get;
-function isArrayBuffer(value) {
-  try {
-    byteLengthGetter.call(value);
-    return true;
-  } catch {
-    return false;
-  }
-}
-
-function throwForDisallowedKey(key) {
-  if (!isAllowedAsAKey(key)) {
-    throw new DOMException(
-        'The given value is not allowed as a key', 'DataError');
-  }
+        request.onupgradeneeded = () => {
+          try {
+            request.result.createObjectStore(DEFAULT_IDB_STORE_NAME);
+          } catch (e) {
+            reject(e);
+          }
+        };
+      }));
 }
 
 function zip(a, b) {
@@ -234,11 +186,3 @@
 
   return result;
 }
-
-function deleteDatabase(name) {
-  return new Promise((resolve, reject) => {
-    const request = self.indexedDB.deleteDatabase(name);
-    request.onsuccess = () => resolve();
-    request.onerror = () => reject(request.error);
-  });
-}
diff --git a/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc b/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
index c077945..fb223261 100644
--- a/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
+++ b/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
@@ -732,54 +732,34 @@
     EndListChanged(elapsed);
 }
 
-inline bool CompareTimes(const SMILTimeWithOrigin& left,
-                         const SMILTimeWithOrigin& right) {
-  return left.Time() < right.Time();
-}
-
 SMILTime SVGSMILElement::FindInstanceTime(BeginOrEnd begin_or_end,
                                           SMILTime minimum_time,
                                           bool equals_minimum_ok) const {
   const Vector<SMILTimeWithOrigin>& list =
       begin_or_end == kBegin ? begin_times_ : end_times_;
-  int size_of_list = list.size();
 
-  if (!size_of_list)
+  if (list.IsEmpty())
     return begin_or_end == kBegin ? SMILTime::Unresolved()
                                   : SMILTime::Indefinite();
 
-  const SMILTimeWithOrigin dummy_time_with_origin(
-      minimum_time, SMILTimeWithOrigin::kParserOrigin);
-  const SMILTimeWithOrigin* result = std::lower_bound(
-      list.begin(), list.end(), dummy_time_with_origin, CompareTimes);
-  int index_of_result = static_cast<int>(result - list.begin());
-  if (index_of_result == size_of_list)
+  // If an equal value is not accepted, return the next bigger item in the list,
+  // if any.
+  auto predicate = [equals_minimum_ok](const SMILTimeWithOrigin& instance_time,
+                                       const SMILTime& time) {
+    return equals_minimum_ok ? instance_time.Time() < time
+                             : instance_time.Time() <= time;
+  };
+  auto* item =
+      std::lower_bound(list.begin(), list.end(), minimum_time, predicate);
+  if (item == list.end())
     return SMILTime::Unresolved();
-  const SMILTime& current_time = list[index_of_result].Time();
 
   // The special value "indefinite" does not yield an instance time in the begin
   // list.
-  if (current_time.IsIndefinite() && begin_or_end == kBegin)
+  if (item->Time().IsIndefinite() && begin_or_end == kBegin)
     return SMILTime::Unresolved();
 
-  if (current_time > minimum_time)
-    return current_time;
-
-  DCHECK(current_time == minimum_time);
-  if (equals_minimum_ok)
-    return current_time;
-
-  // If the equals is not accepted, return the next bigger item in the list.
-  SMILTime next_time = current_time;
-  while (index_of_result < size_of_list - 1) {
-    next_time = list[index_of_result + 1].Time();
-    if (next_time > minimum_time)
-      return next_time;
-    ++index_of_result;
-  }
-
-  return begin_or_end == kBegin ? SMILTime::Unresolved()
-                                : SMILTime::Indefinite();
+  return item->Time();
 }
 
 SMILTime SVGSMILElement::RepeatingDuration() const {
diff --git a/third_party/blink/renderer/core/testing/internals.cc b/third_party/blink/renderer/core/testing/internals.cc
index 91e2e2a..01908d9 100644
--- a/third_party/blink/renderer/core/testing/internals.cc
+++ b/third_party/blink/renderer/core/testing/internals.cc
@@ -1941,7 +1941,8 @@
       const cc::TouchActionRegion& touch_action_region =
           layer->touch_action_region();
       if (!touch_action_region.region().IsEmpty()) {
-        IntRect layer_rect(RoundedIntPoint(FloatPoint(layer->position())),
+        const auto& offset = layer->offset_to_transform_parent();
+        IntRect layer_rect(RoundedIntPoint(FloatPoint(offset.x(), offset.y())),
                            IntSize(layer->bounds()));
 
         Vector<IntRect> layer_hit_test_rects;
diff --git a/third_party/blink/renderer/devtools/front_end/security/SecurityPanel.js b/third_party/blink/renderer/devtools/front_end/security/SecurityPanel.js
index 833df59..7318c75 100644
--- a/third_party/blink/renderer/devtools/front_end/security/SecurityPanel.js
+++ b/third_party/blink/renderer/devtools/front_end/security/SecurityPanel.js
@@ -376,7 +376,6 @@
  * @typedef {Object}
  * @property {!Protocol.Security.SecurityState} securityState
  * @property {?Protocol.Network.SecurityDetails} securityDetails
- * @property {?Promise<>} certificateDetailsPromise
  * @property {?bool} loadedFromCache
  * @property {?Security.SecurityOriginView} originView
  */
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
index fae6134e..5bea64e31 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
@@ -9,6 +9,7 @@
 #include <memory>
 
 #include "base/metrics/histogram_functions.h"
+#include "base/numerics/checked_math.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/renderer/core/css/cssom/css_url_image_value.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser.h"
@@ -1767,9 +1768,12 @@
       CanvasColorParams(ColorParams().ColorSpace(), PixelFormat(), kNonOpaque);
   if (data_color_params.NeedsColorConversion(context_color_params) ||
       PixelFormat() == kF16CanvasPixelFormat) {
-    size_t data_length =
-        data->Size().Area() * context_color_params.BytesPerPixel();
-    std::unique_ptr<uint8_t[]> converted_pixels(new uint8_t[data_length]);
+    base::CheckedNumeric<size_t> data_length = data->Size().Area();
+    data_length *= context_color_params.BytesPerPixel();
+    if (!data_length.IsValid())
+      return;
+    std::unique_ptr<uint8_t[]> converted_pixels(
+        new uint8_t[data_length.ValueOrDie()]);
     if (data->ImageDataInCanvasColorSettings(
             ColorParams().ColorSpace(), PixelFormat(), converted_pixels.get(),
             kRGBAColorType)) {
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.cc
index c70cb754..9e63a1e 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.cc
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.cc
@@ -144,7 +144,8 @@
 }
 
 void MediaControlPopupMenuElement::DefaultEventHandler(Event& event) {
-  if (event.type() == event_type_names::kPointermove) {
+  if (event.type() == event_type_names::kPointermove &&
+      event.target() != this) {
     ToElement(event.target()->ToNode())->focus();
   } else if (event.type() == event_type_names::kFocusout) {
     GetDocument()
@@ -226,7 +227,8 @@
     return;
 
   if (!GetDocument().FocusedElement() ||
-      GetDocument().FocusedElement()->parentElement() != this) {
+      (GetDocument().FocusedElement()->parentElement() != this &&
+       GetDocument().FocusedElement() != this)) {
     SetIsWanted(false);
   }
 }
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.h b/third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.h
index a538d3ee5..67808d74 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.h
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_popup_menu_element.h
@@ -31,6 +31,13 @@
 
   void Trace(blink::Visitor*) override;
 
+  // When clicking the scroll bar, chrome will find its first focusable parent
+  // and focus on it. In order to prevent popup menu from losing focus (which
+  // will close the menu), we are setting the popup menu support focus and mouse
+  // focusable.
+  bool IsMouseFocusable() const override { return true; }
+  bool SupportsFocus() const override { return true; }
+
  protected:
   MediaControlPopupMenuElement(MediaControlsImpl&, MediaControlElementType);
 
diff --git a/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css b/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css
index 8b06a21c..a39597f8 100644
--- a/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css
+++ b/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css
@@ -827,6 +827,11 @@
   transform-origin: bottom right;
 }
 
+audio::-internal-media-controls-overflow-menu-list:focus,
+video::-internal-media-controls-overflow-menu-list:focus {
+  outline: none;
+}
+
 audio::-internal-media-controls-overflow-menu-list.closed,
 video::-internal-media-controls-overflow-menu-list.closed {
   transform: scale(0);
diff --git a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
index fdf447f..e5b6209 100644
--- a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
+++ b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
@@ -130,9 +130,11 @@
           event_type_names::kEnterpictureinpicture,
           WrapPersistent(picture_in_picture_window_.Get())));
 
-  element->GetWebMediaPlayer()->RegisterPictureInPictureWindowResizeCallback(
-      WTF::BindRepeating(&PictureInPictureWindow::OnResize,
-                         WrapPersistent(picture_in_picture_window_.Get())));
+  if (element->GetWebMediaPlayer()) {
+    element->GetWebMediaPlayer()->RegisterPictureInPictureWindowResizeCallback(
+        WTF::BindRepeating(&PictureInPictureWindow::OnResize,
+                           WrapPersistent(picture_in_picture_window_.Get())));
+  }
 
   if (resolver)
     resolver->Resolve(picture_in_picture_window_);
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 b3a75b1..42a8230 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
@@ -122,13 +122,14 @@
                                             unsigned end) const {
   if (graphemes_.size() == 0 || start >= num_characters_)
     return 0;
-  DCHECK_LT(start, end);
-  DCHECK_LE(end, num_characters_);
+  CHECK_LT(start, end);
+  CHECK_LE(end, num_characters_);
+  CHECK_EQ(num_characters_, graphemes_.size());
   return graphemes_[end - 1] - graphemes_[start] + 1;
 }
 
 void ShapeResult::EnsureGraphemes(const StringView& text) const {
-  DCHECK_EQ(NumCharacters(), text.length());
+  CHECK_EQ(NumCharacters(), text.length());
 
   // Hit-testing, canvas, etc. may still call this function for 0-length text,
   // or glyphs may be missing at all.
@@ -144,7 +145,7 @@
     return;
 
   unsigned result_start_index = StartIndex();
-  for (const auto& run : runs_) {
+  for (const scoped_refptr<RunInfo>& run : runs_) {
     if (!run)
       continue;
     DCHECK_GE(run->start_index_, result_start_index);
@@ -289,7 +290,6 @@
     BreakGlyphsOption break_glyphs_option,
     GlyphIndexResult* result) const {
   DCHECK(target_x >= 0 && target_x <= width_);
-  const unsigned num_glyphs = glyph_data_.size();
 
   result->origin_x = 0;
   unsigned glyph_sequence_start = 0;
@@ -301,12 +301,12 @@
     glyph_sequence_start = glyph_sequence_end = num_characters_;
   }
 
-  for (unsigned i = 0; i < num_glyphs; ++i) {
-    unsigned current_glyph_char_index = glyph_data_[i].character_index;
+  for (const HarfBuzzRunGlyphData& glyph_data : glyph_data_) {
+    unsigned current_glyph_char_index = glyph_data.character_index;
     // If the glyph is part of the same sequence, we just accumulate the
     // advance.
     if (glyph_sequence_start == current_glyph_char_index) {
-      result->advance += glyph_data_[i].advance;
+      result->advance += glyph_data.advance;
       continue;
     }
 
@@ -328,7 +328,7 @@
     }
     glyph_sequence_start = current_glyph_char_index;
     result->origin_x += result->advance;
-    result->advance = glyph_data_[i].advance;
+    result->advance = glyph_data.advance;
   }
 
   // At this point, we have [glyph_sequence_start, glyph_sequence_end)
@@ -512,19 +512,18 @@
   unsigned characters_so_far = Rtl() ? NumCharacters() : 0;
   float current_x = 0;
 
-  for (unsigned i = 0; i < runs_.size(); ++i) {
-    const RunInfo* run = runs_[i].get();
+  for (const scoped_refptr<RunInfo>& run_ptr : runs_) {
+    const RunInfo* run = run_ptr.get();
     if (!run)
       continue;
     if (Rtl())
-      characters_so_far -= runs_[i]->num_characters_;
+      characters_so_far -= run->num_characters_;
     float next_x = current_x + run->width_;
     float offset_for_run = target_x - current_x;
     if (offset_for_run >= 0 && offset_for_run < run->width_) {
       // The x value in question is within this script run.
       run->CharacterIndexForXPosition(offset_for_run, break_glyphs_option,
                                       result);
-      result->run_index = i;
       result->characters_on_left_runs = characters_so_far;
       if (Rtl()) {
         result->left_character_index =
@@ -555,7 +554,6 @@
     result->right_character_index += characters_so_far;
   }
 
-  result->run_index = runs_.size() - 1;
   result->characters_on_left_runs = characters_so_far;
 
   DCHECK_LE(result->left_character_index, NumCharacters());
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 72e7d4ee..05ff17b 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
@@ -342,7 +342,6 @@
     STACK_ALLOCATED();
 
    public:
-    unsigned run_index = 0;
     // The total number of characters of runs_[0..run_index - 1].
     unsigned characters_on_left_runs = 0;
 
diff --git a/third_party/blink/renderer/platform/graphics/bitmap_image.cc b/third_party/blink/renderer/platform/graphics/bitmap_image.cc
index 0fdd3dd6..8a56e38 100644
--- a/third_party/blink/renderer/platform/graphics/bitmap_image.cc
+++ b/third_party/blink/renderer/platform/graphics/bitmap_image.cc
@@ -99,7 +99,7 @@
 
 size_t BitmapImage::TotalFrameBytes() {
   if (cached_frame_)
-    return Size().Area() * sizeof(ImageFrame::PixelData);
+    return static_cast<size_t>(Size().Area()) * sizeof(ImageFrame::PixelData);
   return 0u;
 }
 
@@ -182,8 +182,8 @@
 
 // Return the image density in 0.01 "bits per pixel" rounded to the nearest
 // integer.
-static inline int ImageDensityInCentiBpp(IntSize size,
-                                         size_t image_size_bytes) {
+static inline uint64_t ImageDensityInCentiBpp(IntSize size,
+                                              size_t image_size_bytes) {
   uint64_t image_area = static_cast<uint64_t>(size.Width()) * size.Height();
   return (static_cast<uint64_t>(image_size_bytes) * 100 * 8 + image_area / 2) /
          image_area;
diff --git a/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.cc b/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.cc
index d00a092..965892c8 100644
--- a/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.cc
+++ b/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.cc
@@ -46,7 +46,7 @@
 }
 
 void BitmapImageMetrics::CountImageJpegDensity(int image_min_side,
-                                               int64_t density_centi_bpp) {
+                                               uint64_t density_centi_bpp) {
   // Values are reported in the range 0.01 to 10 bpp, in different metrics
   // depending on the image category (small, medium, large).
   if (image_min_side >= 1000) {
diff --git a/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.h b/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.h
index 3479690..ab67d76c 100644
--- a/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.h
+++ b/third_party/blink/renderer/platform/graphics/bitmap_image_metrics.h
@@ -77,7 +77,7 @@
   // Report the JPEG compression density in 0.01 bits per pixel for an image
   // with a smallest side (width or length) of |image_min_side|.
   static void CountImageJpegDensity(int image_min_side,
-                                    int64_t density_centi_bpp);
+                                    uint64_t density_centi_bpp);
   static void CountImageGammaAndGamut(const skcms_ICCProfile*);
   static void CountJpegArea(const IntSize& size);
   static void CountJpegColorSpace(JpegColorSpace color_space);
diff --git a/third_party/blink/renderer/platform/graphics/crossfade_generated_image.cc b/third_party/blink/renderer/platform/graphics/crossfade_generated_image.cc
index 4550162..59c68f6 100644
--- a/third_party/blink/renderer/platform/graphics/crossfade_generated_image.cc
+++ b/third_party/blink/renderer/platform/graphics/crossfade_generated_image.cc
@@ -63,7 +63,6 @@
   PaintFlags image_flags(flags);
   image_flags.setBlendMode(SkBlendMode::kSrcOver);
   image_flags.setColor(ScaleAlpha(flags.getColor(), 1 - percentage_));
-  image_flags.setAntiAlias(flags.isAntiAlias());
   // TODO(junov): This code should probably be propagating the
   // RespectImageOrientationEnum from CrossfadeGeneratedImage::draw(). Code was
   // written this way during refactoring to avoid modifying existing behavior,
@@ -106,7 +105,6 @@
 
   PaintFlags flags = context.FillFlags();
   flags.setBlendMode(SkBlendMode::kSrcOver);
-  flags.setAntiAlias(context.ShouldAntialias());
   FloatRect dest_rect((FloatPoint()), crossfade_size_);
   flags.setFilterQuality(
       context.ComputeFilterQuality(this, dest_rect, src_rect));
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgl_image_conversion.cc b/third_party/blink/renderer/platform/graphics/gpu/webgl_image_conversion.cc
index 6ad59bb..2cc0ad8c 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/webgl_image_conversion.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/webgl_image_conversion.cc
@@ -2721,8 +2721,8 @@
   }
 
   unsigned padding = 0;
-  base::CheckedNumeric<uint32_t> checked_residual =
-      checked_value % params.alignment;
+  base::CheckedNumeric<uint32_t> checked_residual = checked_value;
+  checked_residual %= static_cast<uint32_t>(params.alignment);
   if (!checked_residual.IsValid()) {
     return GL_INVALID_VALUE;
   }
diff --git a/third_party/blink/renderer/platform/graphics/graphics_context.cc b/third_party/blink/renderer/platform/graphics/graphics_context.cc
index 676eb95..4cc66dadf 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_context.cc
+++ b/third_party/blink/renderer/platform/graphics/graphics_context.cc
@@ -910,7 +910,6 @@
   image_flags.setBlendMode(op);
   image_flags.setColor(SK_ColorBLACK);
   image_flags.setFilterQuality(ComputeFilterQuality(image, dest, src));
-  image_flags.setAntiAlias(ShouldAntialias());
   if (ShouldApplyHighContrastFilterToImage(*image))
     image_flags.setColorFilter(high_contrast_filter_);
   image->Draw(canvas_, image_flags, dest, src, should_respect_image_orientation,
@@ -946,7 +945,6 @@
   image_flags.setColor(SK_ColorBLACK);
   image_flags.setFilterQuality(
       ComputeFilterQuality(image, dest.Rect(), src_rect));
-  image_flags.setAntiAlias(ShouldAntialias());
 
   bool use_shader = (visible_src == src_rect) &&
                     (respect_orientation == kDoNotRespectImageOrientation);
diff --git a/third_party/blink/renderer/platform/graphics/image.cc b/third_party/blink/renderer/platform/graphics/image.cc
index 154e994..efa5fa09 100644
--- a/third_party/blink/renderer/platform/graphics/image.cc
+++ b/third_party/blink/renderer/platform/graphics/image.cc
@@ -303,7 +303,8 @@
 
 sk_sp<PaintShader> CreatePatternShader(const PaintImage& image,
                                        const SkMatrix& shader_matrix,
-                                       const PaintFlags& paint,
+                                       SkFilterQuality quality_to_use,
+                                       bool should_antialias,
                                        const FloatSize& spacing,
                                        SkShader::TileMode tmx,
                                        SkShader::TileMode tmy) {
@@ -318,7 +319,10 @@
 
   PaintRecorder recorder;
   cc::PaintCanvas* canvas = recorder.beginRecording(tile_rect);
-  canvas->drawImage(image, 0, 0, &paint);
+  PaintFlags flags;
+  flags.setAntiAlias(should_antialias);
+  flags.setFilterQuality(quality_to_use);
+  canvas->drawImage(image, 0, 0, &flags);
 
   return PaintShader::MakePaintRecord(recorder.finishRecordingAsPicture(),
                                       tile_rect, tmx, tmy, &shader_matrix);
@@ -389,22 +393,22 @@
   const auto tmy = ComputeTileMode(dest_rect.Y(), dest_rect.MaxY(), adjusted_y,
                                    adjusted_y + tile_size.Height());
 
-  PaintFlags flags = context.FillFlags();
-  flags.setColor(SK_ColorBLACK);
-  flags.setBlendMode(composite_op);
-  flags.setFilterQuality(
-      context.ComputeFilterQuality(this, dest_rect, FloatRect(subset_rect)));
-  flags.setAntiAlias(context.ShouldAntialias());
-  flags.setShader(CreatePatternShader(
-      image, local_matrix, flags,
+  SkFilterQuality quality_to_use =
+      context.ComputeFilterQuality(this, dest_rect, FloatRect(subset_rect));
+  sk_sp<PaintShader> tile_shader = CreatePatternShader(
+      image, local_matrix, quality_to_use, context.ShouldAntialias(),
       FloatSize(repeat_spacing.Width() / scale_src_to_dest.Width(),
                 repeat_spacing.Height() / scale_src_to_dest.Height()),
-      tmx, tmy));
+      tmx, tmy);
+
+  PaintFlags flags = context.FillFlags();
   // If the shader could not be instantiated (e.g. non-invertible matrix),
   // draw transparent.
   // Note: we can't simply bail, because of arbitrary blend mode.
-  if (!flags.HasShader())
-    flags.setColor(SK_ColorTRANSPARENT);
+  flags.setColor(tile_shader ? SK_ColorBLACK : SK_ColorTRANSPARENT);
+  flags.setBlendMode(composite_op);
+  flags.setFilterQuality(quality_to_use);
+  flags.setShader(std::move(tile_shader));
 
   context.DrawRect(dest_rect, flags);
 
diff --git a/third_party/blink/renderer/platform/image-decoders/image_decoder.cc b/third_party/blink/renderer/platform/image-decoders/image_decoder.cc
index b9ad319..6133e01 100644
--- a/third_party/blink/renderer/platform/image-decoders/image_decoder.cc
+++ b/third_party/blink/renderer/platform/image-decoders/image_decoder.cc
@@ -21,6 +21,8 @@
 #include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
 
 #include <memory>
+
+#include "base/numerics/safe_conversions.h"
 #include "third_party/blink/renderer/platform/graphics/bitmap_image_metrics.h"
 #include "third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_decoder.h"
 #include "third_party/blink/renderer/platform/image-decoders/fast_shared_buffer_reader.h"
@@ -193,20 +195,16 @@
       frame_buffer_cache_[index].GetStatus() == ImageFrame::kFrameEmpty)
     return 0;
 
-  struct ImageSize {
-    explicit ImageSize(IntSize size) {
-      area = static_cast<uint64_t>(size.Width()) * size.Height();
-    }
-
-    uint64_t area;
-  };
-
   size_t decoded_bytes_per_pixel = k4BytesPerPixel;
   if (frame_buffer_cache_[index].GetPixelFormat() ==
       ImageFrame::PixelFormat::kRGBA_F16) {
     decoded_bytes_per_pixel = k8BytesPerPixel;
   }
-  return ImageSize(FrameSizeAtIndex(index)).area * decoded_bytes_per_pixel;
+  IntSize size = FrameSizeAtIndex(index);
+  base::CheckedNumeric<size_t> area = size.Width();
+  area *= size.Height();
+  area *= decoded_bytes_per_pixel;
+  return area.ValueOrDie();
 }
 
 size_t ImageDecoder::ClearCacheExceptFrame(size_t clear_except_frame) {
diff --git a/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder.cc b/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder.cc
index 45f2b95..3f8d7e09 100644
--- a/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder.cc
+++ b/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder.cc
@@ -39,6 +39,8 @@
 #include "third_party/blink/renderer/platform/image-decoders/png/png_image_decoder.h"
 
 #include <memory>
+
+#include "base/numerics/checked_math.h"
 #include "third_party/skia/third_party/skcms/skcms.h"
 
 #if (defined(__ARM_NEON__) || defined(__ARM_NEON))
@@ -528,10 +530,15 @@
     if (PNG_INTERLACE_ADAM7 ==
         png_get_interlace_type(png, reader_->InfoPtr())) {
       unsigned color_channels = has_alpha_channel_ ? 4 : 3;
-      unsigned interlace_buffer_size = color_channels * Size().Area();
+      base::CheckedNumeric<int> interlace_buffer_size = color_channels;
+      interlace_buffer_size *= Size().Area();
       if (decode_to_half_float_)
         interlace_buffer_size *= 2;
-      reader_->CreateInterlaceBuffer(interlace_buffer_size);
+      if (!interlace_buffer_size.IsValid()) {
+        longjmp(JMPBUF(png), 1);
+        return;
+      }
+      reader_->CreateInterlaceBuffer(interlace_buffer_size.ValueOrDie());
       if (!reader_->InterlaceBuffer()) {
         longjmp(JMPBUF(png), 1);
         return;
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index f35623da..5efc22c 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -134,7 +134,7 @@
     },
     {
       name: "BlinkGenPropertyTrees",
-      status: "test",
+      status: "experimental",
     },
     {
       name: "BlinkRuntimeCallStats",
diff --git a/third_party/blink/tools/blinkpy/third_party/README.chromium b/third_party/blink/tools/blinkpy/third_party/README.chromium
index 471794f..ff59668 100644
--- a/third_party/blink/tools/blinkpy/third_party/README.chromium
+++ b/third_party/blink/tools/blinkpy/third_party/README.chromium
@@ -32,7 +32,7 @@
 Name: web-platform-tests - Test Suites for Web Platform specifications
 Short Name: wpt
 URL: https://github.com/web-platform-tests/wpt/
-Version: 23ce30a85c115ea9247e4ef7e3e0d108110a08cd
+Version: f759f0b3a8cb7457adbf30dc0734d3a158ce4990
 License: LICENSES FOR W3C TEST SUITES (http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html)
 License File: wpt/wpt/LICENSE.md
 Security Critical: no
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/checkout.sh b/third_party/blink/tools/blinkpy/third_party/wpt/checkout.sh
index 7a4fe6c0..d927f184 100755
--- a/third_party/blink/tools/blinkpy/third_party/wpt/checkout.sh
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/checkout.sh
@@ -9,7 +9,7 @@
 
 TARGET_DIR=$DIR/wpt
 REMOTE_REPO="https://chromium.googlesource.com/external/github.com/web-platform-tests/wpt.git"
-WPT_HEAD=23ce30a85c115ea9247e4ef7e3e0d108110a08cd
+WPT_HEAD=f759f0b3a8cb7457adbf30dc0734d3a158ce4990
 
 function clone {
   # Remove existing repo if already exists.
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/.gitignore b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/.gitignore
index a71d35cb..8e3a851 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/.gitignore
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/.gitignore
@@ -15,6 +15,11 @@
 .wptcache/
 /config.json
 
+# Files generated when regenerating pre-generated certs
+/tools/certs/0*.pem
+/tools/certs/index.txt*
+/tools/certs/serial*
+
 # Various OS/editor specific files
 *#
 *.sw[po]
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/manifest.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/manifest.py
index 2777109..127d45d 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/manifest.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/manifest.py
@@ -79,7 +79,12 @@
         return rv
 
     def __delitem__(self, key):
-        del self.data[key]
+        if key in self.data:
+            del self.data[key]
+        elif self.json_data is not None:
+            del self.json_data[from_os_path(key)]
+        else:
+            raise KeyError
 
     def __setitem__(self, key, value):
         self.data[key] = value
@@ -279,6 +284,11 @@
                     if old_hash != file_hash:
                         new_type, manifest_items = source_file.manifest_items()
                         hash_changed = True
+                        if new_type != old_type:
+                            try:
+                                del self._data[old_type][rel_path]
+                            except KeyError:
+                                pass
                     else:
                         new_type, manifest_items = old_type, self._data[old_type][rel_path]
                     if old_type in reftest_types and new_type != old_type:
@@ -306,10 +316,7 @@
                     _, old_type = self._path_hash[rel_path]
                     if old_type in reftest_types:
                         reftest_changes = True
-                    try:
-                        del self._path_hash[rel_path]
-                    except KeyError:
-                        pass
+                    del self._path_hash[rel_path]
                     try:
                         del self._data[old_type][rel_path]
                     except KeyError:
@@ -402,8 +409,16 @@
     return _load(logger, tests_root, manifest, types, meta_filters)
 
 
+__load_cache = {}
+
+
 def _load(logger, tests_root, manifest, types=None, meta_filters=None):
     # "manifest" is a path or file-like object.
+    manifest_path = (manifest if isinstance(manifest, string_types)
+                     else manifest.name)
+    if manifest_path in __load_cache:
+        return __load_cache[manifest_path]
+
     if isinstance(manifest, string_types):
         if os.path.exists(manifest):
             logger.debug("Opening manifest at %s" % manifest)
@@ -420,12 +435,14 @@
         except ValueError:
             logger.warning("%r may be corrupted", manifest)
             return None
-        return rv
+    else:
+        rv = Manifest.from_json(tests_root,
+                                json.load(manifest),
+                                types=types,
+                                meta_filters=meta_filters)
 
-    return Manifest.from_json(tests_root,
-                              json.load(manifest),
-                              types=types,
-                              meta_filters=meta_filters)
+    __load_cache[manifest_path] = rv
+    return rv
 
 
 def load_and_update(tests_root,
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/serve/serve.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/serve/serve.py
index c4afc69..4eee732 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/serve/serve.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/serve/serve.py
@@ -757,7 +757,9 @@
             "openssl": {
                 "openssl_binary": "openssl",
                 "base_path": "_certs",
+                "password": "web-platform-tests",
                 "force_regenerate": False,
+                "duration": 30,
                 "base_conf_path": None
             },
             "pregenerated": {
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/browser.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/browser.py
index 959bec70..71d1e61 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/browser.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/browser.py
@@ -1,4 +1,3 @@
-import logging
 import os
 import platform
 import re
@@ -12,14 +11,15 @@
 
 from utils import call, get, untar, unzip
 
-logger = logging.getLogger(__name__)
-
 uname = platform.uname()
 
 
 class Browser(object):
     __metaclass__ = ABCMeta
 
+    def __init__(self, logger):
+        self.logger = logger
+
     @abstractmethod
     def install(self, dest=None):
         """Install the browser."""
@@ -124,10 +124,14 @@
 
         dest = os.path.join(dest, "browsers", channel)
 
-        filename = FactoryScraper(scraper[channel],
-                                  branch=branch[channel],
-                                  version=version[channel],
-                                  destination=dest).download()
+        scraper = FactoryScraper(scraper[channel],
+                                 branch=branch[channel],
+                                 version=version[channel],
+                                 destination=dest)
+
+        self.logger.info("Downloading Firefox from %s" % scraper.url)
+
+        filename = scraper.download()
 
         try:
             mozinstall.install(filename, dest)
@@ -237,7 +241,7 @@
         if channel is not None and channel != channel_:
             # Beta doesn't always seem to have the b in the version string, so allow the
             # manually supplied value to override the one from the binary
-            logger.warning("Supplied channel doesn't match binary, using supplied channel")
+            self.logger.warning("Supplied channel doesn't match binary, using supplied channel")
         elif channel is None:
             channel = channel_
         if dest is None:
@@ -263,7 +267,7 @@
 
             url = self.get_profile_bundle_url(version, channel)
 
-            logger.info("Installing test prefs from %s" % url)
+            self.logger.info("Installing test prefs from %s" % url)
             try:
                 extract_dir = tempfile.mkdtemp()
                 unzip(get(url).raw, dest=extract_dir)
@@ -275,7 +279,7 @@
             finally:
                 shutil.rmtree(extract_dir)
         else:
-            logger.info("Using cached test prefs from %s" % dest)
+            self.logger.info("Using cached test prefs from %s" % dest)
 
         return dest
 
@@ -305,11 +309,11 @@
             if path is not None:
                 return path
             else:
-                logger.warning("Nightly webdriver not found; falling back to release")
+                self.logger.warning("Nightly webdriver not found; falling back to release")
 
         version = self._latest_geckodriver_version()
         format = "zip" if uname[0] == "Windows" else "tar.gz"
-        logger.debug("Latest geckodriver release %s" % version)
+        self.logger.debug("Latest geckodriver release %s" % version)
         url = ("https://github.com/mozilla/geckodriver/releases/download/%s/geckodriver-%s-%s.%s" %
                (version, version, self.platform_string_geckodriver(), format))
         if format == "zip":
@@ -321,7 +325,7 @@
     def install_geckodriver_nightly(self, dest):
         import tarfile
         import mozdownload
-        logger.info("Attempting to install webdriver from nightly")
+        self.logger.info("Attempting to install webdriver from nightly")
         try:
             s = mozdownload.DailyScraper(branch="mozilla-central",
                                          extension="common.tests.tar.gz",
@@ -342,7 +346,7 @@
                 member.name = os.path.basename(member.name)
                 f.extractall(members=[member], path=dest)
                 path = os.path.join(dest, member.name)
-            logger.info("Extracted geckodriver to %s" % path)
+            self.logger.info("Extracted geckodriver to %s" % path)
         finally:
             os.unlink(package_path)
 
@@ -395,7 +399,7 @@
         if uname[0] == "Darwin":
             return "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
         # TODO Windows?
-        logger.warn("Unable to find the browser binary.")
+        self.logger.warning("Unable to find the browser binary.")
         return None
 
     def install(self, dest=None, channel=None):
@@ -445,14 +449,14 @@
             try:
                 version_string = call(binary, "--version").strip()
             except subprocess.CalledProcessError:
-                logger.warn("Failed to call %s", binary)
+                self.logger.warning("Failed to call %s", binary)
                 return None
             m = re.match(r"Google Chrome (.*)", version_string)
             if not m:
-                logger.warn("Failed to extract version from: s%", version_string)
+                self.logger.warning("Failed to extract version from: s%", version_string)
                 return None
             return m.group(1)
-        logger.warn("Unable to extract version from binary on Windows.")
+        self.logger.warning("Unable to extract version from binary on Windows.")
         return None
 
 
@@ -495,7 +499,7 @@
         if uname[0] == "Linux":
             return "/usr/bin/opera"
         # TODO Windows, Mac?
-        logger.warn("Unable to find the browser binary.")
+        self.logger.warning("Unable to find the browser binary.")
         return None
 
     def install(self, dest=None, channel=None):
@@ -549,7 +553,7 @@
         try:
             output = call(binary, "--version")
         except subprocess.CalledProcessError:
-            logger.warn("Failed to call %s", binary)
+            self.logger.warning("Failed to call %s", binary)
             return None
         m = re.search(r"[0-9\.]+( [a-z]+)?$", output.strip())
         if m:
@@ -630,7 +634,7 @@
 
     def version(self, binary=None, webdriver_binary=None):
         if webdriver_binary is None:
-            logger.warn("Cannot find Safari version without safaridriver")
+            self.logger.warning("Cannot find Safari version without safaridriver")
             return None
         # Use `safaridriver --version` to get the version. Example output:
         # "Included with Safari 12.1 (14607.1.11)"
@@ -639,11 +643,11 @@
         try:
             version_string = call(webdriver_binary, "--version").strip()
         except subprocess.CalledProcessError:
-            logger.warn("Failed to call %s --version", webdriver_binary)
+            self.logger.warning("Failed to call %s --version", webdriver_binary)
             return None
         m = re.match(r"Included with Safari (.*)", version_string)
         if not m:
-            logger.warn("Failed to extract version from: s%", version_string)
+            self.logger.warning("Failed to extract version from: s%", version_string)
             return None
         return m.group(1)
 
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/install.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/install.py
index 16f565e..be6bf81 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/install.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/install.py
@@ -73,7 +73,11 @@
     install(browser, kwargs["component"], destination, channel)
 
 
-def install(name, component, destination, channel="nightly"):
+def install(name, component, destination, channel="nightly", logger=None):
+    if logger is None:
+        import logging
+        logger = logging.getLogger("install")
+
     if component == 'webdriver':
         method = 'install_webdriver'
     else:
@@ -81,6 +85,6 @@
 
     subclass = getattr(browser, name.title())
     sys.stdout.write('Now installing %s %s...\n' % (name, component))
-    path = getattr(subclass(), method)(dest=destination, channel=channel)
+    path = getattr(subclass(logger), method)(dest=destination, channel=channel)
     if path:
         sys.stdout.write('Binary installed as %s\n' % (path,))
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/run.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/run.py
index 00984af6..44cf3137 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/run.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/run.py
@@ -151,7 +151,7 @@
     browser_cls = None
 
     def __init__(self, venv, prompt=True, sub_product=None):
-        self.browser = self.browser_cls()
+        self.browser = self.browser_cls(logger)
         self.venv = venv
         self.prompt = prompt
         self.sub_product = sub_product
@@ -474,6 +474,7 @@
         default_config = {default_formatter: sys.stdout}
     wptrunner.setup_logging(kwargs, default_config)
     logger = wptrunner.logger
+    return logger
 
 
 def setup_wptrunner(venv, prompt=True, install_browser=False, **kwargs):
@@ -509,11 +510,9 @@
             files_changed, manifest_path=kwargs.get("manifest_path"), manifest_update=kwargs["manifest_update"])
         test_list = tests_changed | tests_affected
         logger.info("Identified %s affected tests" % len(test_list))
-        if not test_list and not kwargs["test_list"]:
-            logger.info("Quitting because no tests were affected.")
-            exit()
         test_list = [os.path.relpath(item, wpt_root) for item in test_list]
         kwargs["test_list"] += test_list
+        kwargs["default_exclude"] = True
 
     if install_browser and not kwargs["channel"]:
         logger.info("--install-browser is given but --channel is not set, default to nightly channel")
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/testfiles.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/testfiles.py
index 2b20b07..70e695a 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/testfiles.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/testfiles.py
@@ -8,8 +8,6 @@
 from collections import OrderedDict
 from six import iteritems
 
-from ..manifest import manifest
-
 here = os.path.dirname(__file__)
 wpt_root = os.path.abspath(os.path.join(here, os.pardir, os.pardir))
 
@@ -183,24 +181,15 @@
     return len(path_components) < 2
 
 
-def _init_manifest_cache():
-    c = {}
-
-    def load(manifest_path=None, manifest_update=True):
-        if manifest_path is None:
-            manifest_path = os.path.join(wpt_root, "MANIFEST.json")
-        if c.get(manifest_path):
-            return c[manifest_path]
-        # cache at most one path:manifest
-        c.clear()
-        wpt_manifest = manifest.load_and_update(wpt_root, manifest_path, "/",
-                                                update=manifest_update)
-        c[manifest_path] = wpt_manifest
-        return c[manifest_path]
-    return load
-
-
-load_manifest = _init_manifest_cache()
+def load_manifest(manifest_path=None, manifest_update=True):
+    # Delay import after localpaths sets up sys.path, because otherwise the
+    # import path will be "..manifest" and Python will treat it as a different
+    # manifest module.
+    from manifest import manifest
+    if manifest_path is None:
+        manifest_path = os.path.join(wpt_root, "MANIFEST.json")
+    return manifest.load_and_update(wpt_root, manifest_path, "/",
+                                    update=manifest_update)
 
 
 def affected_testfiles(files_changed, skip_dirs=None,
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/config.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/config.py
index 57368f7..aadcbb9 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/config.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/config.py
@@ -126,7 +126,9 @@
             "openssl": {
                 "openssl_binary": "openssl",
                 "base_path": "_certs",
+                "password": "web-platform-tests",
                 "force_regenerate": False,
+                "duration": 30,
                 "base_conf_path": None
             },
             "pregenerated": {
@@ -316,7 +318,7 @@
         self._ssl_env.__enter__()
         if self._ssl_env.ssl_enabled:
             key_path, cert_path = self._ssl_env.host_cert_path(data["domains_set"])
-            ca_cert_path = self._ssl_env.ca_cert_path()
+            ca_cert_path = self._ssl_env.ca_cert_path(data["domains_set"])
             return {"key_path": key_path,
                     "ca_cert_path": ca_cert_path,
                     "cert_path": cert_path,
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/base.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/base.py
index c95b693..63ef45cc 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/base.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/base.py
@@ -13,5 +13,5 @@
     def host_cert_path(self, hosts):
         return None, None
 
-    def ca_cert_path(self):
+    def ca_cert_path(self, hosts):
         return None
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/openssl.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/openssl.py
index ebbcf68..db188dad 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/openssl.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/openssl.py
@@ -114,16 +114,18 @@
     return "".join(rv)
 
 def make_alt_names(hosts):
-    rv = []
-    for name in hosts:
-        rv.append("DNS:%s" % name)
-    return ",".join(rv)
+    return ",".join("DNS:%s" % host for host in hosts)
+
+def make_name_constraints(hosts):
+    return ",".join("permitted;DNS:%s" % host for host in hosts)
 
 def get_config(root_dir, hosts, duration=30):
     if hosts is None:
         san_line = ""
+        constraints_line = ""
     else:
         san_line = "subjectAltName = %s" % make_alt_names(hosts)
+        constraints_line = "nameConstraints = " + make_name_constraints(hosts)
 
     if os.path.sep == "\\":
         # This seems to be needed for the Shining Light OpenSSL on
@@ -213,9 +215,11 @@
 subjectKeyIdentifier=hash
 authorityKeyIdentifier=keyid:always,issuer:always
 keyUsage = keyCertSign
+%(constraints_line)s
 """ % {"root_dir": root_dir,
        "san_line": san_line,
        "duration": duration,
+       "constraints_line": constraints_line,
        "sep": os.path.sep.replace("\\", "\\\\")}
 
     return rv
@@ -287,13 +291,13 @@
         return OpenSSL(self.logger, self.binary, self.base_path, conf_path, hosts,
                        self.duration, self.base_conf_path)
 
-    def ca_cert_path(self):
+    def ca_cert_path(self, hosts):
         """Get the path to the CA certificate file, generating a
         new one if needed"""
         if self._ca_cert_path is None and not self.force_regenerate:
             self._load_ca_cert()
         if self._ca_cert_path is None:
-            self._generate_ca()
+            self._generate_ca(hosts)
         return self._ca_cert_path
 
     def _load_ca_cert(self):
@@ -326,7 +330,7 @@
         #TODO: check the key actually signed the cert.
         return True
 
-    def _generate_ca(self):
+    def _generate_ca(self, hosts):
         path = self.path
         self.logger.info("Generating new CA in %s" % self.base_path)
 
@@ -334,7 +338,7 @@
         req_path = path("careq.pem")
         cert_path = path("cacert.pem")
 
-        with self._config_openssl(None) as openssl:
+        with self._config_openssl(hosts) as openssl:
             openssl("req",
                     "-batch",
                     "-new",
@@ -391,7 +395,7 @@
     def _generate_host_cert(self, hosts):
         host = hosts[0]
         if self._ca_key_path is None:
-            self._generate_ca()
+            self._generate_ca(hosts)
         ca_key_path = self._ca_key_path
 
         assert os.path.exists(ca_key_path)
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/pregenerated.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/pregenerated.py
index fc487df..672a106 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/pregenerated.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/sslutils/pregenerated.py
@@ -20,7 +20,7 @@
         """Return the key and certificate paths for the host"""
         return self._host_key_path, self._host_cert_path
 
-    def ca_cert_path(self):
+    def ca_cert_path(self, hosts):
         """Return the certificate path of the CA that signed the
         host certificates, or None if that isn't known"""
         return self._ca_cert_path
diff --git a/third_party/blink/tools/blinkpy/web_tests/servers/apache_http.py b/third_party/blink/tools/blinkpy/web_tests/servers/apache_http.py
index d50fd947..96f830ed 100644
--- a/third_party/blink/tools/blinkpy/web_tests/servers/apache_http.py
+++ b/third_party/blink/tools/blinkpy/web_tests/servers/apache_http.py
@@ -45,9 +45,9 @@
         # match old-run-webkit-tests: https://bugs.webkit.org/show_bug.cgi?id=63956
         self._name = 'httpd'
         self._log_prefixes = ('access_log', 'error_log')
-        self._mappings = [{'port': 8000},
-                          {'port': 8080},
-                          {'port': 8443, 'sslcert': True}]
+        self._mappings = [{'port': 8000, 'scheme': 'http'},
+                          {'port': 8080, 'scheme': 'http'},
+                          {'port': 8443, 'scheme': 'https', 'sslcert': True}]
         self._number_of_servers = number_of_servers
 
         self._pid_file = self._filesystem.join(self._runtime_path, '%s.pid' % self._name)
diff --git a/third_party/blink/tools/blinkpy/web_tests/servers/cli_wrapper.py b/third_party/blink/tools/blinkpy/web_tests/servers/cli_wrapper.py
index 390f3b2..d45341f 100644
--- a/third_party/blink/tools/blinkpy/web_tests/servers/cli_wrapper.py
+++ b/third_party/blink/tools/blinkpy/web_tests/servers/cli_wrapper.py
@@ -36,6 +36,7 @@
 import optparse
 
 from blinkpy.common.host import Host
+from blinkpy.common.system.log_utils import configure_logging
 from blinkpy.web_tests.port.factory import configuration_options
 
 
@@ -56,9 +57,8 @@
         parser.add_option(opt)
     options, _ = parser.parse_args(argv)
 
-    logging.basicConfig()
-    logger = logging.getLogger()
-    logger.setLevel(logging.DEBUG if options.verbose else logging.INFO)
+    configure_logging(logging_level=logging.DEBUG if options.verbose else logging.INFO,
+                      include_time=options.verbose)
 
     host = Host()
     port_obj = host.port_factory.get(options=options)
diff --git a/third_party/blink/tools/blinkpy/web_tests/servers/pywebsocket.py b/third_party/blink/tools/blinkpy/web_tests/servers/pywebsocket.py
index 16a9e32..2a5c9e0 100644
--- a/third_party/blink/tools/blinkpy/web_tests/servers/pywebsocket.py
+++ b/third_party/blink/tools/blinkpy/web_tests/servers/pywebsocket.py
@@ -47,7 +47,7 @@
         super(PyWebSocket, self).__init__(port_obj, output_dir)
         self._name = 'pywebsocket'
         self._log_prefixes = (_WS_LOG_PREFIX,)
-        self._mappings = [{'port': _DEFAULT_WS_PORT}]
+        self._mappings = [{'port': _DEFAULT_WS_PORT, 'scheme': 'ws'}]
         self._pid_file = self._filesystem.join(self._runtime_path, '%s.pid' % self._name)
 
         self._port = _DEFAULT_WS_PORT
diff --git a/third_party/blink/tools/blinkpy/web_tests/servers/server_base.py b/third_party/blink/tools/blinkpy/web_tests/servers/server_base.py
index 23fc9859..c70afdb6 100644
--- a/third_party/blink/tools/blinkpy/web_tests/servers/server_base.py
+++ b/third_party/blink/tools/blinkpy/web_tests/servers/server_base.py
@@ -251,13 +251,14 @@
         for mapping in self._mappings:
             s = socket.socket()
             port = mapping['port']
+            scheme = mapping['scheme']
             try:
                 s.connect(('localhost', port))
-                _log.debug('Server running on %d', port)
+                _log.info('Server running on %s://localhost:%d', scheme, port)
             except IOError as error:
                 if error.errno not in (errno.ECONNREFUSED, errno.ECONNRESET):
                     raise
-                _log.debug('Server NOT running on %d: %s', port, error)
+                _log.debug('Server NOT running on %s://localhost:%d : %s', scheme, port, error)
                 return False
             finally:
                 s.close()
diff --git a/third_party/blink/tools/blinkpy/web_tests/servers/wptserve.py b/third_party/blink/tools/blinkpy/web_tests/servers/wptserve.py
index f1240aa..a94e337 100644
--- a/third_party/blink/tools/blinkpy/web_tests/servers/wptserve.py
+++ b/third_party/blink/tools/blinkpy/web_tests/servers/wptserve.py
@@ -24,11 +24,11 @@
         ws_port, wss_port = (9001, 9444)
         self._name = 'wptserve'
         self._log_prefixes = ('access_log', 'error_log')
-        self._mappings = [{'port': http_port},
-                          {'port': http_alt_port},
-                          {'port': https_port, 'sslcert': True},
-                          {'port': ws_port},
-                          {'port': wss_port, 'sslcert': True}]
+        self._mappings = [{'port': http_port, 'scheme': 'http'},
+                          {'port': http_alt_port, 'scheme': 'http'},
+                          {'port': https_port, 'scheme': 'https', 'sslcert': True},
+                          {'port': ws_port, 'scheme': 'ws'},
+                          {'port': wss_port, 'scheme': 'wss', 'sslcert': True}]
 
         # TODO(burnik): We can probably avoid PID files for WPT in the future.
         fs = self._filesystem
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=CompositeAfterPaint b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=CompositeAfterPaint
index 49fd068..7f0ea16 100644
--- a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=CompositeAfterPaint
+++ b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=CompositeAfterPaint
@@ -182,7 +182,6 @@
 Bug(none) fast/events/platform-wheelevent-paging-y-in-scrolling-page.html [ Failure ]
 Bug(none) fast/events/scroll-after-click-on-tab-index.html [ Failure ]
 Bug(none) fast/events/space-scroll-textinput-canceled.html [ Failure ]
-Bug(none) fast/events/touch/gesture/gesture-scroll-by-page.html [ Failure ]
 Bug(none) fast/webgl/pixelated.html [ Failure ]
 Bug(none) images/color-profile-reflection.html [ Crash Failure ]
 Bug(none) images/color-profile-svg-foreign-object.html [ Failure ]
@@ -468,15 +467,11 @@
 # Duplicated display item id of background of scrollable table cell.
 Bug(none) fast/table/overflowHidden.html [ Crash ]
 
-# These tests have incorrect layer positions.
-crbug.com/909749 fast/events/touch/compositor-touch-hit-rects-animation.html [ Failure ]
+# These tests have additional hit test rects. These may correct and simply due
+# to different layerization decisions, but this needs investigation.
 crbug.com/909749 fast/events/touch/compositor-touch-hit-rects-global.html [ Failure ]
-crbug.com/909749 fast/events/touch/compositor-touch-hit-rects-many.html [ Failure ]
-crbug.com/909749 fast/events/touch/compositor-touch-hit-rects-non-composited-scroll-overflow-with-handler.html [ Failure ]
 crbug.com/909749 fast/events/touch/compositor-touch-hit-rects-non-composited-scroll.html [ Failure ]
-crbug.com/909749 fast/events/touch/compositor-touch-hit-rects-scroll.html [ Failure ]
-crbug.com/909749 fast/events/touch/compositor-touch-hit-rects-squashing.html [ Failure ]
-crbug.com/909749 fast/events/touch/compositor-touch-hit-rects-with-negative-child.html [ Failure ]
-crbug.com/909749 fast/events/touch/compositor-touch-hit-rects.html [ Failure ]
+
+crbug.com/920224 fast/events/touch/gesture/gesture-scroll-by-page.html [ Failure ]
 
 Bug(none) synthetic_gestures/animated-wheel-tiny-delta.html [ Pass Failure ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 87ba537e..f0f5e13 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -4278,6 +4278,8 @@
 crbug.com/636055 external/wpt/css/css-multicol/multicol-span-all-margin-nested-002.xht [ Failure ]
 crbug.com/792446 external/wpt/css/css-multicol/multicol-span-float-001.xht [ Failure ]
 
+crbug.com/917554 external/wpt/upgrade-insecure-requests/worker-subresource-fetch-upgrade.https.html [ Crash ]
+
 # Different results on try bots and CQ, skipped to unblock wpt import.
 crbug.com/888443 external/wpt/css/cssom-view/scroll-behavior-default-css.html [ Skip ]
 crbug.com/888443 external/wpt/css/cssom-view/scroll-behavior-element.html [ Skip ]
@@ -4330,8 +4332,6 @@
 
 crbug.com/912362 external/wpt/web-animations/timing-model/timelines/timelines.html [ Failure ]
 
-crbug.com/912574 virtual/threaded/animations/responsive/transform-responsive-neutral-keyframe.html [ Crash ]
-
 # Decoding test timeout on Win7. Marked flaky to get imported in case it's flaky timeout everywhere.
 crbug.com/862938 external/wpt/encoding/textdecoder-fatal-single-byte.any.worker.html [ Pass Timeout ]
 
@@ -5808,9 +5808,6 @@
 # Flakiness in DTMF
 crbug.com/893112 virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCDTMFSender-ontonechange.https.html [ Pass Failure ]
 
-# Sheriff 2019-01-09
-crbug.com/920144 external/wpt/webrtc/RTCDtlsTransport-state.html [ Timeout Pass ]
-
 # Sheriff 2018-10-09
 crbug.com/806357 [ Linux ] virtual/threaded/fast/events/pointerevents/pinch/pointerevent_touch-action-pinch_zoom_touch.html [ Pass Failure ]
 crbug.com/893869 [ Linux ] css3/masking/mask-repeat-space-padding.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/css3/masking/mask-composite-source-in-repeat-spacing-expected.html b/third_party/blink/web_tests/css3/masking/mask-composite-source-in-repeat-spacing-expected.html
new file mode 100644
index 0000000..ffc1e19
--- /dev/null
+++ b/third_party/blink/web_tests/css3/masking/mask-composite-source-in-repeat-spacing-expected.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<div style="position: relative">
+  <div style="width: 100px; height: 100px; background-color: green; position: absolute"></div>
+  <div style="width: 100px; height: 100px; background-color: green; position: absolute; left: 110px"></div>
+</div>
diff --git a/third_party/blink/web_tests/css3/masking/mask-composite-source-in-repeat-spacing.html b/third_party/blink/web_tests/css3/masking/mask-composite-source-in-repeat-spacing.html
new file mode 100644
index 0000000..3901b92
--- /dev/null
+++ b/third_party/blink/web_tests/css3/masking/mask-composite-source-in-repeat-spacing.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<style>
+#target {
+  height: 150px;
+  width: 210px;
+  background-color: green;
+  -webkit-mask-image: url("../../images/resources/green-100.png"),
+                      url("../../images/resources/green-100.png");
+  -webkit-mask-size: 100px 100px;
+  -webkit-mask-repeat: space, space;
+  -webkit-mask-composite: source-in;
+  mask-image: url("../../images/resources/green-100.png"),
+              url("../../images/resources/green-100.png");
+  mask-size: 100px 100px;
+  mask-repeat: space, space;
+  mask-composite: intersect;
+}
+</style>
+<div id="target"></div>
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-record/MediaRecorder-disabled-tracks.https.html b/third_party/blink/web_tests/external/wpt/mediacapture-record/MediaRecorder-disabled-tracks.https.html
new file mode 100644
index 0000000..fe26e0c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mediacapture-record/MediaRecorder-disabled-tracks.https.html
@@ -0,0 +1,53 @@
+<!doctype html>
+<html>
+<head>
+  <title>MediaRecorder Disabled Tracks</title>
+  <link rel="help" href="https://w3c.github.io/mediacapture-record/MediaRecorder.html#mediarecorder">
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+</head>
+<script>
+
+  // This test verifies that MediaStream with disabled tracks can be correctly
+  // recorded. See crbug.com/878255 for more context.
+
+  [ ["video-only",  {video: true,  audio: false}],
+    ["audio-only",  {video: false, audio: true}],
+    ["audio-video", {video: true,  audio: true}]]
+  .forEach( function(args) {
+    async_test(function(test) {
+      let recorder;
+      const recorderOnDataAvailable = test.step_func(function(event) {
+        if (recorder.state != "recording")
+          return;
+
+        recorder.onstop = recorderOnStopExpected;
+        recorder.stop();
+      });
+
+      const recorderOnStopExpected = test.step_func_done();
+      const recorderOnStopUnexpected = test.unreached_func('Recording stopped.');
+      const recorderOnError = test.unreached_func('Recording error.');
+
+      const gotStream = test.step_func(function(stream) {
+        for (track in stream.getTracks())
+          track.enabled = false;
+
+        recorder = new MediaRecorder(stream);
+
+        assert_equals(recorder.state, "inactive");
+        recorder.ondataavailable = recorderOnDataAvailable;
+        recorder.onstop = recorderOnStopUnexpected;
+        recorder.onerror = recorderOnError;
+        recorder.start();
+
+        assert_equals(recorder.state, "recording");
+        recorder.requestData();
+      });
+
+      const onError = test.unreached_func('Error creating MediaStream.');
+      navigator.getUserMedia(args[1], gotStream, onError);
+    }, args[0]);
+  });
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/generic/tools/generate.py b/third_party/blink/web_tests/external/wpt/referrer-policy/generic/tools/generate.py
index 30e5b61..84aa9fe 100755
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/generic/tools/generate.py
+++ b/third_party/blink/web_tests/external/wpt/referrer-policy/generic/tools/generate.py
@@ -2,6 +2,7 @@
 
 from __future__ import print_function
 
+import copy
 import os, sys, json
 from common_paths import *
 import spec_validator
@@ -142,21 +143,33 @@
             exclusion_dict[excluded_selection_path] = True
 
     for spec in specification:
+        # Used to make entries with expansion="override" override preceding
+        # entries with the same |selection_path|.
+        output_dict = {}
+
         for spec_test_expansion in spec['test_expansion']:
             expansion = expand_test_expansion_pattern(spec_test_expansion,
                                                       test_expansion_schema)
             for selection in permute_expansion(expansion):
                 selection_path = selection_pattern % selection
                 if not selection_path in exclusion_dict:
-                    subresource_path = \
-                        spec_json["subresource_path"][selection["subresource"]]
-                    generate_selection(selection,
-                                       spec,
-                                       subresource_path,
-                                       html_template)
+                    if selection_path in output_dict:
+                        if spec_test_expansion['expansion'] != 'override':
+                            print("Error: %s's expansion is default but overrides %s" % (selection['name'], output_dict[selection_path]['name']))
+                            sys.exit(1)
+                    output_dict[selection_path] = copy.deepcopy(selection)
                 else:
                     print('Excluding selection:', selection_path)
 
+        for selection_path in output_dict:
+            selection = output_dict[selection_path]
+            subresource_path = \
+                spec_json["subresource_path"][selection["subresource"]]
+            generate_selection(selection,
+                           spec,
+                           subresource_path,
+                           html_template)
+
 
 def main(target):
     spec_json = load_spec_json();
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/a-tag/no-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/a-tag/no-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index 12903c4d..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/a-tag/no-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via a-tag using the attr-referrer
-                                 delivery method with no-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "attr-referrer",
-          "redirection": "no-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "a-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/document.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/iframe-tag/keep-origin-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/iframe-tag/keep-origin-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index ca0b0b1..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/iframe-tag/keep-origin-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via iframe-tag using the attr-referrer
-                                 delivery method with keep-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "attr-referrer",
-          "redirection": "keep-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "iframe-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/document.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/iframe-tag/no-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/iframe-tag/no-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index 19cf593..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/iframe-tag/no-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via iframe-tag using the attr-referrer
-                                 delivery method with no-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "attr-referrer",
-          "redirection": "no-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "iframe-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/document.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/iframe-tag/swap-origin-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/iframe-tag/swap-origin-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index 7745262..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/iframe-tag/swap-origin-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via iframe-tag using the attr-referrer
-                                 delivery method with swap-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "attr-referrer",
-          "redirection": "swap-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "iframe-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/document.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/iframe-tag/swap-origin-redirect/same-origin-upgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/iframe-tag/swap-origin-redirect/same-origin-upgrade.http.html
deleted file mode 100644
index 7745262..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/iframe-tag/swap-origin-redirect/same-origin-upgrade.http.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via iframe-tag using the attr-referrer
-                                 delivery method with swap-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "attr-referrer",
-          "redirection": "swap-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "iframe-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/document.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/img-tag/keep-origin-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/img-tag/keep-origin-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index f0c9e6fd..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/img-tag/keep-origin-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via img-tag using the attr-referrer
-                                 delivery method with keep-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "attr-referrer",
-          "redirection": "keep-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "img-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/image.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/img-tag/no-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/img-tag/no-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index 2aed178..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/img-tag/no-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via img-tag using the attr-referrer
-                                 delivery method with no-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "attr-referrer",
-          "redirection": "no-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "img-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/image.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/img-tag/swap-origin-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/img-tag/swap-origin-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index 4e18451..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/img-tag/swap-origin-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via img-tag using the attr-referrer
-                                 delivery method with swap-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "attr-referrer",
-          "redirection": "swap-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "img-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/image.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/img-tag/swap-origin-redirect/same-origin-upgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/img-tag/swap-origin-redirect/same-origin-upgrade.http.html
deleted file mode 100644
index 4e18451..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/img-tag/swap-origin-redirect/same-origin-upgrade.http.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via img-tag using the attr-referrer
-                                 delivery method with swap-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "attr-referrer",
-          "redirection": "swap-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "img-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/image.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/script-tag/keep-origin-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/script-tag/keep-origin-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index 9063bbd5..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/script-tag/keep-origin-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via script-tag using the attr-referrer
-                                 delivery method with keep-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "attr-referrer",
-          "redirection": "keep-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "script-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/script.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/script-tag/no-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/script-tag/no-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index 56bc742d..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/script-tag/no-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via script-tag using the attr-referrer
-                                 delivery method with no-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "attr-referrer",
-          "redirection": "no-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "script-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/script.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/script-tag/swap-origin-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/script-tag/swap-origin-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index 3209c5b..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/script-tag/swap-origin-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via script-tag using the attr-referrer
-                                 delivery method with swap-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "attr-referrer",
-          "redirection": "swap-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "script-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/script.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/script-tag/swap-origin-redirect/same-origin-upgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/script-tag/swap-origin-redirect/same-origin-upgrade.http.html
deleted file mode 100644
index 3209c5b..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/attr-referrer/same-origin/http-https/script-tag/swap-origin-redirect/same-origin-upgrade.http.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via script-tag using the attr-referrer
-                                 delivery method with swap-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "attr-referrer",
-          "redirection": "swap-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "script-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/script.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/a-tag/no-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/a-tag/no-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index 79e7506..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/a-tag/no-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <!-- No meta: Referrer policy delivered via HTTP headers. -->
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via a-tag using the http-rp
-                                 delivery method with no-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "http-rp",
-          "redirection": "no-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "a-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/document.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/a-tag/no-redirect/same-origin-downgrade.http.html.headers b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/a-tag/no-redirect/same-origin-downgrade.http.html.headers
deleted file mode 100644
index 9ce1de3..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/a-tag/no-redirect/same-origin-downgrade.http.html.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Referrer-Policy: origin-when-cross-origin
-Access-Control-Allow-Origin: *
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/keep-origin-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/keep-origin-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index ee78d6e..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/keep-origin-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <!-- No meta: Referrer policy delivered via HTTP headers. -->
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via fetch-request using the http-rp
-                                 delivery method with keep-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "http-rp",
-          "redirection": "keep-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "fetch-request",
-          "subresource_path": "/referrer-policy/generic/subresource/xhr.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/keep-origin-redirect/same-origin-downgrade.http.html.headers b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/keep-origin-redirect/same-origin-downgrade.http.html.headers
deleted file mode 100644
index 9ce1de3..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/keep-origin-redirect/same-origin-downgrade.http.html.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Referrer-Policy: origin-when-cross-origin
-Access-Control-Allow-Origin: *
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/no-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/no-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index 0019b7d1..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/no-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <!-- No meta: Referrer policy delivered via HTTP headers. -->
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via fetch-request using the http-rp
-                                 delivery method with no-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "http-rp",
-          "redirection": "no-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "fetch-request",
-          "subresource_path": "/referrer-policy/generic/subresource/xhr.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/no-redirect/same-origin-downgrade.http.html.headers b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/no-redirect/same-origin-downgrade.http.html.headers
deleted file mode 100644
index 9ce1de3..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/no-redirect/same-origin-downgrade.http.html.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Referrer-Policy: origin-when-cross-origin
-Access-Control-Allow-Origin: *
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/swap-origin-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/swap-origin-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index f4020bd..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/swap-origin-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <!-- No meta: Referrer policy delivered via HTTP headers. -->
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via fetch-request using the http-rp
-                                 delivery method with swap-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "http-rp",
-          "redirection": "swap-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "fetch-request",
-          "subresource_path": "/referrer-policy/generic/subresource/xhr.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/swap-origin-redirect/same-origin-downgrade.http.html.headers b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/swap-origin-redirect/same-origin-downgrade.http.html.headers
deleted file mode 100644
index 9ce1de3..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/swap-origin-redirect/same-origin-downgrade.http.html.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Referrer-Policy: origin-when-cross-origin
-Access-Control-Allow-Origin: *
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/swap-origin-redirect/same-origin-upgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/swap-origin-redirect/same-origin-upgrade.http.html
deleted file mode 100644
index f4020bd..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/swap-origin-redirect/same-origin-upgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <!-- No meta: Referrer policy delivered via HTTP headers. -->
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via fetch-request using the http-rp
-                                 delivery method with swap-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "http-rp",
-          "redirection": "swap-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "fetch-request",
-          "subresource_path": "/referrer-policy/generic/subresource/xhr.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/swap-origin-redirect/same-origin-upgrade.http.html.headers b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/swap-origin-redirect/same-origin-upgrade.http.html.headers
deleted file mode 100644
index 9ce1de3..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/swap-origin-redirect/same-origin-upgrade.http.html.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Referrer-Policy: origin-when-cross-origin
-Access-Control-Allow-Origin: *
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/keep-origin-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/keep-origin-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index 48dcc5d..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/keep-origin-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <!-- No meta: Referrer policy delivered via HTTP headers. -->
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via iframe-tag using the http-rp
-                                 delivery method with keep-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "http-rp",
-          "redirection": "keep-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "iframe-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/document.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/keep-origin-redirect/same-origin-downgrade.http.html.headers b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/keep-origin-redirect/same-origin-downgrade.http.html.headers
deleted file mode 100644
index 9ce1de3..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/keep-origin-redirect/same-origin-downgrade.http.html.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Referrer-Policy: origin-when-cross-origin
-Access-Control-Allow-Origin: *
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/no-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/no-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index 6cc4669..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/no-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <!-- No meta: Referrer policy delivered via HTTP headers. -->
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via iframe-tag using the http-rp
-                                 delivery method with no-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "http-rp",
-          "redirection": "no-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "iframe-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/document.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/no-redirect/same-origin-downgrade.http.html.headers b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/no-redirect/same-origin-downgrade.http.html.headers
deleted file mode 100644
index 9ce1de3..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/no-redirect/same-origin-downgrade.http.html.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Referrer-Policy: origin-when-cross-origin
-Access-Control-Allow-Origin: *
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/swap-origin-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/swap-origin-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index b1bacfe..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/swap-origin-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <!-- No meta: Referrer policy delivered via HTTP headers. -->
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via iframe-tag using the http-rp
-                                 delivery method with swap-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "http-rp",
-          "redirection": "swap-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "iframe-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/document.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/swap-origin-redirect/same-origin-downgrade.http.html.headers b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/swap-origin-redirect/same-origin-downgrade.http.html.headers
deleted file mode 100644
index 9ce1de3..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/swap-origin-redirect/same-origin-downgrade.http.html.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Referrer-Policy: origin-when-cross-origin
-Access-Control-Allow-Origin: *
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/swap-origin-redirect/same-origin-upgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/swap-origin-redirect/same-origin-upgrade.http.html
deleted file mode 100644
index b1bacfe..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/swap-origin-redirect/same-origin-upgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <!-- No meta: Referrer policy delivered via HTTP headers. -->
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via iframe-tag using the http-rp
-                                 delivery method with swap-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "http-rp",
-          "redirection": "swap-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "iframe-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/document.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/swap-origin-redirect/same-origin-upgrade.http.html.headers b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/swap-origin-redirect/same-origin-upgrade.http.html.headers
deleted file mode 100644
index 9ce1de3..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/swap-origin-redirect/same-origin-upgrade.http.html.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Referrer-Policy: origin-when-cross-origin
-Access-Control-Allow-Origin: *
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/img-tag/keep-origin-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/img-tag/keep-origin-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index 08156b6..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/img-tag/keep-origin-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <!-- No meta: Referrer policy delivered via HTTP headers. -->
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via img-tag using the http-rp
-                                 delivery method with keep-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "http-rp",
-          "redirection": "keep-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "img-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/image.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/img-tag/keep-origin-redirect/same-origin-downgrade.http.html.headers b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/img-tag/keep-origin-redirect/same-origin-downgrade.http.html.headers
deleted file mode 100644
index 9ce1de3..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/img-tag/keep-origin-redirect/same-origin-downgrade.http.html.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Referrer-Policy: origin-when-cross-origin
-Access-Control-Allow-Origin: *
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/img-tag/no-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/img-tag/no-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index ae1f449..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/img-tag/no-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <!-- No meta: Referrer policy delivered via HTTP headers. -->
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via img-tag using the http-rp
-                                 delivery method with no-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "http-rp",
-          "redirection": "no-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "img-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/image.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/img-tag/no-redirect/same-origin-downgrade.http.html.headers b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/img-tag/no-redirect/same-origin-downgrade.http.html.headers
deleted file mode 100644
index 9ce1de3..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/img-tag/no-redirect/same-origin-downgrade.http.html.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Referrer-Policy: origin-when-cross-origin
-Access-Control-Allow-Origin: *
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/img-tag/swap-origin-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/img-tag/swap-origin-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index 7b0f9d4..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/img-tag/swap-origin-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <!-- No meta: Referrer policy delivered via HTTP headers. -->
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via img-tag using the http-rp
-                                 delivery method with swap-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "http-rp",
-          "redirection": "swap-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "img-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/image.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/img-tag/swap-origin-redirect/same-origin-downgrade.http.html.headers b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/img-tag/swap-origin-redirect/same-origin-downgrade.http.html.headers
deleted file mode 100644
index 9ce1de3..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/img-tag/swap-origin-redirect/same-origin-downgrade.http.html.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Referrer-Policy: origin-when-cross-origin
-Access-Control-Allow-Origin: *
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/img-tag/swap-origin-redirect/same-origin-upgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/img-tag/swap-origin-redirect/same-origin-upgrade.http.html
deleted file mode 100644
index 7b0f9d4..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/img-tag/swap-origin-redirect/same-origin-upgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <!-- No meta: Referrer policy delivered via HTTP headers. -->
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via img-tag using the http-rp
-                                 delivery method with swap-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "http-rp",
-          "redirection": "swap-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "img-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/image.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/img-tag/swap-origin-redirect/same-origin-upgrade.http.html.headers b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/img-tag/swap-origin-redirect/same-origin-upgrade.http.html.headers
deleted file mode 100644
index 9ce1de3..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/img-tag/swap-origin-redirect/same-origin-upgrade.http.html.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Referrer-Policy: origin-when-cross-origin
-Access-Control-Allow-Origin: *
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/keep-origin-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/keep-origin-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index 633eb15..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/keep-origin-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <!-- No meta: Referrer policy delivered via HTTP headers. -->
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via script-tag using the http-rp
-                                 delivery method with keep-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "http-rp",
-          "redirection": "keep-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "script-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/script.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/keep-origin-redirect/same-origin-downgrade.http.html.headers b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/keep-origin-redirect/same-origin-downgrade.http.html.headers
deleted file mode 100644
index 9ce1de3..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/keep-origin-redirect/same-origin-downgrade.http.html.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Referrer-Policy: origin-when-cross-origin
-Access-Control-Allow-Origin: *
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/no-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/no-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index b7dd2d2..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/no-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <!-- No meta: Referrer policy delivered via HTTP headers. -->
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via script-tag using the http-rp
-                                 delivery method with no-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "http-rp",
-          "redirection": "no-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "script-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/script.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/no-redirect/same-origin-downgrade.http.html.headers b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/no-redirect/same-origin-downgrade.http.html.headers
deleted file mode 100644
index 9ce1de3..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/no-redirect/same-origin-downgrade.http.html.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Referrer-Policy: origin-when-cross-origin
-Access-Control-Allow-Origin: *
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/swap-origin-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/swap-origin-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index d968e31f..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/swap-origin-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <!-- No meta: Referrer policy delivered via HTTP headers. -->
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via script-tag using the http-rp
-                                 delivery method with swap-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "http-rp",
-          "redirection": "swap-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "script-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/script.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/swap-origin-redirect/same-origin-downgrade.http.html.headers b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/swap-origin-redirect/same-origin-downgrade.http.html.headers
deleted file mode 100644
index 9ce1de3..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/swap-origin-redirect/same-origin-downgrade.http.html.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Referrer-Policy: origin-when-cross-origin
-Access-Control-Allow-Origin: *
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/swap-origin-redirect/same-origin-upgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/swap-origin-redirect/same-origin-upgrade.http.html
deleted file mode 100644
index d968e31f..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/swap-origin-redirect/same-origin-upgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <!-- No meta: Referrer policy delivered via HTTP headers. -->
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via script-tag using the http-rp
-                                 delivery method with swap-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "http-rp",
-          "redirection": "swap-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "script-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/script.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/swap-origin-redirect/same-origin-upgrade.http.html.headers b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/swap-origin-redirect/same-origin-upgrade.http.html.headers
deleted file mode 100644
index 9ce1de3..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/swap-origin-redirect/same-origin-upgrade.http.html.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Referrer-Policy: origin-when-cross-origin
-Access-Control-Allow-Origin: *
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/keep-origin-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/keep-origin-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index cde3c4dc..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/keep-origin-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <!-- No meta: Referrer policy delivered via HTTP headers. -->
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via xhr-request using the http-rp
-                                 delivery method with keep-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "http-rp",
-          "redirection": "keep-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "xhr-request",
-          "subresource_path": "/referrer-policy/generic/subresource/xhr.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/keep-origin-redirect/same-origin-downgrade.http.html.headers b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/keep-origin-redirect/same-origin-downgrade.http.html.headers
deleted file mode 100644
index 9ce1de3..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/keep-origin-redirect/same-origin-downgrade.http.html.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Referrer-Policy: origin-when-cross-origin
-Access-Control-Allow-Origin: *
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/no-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/no-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index 69e0ac3f..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/no-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <!-- No meta: Referrer policy delivered via HTTP headers. -->
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via xhr-request using the http-rp
-                                 delivery method with no-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "http-rp",
-          "redirection": "no-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "xhr-request",
-          "subresource_path": "/referrer-policy/generic/subresource/xhr.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/no-redirect/same-origin-downgrade.http.html.headers b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/no-redirect/same-origin-downgrade.http.html.headers
deleted file mode 100644
index 9ce1de3..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/no-redirect/same-origin-downgrade.http.html.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Referrer-Policy: origin-when-cross-origin
-Access-Control-Allow-Origin: *
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/swap-origin-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/swap-origin-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index f9f5cbf..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/swap-origin-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <!-- No meta: Referrer policy delivered via HTTP headers. -->
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via xhr-request using the http-rp
-                                 delivery method with swap-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "http-rp",
-          "redirection": "swap-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "xhr-request",
-          "subresource_path": "/referrer-policy/generic/subresource/xhr.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/swap-origin-redirect/same-origin-downgrade.http.html.headers b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/swap-origin-redirect/same-origin-downgrade.http.html.headers
deleted file mode 100644
index 9ce1de3..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/swap-origin-redirect/same-origin-downgrade.http.html.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Referrer-Policy: origin-when-cross-origin
-Access-Control-Allow-Origin: *
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/swap-origin-redirect/same-origin-upgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/swap-origin-redirect/same-origin-upgrade.http.html
deleted file mode 100644
index f9f5cbf..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/swap-origin-redirect/same-origin-upgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <!-- No meta: Referrer policy delivered via HTTP headers. -->
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via xhr-request using the http-rp
-                                 delivery method with swap-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "http-rp",
-          "redirection": "swap-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "xhr-request",
-          "subresource_path": "/referrer-policy/generic/subresource/xhr.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/swap-origin-redirect/same-origin-upgrade.http.html.headers b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/swap-origin-redirect/same-origin-upgrade.http.html.headers
deleted file mode 100644
index 9ce1de3..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/swap-origin-redirect/same-origin-upgrade.http.html.headers
+++ /dev/null
@@ -1,2 +0,0 @@
-Referrer-Policy: origin-when-cross-origin
-Access-Control-Allow-Origin: *
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/a-tag/no-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/a-tag/no-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index 2111a0cf..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/a-tag/no-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <meta name="referrer" content="origin-when-cross-origin">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via a-tag using the meta-referrer
-                                 delivery method with no-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "meta-referrer",
-          "redirection": "no-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "a-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/document.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/fetch-request/keep-origin-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/fetch-request/keep-origin-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index f0adebf..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/fetch-request/keep-origin-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <meta name="referrer" content="origin-when-cross-origin">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via fetch-request using the meta-referrer
-                                 delivery method with keep-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "meta-referrer",
-          "redirection": "keep-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "fetch-request",
-          "subresource_path": "/referrer-policy/generic/subresource/xhr.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/fetch-request/no-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/fetch-request/no-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index 4d5714f8..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/fetch-request/no-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <meta name="referrer" content="origin-when-cross-origin">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via fetch-request using the meta-referrer
-                                 delivery method with no-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "meta-referrer",
-          "redirection": "no-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "fetch-request",
-          "subresource_path": "/referrer-policy/generic/subresource/xhr.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/fetch-request/swap-origin-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/fetch-request/swap-origin-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index 6578bd1..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/fetch-request/swap-origin-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <meta name="referrer" content="origin-when-cross-origin">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via fetch-request using the meta-referrer
-                                 delivery method with swap-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "meta-referrer",
-          "redirection": "swap-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "fetch-request",
-          "subresource_path": "/referrer-policy/generic/subresource/xhr.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/fetch-request/swap-origin-redirect/same-origin-upgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/fetch-request/swap-origin-redirect/same-origin-upgrade.http.html
deleted file mode 100644
index 6578bd1..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/fetch-request/swap-origin-redirect/same-origin-upgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <meta name="referrer" content="origin-when-cross-origin">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via fetch-request using the meta-referrer
-                                 delivery method with swap-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "meta-referrer",
-          "redirection": "swap-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "fetch-request",
-          "subresource_path": "/referrer-policy/generic/subresource/xhr.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/iframe-tag/keep-origin-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/iframe-tag/keep-origin-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index 9480247..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/iframe-tag/keep-origin-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <meta name="referrer" content="origin-when-cross-origin">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via iframe-tag using the meta-referrer
-                                 delivery method with keep-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "meta-referrer",
-          "redirection": "keep-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "iframe-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/document.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/iframe-tag/no-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/iframe-tag/no-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index a4298049..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/iframe-tag/no-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <meta name="referrer" content="origin-when-cross-origin">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via iframe-tag using the meta-referrer
-                                 delivery method with no-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "meta-referrer",
-          "redirection": "no-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "iframe-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/document.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/iframe-tag/swap-origin-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/iframe-tag/swap-origin-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index 548e63ea..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/iframe-tag/swap-origin-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <meta name="referrer" content="origin-when-cross-origin">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via iframe-tag using the meta-referrer
-                                 delivery method with swap-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "meta-referrer",
-          "redirection": "swap-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "iframe-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/document.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/iframe-tag/swap-origin-redirect/same-origin-upgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/iframe-tag/swap-origin-redirect/same-origin-upgrade.http.html
deleted file mode 100644
index 548e63ea..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/iframe-tag/swap-origin-redirect/same-origin-upgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <meta name="referrer" content="origin-when-cross-origin">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via iframe-tag using the meta-referrer
-                                 delivery method with swap-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "meta-referrer",
-          "redirection": "swap-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "iframe-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/document.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/img-tag/keep-origin-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/img-tag/keep-origin-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index 32da6f1e..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/img-tag/keep-origin-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <meta name="referrer" content="origin-when-cross-origin">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via img-tag using the meta-referrer
-                                 delivery method with keep-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "meta-referrer",
-          "redirection": "keep-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "img-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/image.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/img-tag/no-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/img-tag/no-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index c7367f7..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/img-tag/no-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <meta name="referrer" content="origin-when-cross-origin">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via img-tag using the meta-referrer
-                                 delivery method with no-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "meta-referrer",
-          "redirection": "no-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "img-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/image.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/img-tag/swap-origin-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/img-tag/swap-origin-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index a0e33c7..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/img-tag/swap-origin-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <meta name="referrer" content="origin-when-cross-origin">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via img-tag using the meta-referrer
-                                 delivery method with swap-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "meta-referrer",
-          "redirection": "swap-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "img-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/image.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/img-tag/swap-origin-redirect/same-origin-upgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/img-tag/swap-origin-redirect/same-origin-upgrade.http.html
deleted file mode 100644
index a0e33c7..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/img-tag/swap-origin-redirect/same-origin-upgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <meta name="referrer" content="origin-when-cross-origin">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via img-tag using the meta-referrer
-                                 delivery method with swap-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "meta-referrer",
-          "redirection": "swap-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "img-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/image.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/script-tag/keep-origin-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/script-tag/keep-origin-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index c80a3c7e..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/script-tag/keep-origin-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <meta name="referrer" content="origin-when-cross-origin">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via script-tag using the meta-referrer
-                                 delivery method with keep-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "meta-referrer",
-          "redirection": "keep-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "script-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/script.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/script-tag/no-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/script-tag/no-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index e7e65e1..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/script-tag/no-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <meta name="referrer" content="origin-when-cross-origin">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via script-tag using the meta-referrer
-                                 delivery method with no-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "meta-referrer",
-          "redirection": "no-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "script-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/script.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/script-tag/swap-origin-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/script-tag/swap-origin-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index 42ecdbc..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/script-tag/swap-origin-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <meta name="referrer" content="origin-when-cross-origin">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via script-tag using the meta-referrer
-                                 delivery method with swap-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "meta-referrer",
-          "redirection": "swap-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "script-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/script.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/script-tag/swap-origin-redirect/same-origin-upgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/script-tag/swap-origin-redirect/same-origin-upgrade.http.html
deleted file mode 100644
index 42ecdbc..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/script-tag/swap-origin-redirect/same-origin-upgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <meta name="referrer" content="origin-when-cross-origin">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via script-tag using the meta-referrer
-                                 delivery method with swap-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "meta-referrer",
-          "redirection": "swap-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "script-tag",
-          "subresource_path": "/referrer-policy/generic/subresource/script.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/xhr-request/keep-origin-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/xhr-request/keep-origin-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index c6dcc471..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/xhr-request/keep-origin-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <meta name="referrer" content="origin-when-cross-origin">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via xhr-request using the meta-referrer
-                                 delivery method with keep-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "meta-referrer",
-          "redirection": "keep-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "xhr-request",
-          "subresource_path": "/referrer-policy/generic/subresource/xhr.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/xhr-request/no-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/xhr-request/no-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index 53505ab..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/xhr-request/no-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <meta name="referrer" content="origin-when-cross-origin">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via xhr-request using the meta-referrer
-                                 delivery method with no-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "meta-referrer",
-          "redirection": "no-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "xhr-request",
-          "subresource_path": "/referrer-policy/generic/subresource/xhr.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/xhr-request/swap-origin-redirect/same-origin-downgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/xhr-request/swap-origin-redirect/same-origin-downgrade.http.html
deleted file mode 100644
index 76b1b2d..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/xhr-request/swap-origin-redirect/same-origin-downgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <meta name="referrer" content="origin-when-cross-origin">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via xhr-request using the meta-referrer
-                                 delivery method with swap-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "meta-referrer",
-          "redirection": "swap-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "xhr-request",
-          "subresource_path": "/referrer-policy/generic/subresource/xhr.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/xhr-request/swap-origin-redirect/same-origin-upgrade.http.html b/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/xhr-request/swap-origin-redirect/same-origin-upgrade.http.html
deleted file mode 100644
index 76b1b2d..0000000
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/origin-when-cross-origin/meta-referrer/same-origin/http-https/xhr-request/swap-origin-redirect/same-origin-upgrade.http.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<!-- DO NOT EDIT! Generated by referrer-policy/generic/tools/generate.py using referrer-policy/generic/template/test.release.html.template. -->
-<html>
-  <head>
-    <title>Referrer-Policy: Referrer Policy is set to 'origin-when-cross-origin'</title>
-    <meta name="description" content="Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.">
-    <meta name="referrer" content="origin-when-cross-origin">
-    <link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
-    <link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin">
-    <meta name="assert" content="The referrer URL is origin when a
-                                 document served over http requires an https
-                                 sub-resource via xhr-request using the meta-referrer
-                                 delivery method with swap-origin-redirect and when
-                                 the target request is same-origin.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <!-- TODO(kristijanburnik): Minify and merge both: -->
-    <script src="/referrer-policy/generic/common.js"></script>
-    <script src="/referrer-policy/generic/referrer-policy-test-case.js?pipe=sub"></script>
-  </head>
-  <body>
-    <script>
-      ReferrerPolicyTestCase(
-        {
-          "referrer_policy": "origin-when-cross-origin",
-          "delivery_method": "meta-referrer",
-          "redirection": "swap-origin-redirect",
-          "origin": "same-origin",
-          "source_protocol": "http",
-          "target_protocol": "https",
-          "subresource": "xhr-request",
-          "subresource_path": "/referrer-policy/generic/subresource/xhr.py",
-          "referrer_url": "origin"
-        },
-        document.querySelector("meta[name=assert]").content,
-        new SanityChecker()
-      ).start();
-      </script>
-    <div id="log"></div>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/spec.src.json b/third_party/blink/web_tests/external/wpt/referrer-policy/spec.src.json
index f96eaf59..97fbad6 100644
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/spec.src.json
+++ b/third_party/blink/web_tests/external/wpt/referrer-policy/spec.src.json
@@ -242,8 +242,8 @@
         {
           "name": "same-origin-downgrade",
           "expansion": "default",
-          "source_protocol": "http",
-          "target_protocol": "https",
+          "source_protocol": "https",
+          "target_protocol": "http",
           "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"],
           "redirection": "*",
           "origin": "same-origin",
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/spec_json.js b/third_party/blink/web_tests/external/wpt/referrer-policy/spec_json.js
index 32a32fbc..d178c9f 100644
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/spec_json.js
+++ b/third_party/blink/web_tests/external/wpt/referrer-policy/spec_json.js
@@ -1 +1 @@
-var SPEC_JSON = {"subresource_path": {"img-tag": "/referrer-policy/generic/subresource/image.py", "xhr-request": "/referrer-policy/generic/subresource/xhr.py", "fetch-request": "/referrer-policy/generic/subresource/xhr.py", "module-worker": "/referrer-policy/generic/subresource/worker.py", "a-tag": "/referrer-policy/generic/subresource/document.py", "area-tag": "/referrer-policy/generic/subresource/document.py", "iframe-tag": "/referrer-policy/generic/subresource/document.py", "shared-worker": "/referrer-policy/generic/subresource/shared-worker.py", "worker-request": "/referrer-policy/generic/subresource/worker.py", "script-tag": "/referrer-policy/generic/subresource/script.py"}, "test_expansion_schema": {"origin": ["same-origin", "cross-origin"], "subresource": ["iframe-tag", "img-tag", "script-tag", "a-tag", "area-tag", "xhr-request", "worker-request", "module-worker", "shared-worker", "fetch-request"], "target_protocol": ["http", "https"], "expansion": ["default", "override"], "delivery_method": ["http-rp", "meta-referrer", "attr-referrer", "rel-noreferrer"], "redirection": ["no-redirect", "keep-origin-redirect", "swap-origin-redirect"], "referrer_url": ["omitted", "origin", "stripped-referrer"], "source_protocol": ["http", "https"]}, "specification": [{"specification_url": "https://w3c.github.io/webappsec-referrer-policy/#referrer-policies", "referrer_policy": null, "title": "Referrer Policy is not explicitly defined", "test_expansion": [{"origin": "*", "name": "insecure-protocol", "target_protocol": "http", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "stripped-referrer", "source_protocol": "http", "subresource": "*"}, {"origin": "*", "name": "upgrade-protocol", "target_protocol": "https", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "stripped-referrer", "source_protocol": "http", "subresource": "*"}, {"origin": "*", "name": "downgrade-protocol", "target_protocol": "http", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "omitted", "source_protocol": "https", "subresource": "*"}, {"origin": "*", "name": "secure-protocol", "target_protocol": "https", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "stripped-referrer", "source_protocol": "https", "subresource": "*"}], "name": "unset-referrer-policy", "description": "Check that referrer URL follows no-referrer-when-downgrade policy when no explicit Referrer Policy is set."}, {"specification_url": "https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-no-referrer", "referrer_policy": "no-referrer", "title": "Referrer Policy is set to 'no-referrer'", "test_expansion": [{"origin": "*", "name": "generic", "target_protocol": "*", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "omitted", "source_protocol": "*", "subresource": "*"}], "name": "no-referrer", "description": "Check that sub-resource never gets the referrer URL."}, {"specification_url": "https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-no-referrer-when-downgrade", "referrer_policy": "no-referrer-when-downgrade", "title": "Referrer Policy is set to 'no-referrer-when-downgrade'", "test_expansion": [{"origin": "*", "name": "insecure-protocol", "target_protocol": "http", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "stripped-referrer", "source_protocol": "http", "subresource": "*"}, {"origin": "*", "name": "upgrade-protocol", "target_protocol": "https", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "stripped-referrer", "source_protocol": "http", "subresource": "*"}, {"origin": "*", "name": "downgrade-protocol", "target_protocol": "http", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "omitted", "source_protocol": "https", "subresource": "*"}, {"origin": "*", "name": "secure-protocol", "target_protocol": "https", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "stripped-referrer", "source_protocol": "https", "subresource": "*"}], "name": "no-referrer-when-downgrade", "description": "Check that non a priori insecure subresource gets the full Referrer URL. A priori insecure subresource gets no referrer information."}, {"specification_url": "https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin", "referrer_policy": "origin", "title": "Referrer Policy is set to 'origin'", "test_expansion": [{"origin": "*", "name": "generic", "target_protocol": "*", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "origin", "source_protocol": "*", "subresource": "*"}], "name": "origin", "description": "Check that all subresources in all casses get only the origin portion of the referrer URL."}, {"specification_url": "https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-same-origin", "referrer_policy": "same-origin", "title": "Referrer Policy is set to 'same-origin'", "test_expansion": [{"origin": "same-origin", "name": "same-origin-insecure", "target_protocol": "http", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "stripped-referrer", "source_protocol": "http", "subresource": "*"}, {"origin": "same-origin", "name": "same-origin-secure-default", "target_protocol": "https", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "stripped-referrer", "source_protocol": "https", "subresource": "*"}, {"origin": "same-origin", "name": "same-origin-insecure", "target_protocol": "*", "expansion": "override", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "swap-origin-redirect", "referrer_url": "omitted", "source_protocol": "*", "subresource": "*"}, {"origin": "cross-origin", "name": "cross-origin", "target_protocol": "*", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "omitted", "source_protocol": "*", "subresource": "*"}], "name": "same-origin", "description": "Check that cross-origin subresources get no referrer information and same-origin get the stripped referrer URL."}, {"specification_url": "https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin", "referrer_policy": "origin-when-cross-origin", "title": "Referrer Policy is set to 'origin-when-cross-origin'", "test_expansion": [{"origin": "same-origin", "name": "same-origin-insecure", "target_protocol": "http", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "stripped-referrer", "source_protocol": "http", "subresource": "*"}, {"origin": "same-origin", "name": "same-origin-secure-default", "target_protocol": "https", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "stripped-referrer", "source_protocol": "https", "subresource": "*"}, {"origin": "same-origin", "name": "same-origin-upgrade", "target_protocol": "https", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "origin", "source_protocol": "http", "subresource": "*"}, {"origin": "same-origin", "name": "same-origin-downgrade", "target_protocol": "https", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "origin", "source_protocol": "http", "subresource": "*"}, {"origin": "same-origin", "name": "same-origin-insecure", "target_protocol": "*", "expansion": "override", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "swap-origin-redirect", "referrer_url": "origin", "source_protocol": "*", "subresource": "*"}, {"origin": "cross-origin", "name": "cross-origin", "target_protocol": "*", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "origin", "source_protocol": "*", "subresource": "*"}], "name": "origin-when-cross-origin", "description": "Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL."}, {"specification_url": "https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-strict-origin", "referrer_policy": "strict-origin", "title": "Referrer Policy is set to 'strict-origin'", "test_expansion": [{"origin": "*", "name": "insecure-protocol", "target_protocol": "http", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "origin", "source_protocol": "http", "subresource": "*"}, {"origin": "*", "name": "upgrade-protocol", "target_protocol": "https", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "origin", "source_protocol": "http", "subresource": "*"}, {"origin": "*", "name": "downgrade-protocol", "target_protocol": "http", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "omitted", "source_protocol": "https", "subresource": "*"}, {"origin": "*", "name": "secure-protocol", "target_protocol": "https", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "origin", "source_protocol": "https", "subresource": "*"}], "name": "strict-origin", "description": "Check that non a priori insecure subresource gets only the origin portion of the referrer URL. A priori insecure subresource gets no referrer information."}, {"specification_url": "https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-strict-origin-when-cross-origin", "referrer_policy": "strict-origin-when-cross-origin", "title": "Referrer Policy is set to 'strict-origin-when-cross-origin'", "test_expansion": [{"origin": "same-origin", "name": "same-insecure", "target_protocol": "http", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "stripped-referrer", "source_protocol": "http", "subresource": "*"}, {"origin": "same-origin", "name": "same-insecure", "target_protocol": "http", "expansion": "override", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "swap-origin-redirect", "referrer_url": "origin", "source_protocol": "http", "subresource": "*"}, {"origin": "cross-origin", "name": "cross-insecure", "target_protocol": "http", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "origin", "source_protocol": "http", "subresource": "*"}, {"origin": "*", "name": "upgrade-protocol", "target_protocol": "https", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "origin", "source_protocol": "http", "subresource": "*"}, {"origin": "*", "name": "downgrade-protocol", "target_protocol": "http", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "omitted", "source_protocol": "https", "subresource": "*"}, {"origin": "same-origin", "name": "same-secure", "target_protocol": "https", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "stripped-referrer", "source_protocol": "https", "subresource": "*"}, {"origin": "same-origin", "name": "same-secure", "target_protocol": "https", "expansion": "override", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "swap-origin-redirect", "referrer_url": "origin", "source_protocol": "https", "subresource": "*"}, {"origin": "cross-origin", "name": "cross-secure", "target_protocol": "https", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "origin", "source_protocol": "https", "subresource": "*"}], "name": "strict-origin-when-cross-origin", "description": "Check that a priori insecure subresource gets no referrer information. Otherwise, cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL."}, {"specification_url": "https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-unsafe-url", "referrer_policy": "unsafe-url", "title": "Referrer Policy is set to 'unsafe-url'", "test_expansion": [{"origin": "*", "name": "generic", "target_protocol": "*", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "stripped-referrer", "source_protocol": "*", "subresource": "*"}], "name": "unsafe-url", "description": "Check that all sub-resources get the stripped referrer URL."}], "referrer_policy_schema": [null, "no-referrer", "no-referrer-when-downgrade", "same-origin", "origin", "origin-when-cross-origin", "strict-origin", "strict-origin-when-cross-origin", "unsafe-url"], "excluded_tests": [{"origin": "cross-origin", "name": "cross-origin-workers", "target_protocol": "*", "expansion": "*", "delivery_method": "*", "redirection": "*", "referrer_url": "*", "source_protocol": "*", "subresource": ["worker-request", "module-worker", "shared-worker"]}, {"origin": "*", "name": "upgraded-protocol-workers", "target_protocol": "https", "expansion": "*", "delivery_method": "*", "redirection": "*", "referrer_url": "*", "source_protocol": "http", "subresource": ["worker-request", "module-worker", "shared-worker"]}, {"origin": "*", "name": "mixed-content-insecure-subresources", "target_protocol": "http", "expansion": "*", "delivery_method": "*", "redirection": "*", "referrer_url": "*", "source_protocol": "https", "subresource": "*"}, {"origin": "*", "name": "elements-not-supporting-attr-referrer", "target_protocol": "*", "expansion": "*", "delivery_method": ["attr-referrer"], "redirection": "*", "referrer_url": "*", "source_protocol": "*", "subresource": ["xhr-request", "worker-request", "module-worker", "shared-worker", "fetch-request"]}, {"origin": "*", "name": "elements-not-supporting-rel-noreferrer", "target_protocol": "*", "expansion": "*", "delivery_method": ["rel-noreferrer"], "redirection": "*", "referrer_url": "*", "source_protocol": "*", "subresource": ["iframe-tag", "img-tag", "script-tag", "xhr-request", "worker-request", "module-worker", "shared-worker", "fetch-request", "area-tag"]}, {"origin": "*", "name": "area-tag", "target_protocol": "*", "expansion": "*", "delivery_method": "*", "redirection": "*", "referrer_url": "*", "source_protocol": "*", "subresource": "area-tag"}, {"origin": "*", "name": "worker-requests-with-swap-origin-redirect", "target_protocol": "*", "expansion": "*", "delivery_method": "*", "redirection": "swap-origin-redirect", "referrer_url": "*", "source_protocol": "*", "subresource": ["worker-request", "module-worker", "shared-worker"]}, {"origin": "*", "name": "overhead-for-redirection", "target_protocol": "*", "expansion": "*", "delivery_method": "*", "redirection": ["keep-origin-redirect", "swap-origin-redirect"], "referrer_url": "*", "source_protocol": "*", "subresource": ["a-tag", "area-tag"]}, {"origin": "*", "name": "source-https-unsupported-by-web-platform-tests-runners", "target_protocol": "*", "expansion": "*", "delivery_method": "*", "redirection": "*", "referrer_url": "*", "source_protocol": "https", "subresource": "*"}]};
+var SPEC_JSON = {"subresource_path": {"img-tag": "/referrer-policy/generic/subresource/image.py", "xhr-request": "/referrer-policy/generic/subresource/xhr.py", "fetch-request": "/referrer-policy/generic/subresource/xhr.py", "module-worker": "/referrer-policy/generic/subresource/worker.py", "a-tag": "/referrer-policy/generic/subresource/document.py", "area-tag": "/referrer-policy/generic/subresource/document.py", "iframe-tag": "/referrer-policy/generic/subresource/document.py", "shared-worker": "/referrer-policy/generic/subresource/shared-worker.py", "worker-request": "/referrer-policy/generic/subresource/worker.py", "script-tag": "/referrer-policy/generic/subresource/script.py"}, "test_expansion_schema": {"origin": ["same-origin", "cross-origin"], "subresource": ["iframe-tag", "img-tag", "script-tag", "a-tag", "area-tag", "xhr-request", "worker-request", "module-worker", "shared-worker", "fetch-request"], "target_protocol": ["http", "https"], "expansion": ["default", "override"], "delivery_method": ["http-rp", "meta-referrer", "attr-referrer", "rel-noreferrer"], "redirection": ["no-redirect", "keep-origin-redirect", "swap-origin-redirect"], "referrer_url": ["omitted", "origin", "stripped-referrer"], "source_protocol": ["http", "https"]}, "specification": [{"specification_url": "https://w3c.github.io/webappsec-referrer-policy/#referrer-policies", "referrer_policy": null, "title": "Referrer Policy is not explicitly defined", "test_expansion": [{"origin": "*", "name": "insecure-protocol", "target_protocol": "http", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "stripped-referrer", "source_protocol": "http", "subresource": "*"}, {"origin": "*", "name": "upgrade-protocol", "target_protocol": "https", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "stripped-referrer", "source_protocol": "http", "subresource": "*"}, {"origin": "*", "name": "downgrade-protocol", "target_protocol": "http", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "omitted", "source_protocol": "https", "subresource": "*"}, {"origin": "*", "name": "secure-protocol", "target_protocol": "https", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "stripped-referrer", "source_protocol": "https", "subresource": "*"}], "name": "unset-referrer-policy", "description": "Check that referrer URL follows no-referrer-when-downgrade policy when no explicit Referrer Policy is set."}, {"specification_url": "https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-no-referrer", "referrer_policy": "no-referrer", "title": "Referrer Policy is set to 'no-referrer'", "test_expansion": [{"origin": "*", "name": "generic", "target_protocol": "*", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "omitted", "source_protocol": "*", "subresource": "*"}], "name": "no-referrer", "description": "Check that sub-resource never gets the referrer URL."}, {"specification_url": "https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-no-referrer-when-downgrade", "referrer_policy": "no-referrer-when-downgrade", "title": "Referrer Policy is set to 'no-referrer-when-downgrade'", "test_expansion": [{"origin": "*", "name": "insecure-protocol", "target_protocol": "http", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "stripped-referrer", "source_protocol": "http", "subresource": "*"}, {"origin": "*", "name": "upgrade-protocol", "target_protocol": "https", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "stripped-referrer", "source_protocol": "http", "subresource": "*"}, {"origin": "*", "name": "downgrade-protocol", "target_protocol": "http", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "omitted", "source_protocol": "https", "subresource": "*"}, {"origin": "*", "name": "secure-protocol", "target_protocol": "https", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "stripped-referrer", "source_protocol": "https", "subresource": "*"}], "name": "no-referrer-when-downgrade", "description": "Check that non a priori insecure subresource gets the full Referrer URL. A priori insecure subresource gets no referrer information."}, {"specification_url": "https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin", "referrer_policy": "origin", "title": "Referrer Policy is set to 'origin'", "test_expansion": [{"origin": "*", "name": "generic", "target_protocol": "*", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "origin", "source_protocol": "*", "subresource": "*"}], "name": "origin", "description": "Check that all subresources in all casses get only the origin portion of the referrer URL."}, {"specification_url": "https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-same-origin", "referrer_policy": "same-origin", "title": "Referrer Policy is set to 'same-origin'", "test_expansion": [{"origin": "same-origin", "name": "same-origin-insecure", "target_protocol": "http", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "stripped-referrer", "source_protocol": "http", "subresource": "*"}, {"origin": "same-origin", "name": "same-origin-secure-default", "target_protocol": "https", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "stripped-referrer", "source_protocol": "https", "subresource": "*"}, {"origin": "same-origin", "name": "same-origin-insecure", "target_protocol": "*", "expansion": "override", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "swap-origin-redirect", "referrer_url": "omitted", "source_protocol": "*", "subresource": "*"}, {"origin": "cross-origin", "name": "cross-origin", "target_protocol": "*", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "omitted", "source_protocol": "*", "subresource": "*"}], "name": "same-origin", "description": "Check that cross-origin subresources get no referrer information and same-origin get the stripped referrer URL."}, {"specification_url": "https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin", "referrer_policy": "origin-when-cross-origin", "title": "Referrer Policy is set to 'origin-when-cross-origin'", "test_expansion": [{"origin": "same-origin", "name": "same-origin-insecure", "target_protocol": "http", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "stripped-referrer", "source_protocol": "http", "subresource": "*"}, {"origin": "same-origin", "name": "same-origin-secure-default", "target_protocol": "https", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "stripped-referrer", "source_protocol": "https", "subresource": "*"}, {"origin": "same-origin", "name": "same-origin-upgrade", "target_protocol": "https", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "origin", "source_protocol": "http", "subresource": "*"}, {"origin": "same-origin", "name": "same-origin-downgrade", "target_protocol": "http", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "origin", "source_protocol": "https", "subresource": "*"}, {"origin": "same-origin", "name": "same-origin-insecure", "target_protocol": "*", "expansion": "override", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "swap-origin-redirect", "referrer_url": "origin", "source_protocol": "*", "subresource": "*"}, {"origin": "cross-origin", "name": "cross-origin", "target_protocol": "*", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "origin", "source_protocol": "*", "subresource": "*"}], "name": "origin-when-cross-origin", "description": "Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL."}, {"specification_url": "https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-strict-origin", "referrer_policy": "strict-origin", "title": "Referrer Policy is set to 'strict-origin'", "test_expansion": [{"origin": "*", "name": "insecure-protocol", "target_protocol": "http", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "origin", "source_protocol": "http", "subresource": "*"}, {"origin": "*", "name": "upgrade-protocol", "target_protocol": "https", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "origin", "source_protocol": "http", "subresource": "*"}, {"origin": "*", "name": "downgrade-protocol", "target_protocol": "http", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "omitted", "source_protocol": "https", "subresource": "*"}, {"origin": "*", "name": "secure-protocol", "target_protocol": "https", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "origin", "source_protocol": "https", "subresource": "*"}], "name": "strict-origin", "description": "Check that non a priori insecure subresource gets only the origin portion of the referrer URL. A priori insecure subresource gets no referrer information."}, {"specification_url": "https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-strict-origin-when-cross-origin", "referrer_policy": "strict-origin-when-cross-origin", "title": "Referrer Policy is set to 'strict-origin-when-cross-origin'", "test_expansion": [{"origin": "same-origin", "name": "same-insecure", "target_protocol": "http", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "stripped-referrer", "source_protocol": "http", "subresource": "*"}, {"origin": "same-origin", "name": "same-insecure", "target_protocol": "http", "expansion": "override", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "swap-origin-redirect", "referrer_url": "origin", "source_protocol": "http", "subresource": "*"}, {"origin": "cross-origin", "name": "cross-insecure", "target_protocol": "http", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "origin", "source_protocol": "http", "subresource": "*"}, {"origin": "*", "name": "upgrade-protocol", "target_protocol": "https", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "origin", "source_protocol": "http", "subresource": "*"}, {"origin": "*", "name": "downgrade-protocol", "target_protocol": "http", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "omitted", "source_protocol": "https", "subresource": "*"}, {"origin": "same-origin", "name": "same-secure", "target_protocol": "https", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "stripped-referrer", "source_protocol": "https", "subresource": "*"}, {"origin": "same-origin", "name": "same-secure", "target_protocol": "https", "expansion": "override", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "swap-origin-redirect", "referrer_url": "origin", "source_protocol": "https", "subresource": "*"}, {"origin": "cross-origin", "name": "cross-secure", "target_protocol": "https", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "origin", "source_protocol": "https", "subresource": "*"}], "name": "strict-origin-when-cross-origin", "description": "Check that a priori insecure subresource gets no referrer information. Otherwise, cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL."}, {"specification_url": "https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-unsafe-url", "referrer_policy": "unsafe-url", "title": "Referrer Policy is set to 'unsafe-url'", "test_expansion": [{"origin": "*", "name": "generic", "target_protocol": "*", "expansion": "default", "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], "redirection": "*", "referrer_url": "stripped-referrer", "source_protocol": "*", "subresource": "*"}], "name": "unsafe-url", "description": "Check that all sub-resources get the stripped referrer URL."}], "referrer_policy_schema": [null, "no-referrer", "no-referrer-when-downgrade", "same-origin", "origin", "origin-when-cross-origin", "strict-origin", "strict-origin-when-cross-origin", "unsafe-url"], "excluded_tests": [{"origin": "cross-origin", "name": "cross-origin-workers", "target_protocol": "*", "expansion": "*", "delivery_method": "*", "redirection": "*", "referrer_url": "*", "source_protocol": "*", "subresource": ["worker-request", "module-worker", "shared-worker"]}, {"origin": "*", "name": "upgraded-protocol-workers", "target_protocol": "https", "expansion": "*", "delivery_method": "*", "redirection": "*", "referrer_url": "*", "source_protocol": "http", "subresource": ["worker-request", "module-worker", "shared-worker"]}, {"origin": "*", "name": "mixed-content-insecure-subresources", "target_protocol": "http", "expansion": "*", "delivery_method": "*", "redirection": "*", "referrer_url": "*", "source_protocol": "https", "subresource": "*"}, {"origin": "*", "name": "elements-not-supporting-attr-referrer", "target_protocol": "*", "expansion": "*", "delivery_method": ["attr-referrer"], "redirection": "*", "referrer_url": "*", "source_protocol": "*", "subresource": ["xhr-request", "worker-request", "module-worker", "shared-worker", "fetch-request"]}, {"origin": "*", "name": "elements-not-supporting-rel-noreferrer", "target_protocol": "*", "expansion": "*", "delivery_method": ["rel-noreferrer"], "redirection": "*", "referrer_url": "*", "source_protocol": "*", "subresource": ["iframe-tag", "img-tag", "script-tag", "xhr-request", "worker-request", "module-worker", "shared-worker", "fetch-request", "area-tag"]}, {"origin": "*", "name": "area-tag", "target_protocol": "*", "expansion": "*", "delivery_method": "*", "redirection": "*", "referrer_url": "*", "source_protocol": "*", "subresource": "area-tag"}, {"origin": "*", "name": "worker-requests-with-swap-origin-redirect", "target_protocol": "*", "expansion": "*", "delivery_method": "*", "redirection": "swap-origin-redirect", "referrer_url": "*", "source_protocol": "*", "subresource": ["worker-request", "module-worker", "shared-worker"]}, {"origin": "*", "name": "overhead-for-redirection", "target_protocol": "*", "expansion": "*", "delivery_method": "*", "redirection": ["keep-origin-redirect", "swap-origin-redirect"], "referrer_url": "*", "source_protocol": "*", "subresource": ["a-tag", "area-tag"]}, {"origin": "*", "name": "source-https-unsupported-by-web-platform-tests-runners", "target_protocol": "*", "expansion": "*", "delivery_method": "*", "redirection": "*", "referrer_url": "*", "source_protocol": "https", "subresource": "*"}]};
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/animation-worklet-import-upgrade.https.html b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/animation-worklet-import-upgrade.https.html
new file mode 100644
index 0000000..38e89eb8b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/animation-worklet-import-upgrade.https.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<!-- Generated by wpt/upgrade-insecure-requests/support/generate.py -->
+<title>Upgrade Insecure Requests: animation-worklet.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./support/testharness-helper.sub.js"></script>
+<script src="/mixed-content/generic/common.js"></script>
+
+<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
+</head>
+<body>
+<script>
+const tests = generateModuleImportTests(ResourceType.WORKLET, false);
+tests.forEach(test => testMap['animation-worklet'](test));
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/animation-worklet-redirect-upgrade.https.html b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/animation-worklet-redirect-upgrade.https.html
new file mode 100644
index 0000000..87d0d2aa
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/animation-worklet-redirect-upgrade.https.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<!-- Generated by wpt/upgrade-insecure-requests/support/generate.py -->
+<title>Upgrade Insecure Requests: animation-worklet.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./support/testharness-helper.sub.js"></script>
+<script src="/mixed-content/generic/common.js"></script>
+
+<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
+</head>
+<body>
+<script>
+const tests = generateRedirectTests(ResourceType.WORKLET, false);
+tests.forEach(test => testMap['animation-worklet'](test));
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/animation-worklet-upgrade.https.html b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/animation-worklet-upgrade.https.html
new file mode 100644
index 0000000..8a68b2d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/animation-worklet-upgrade.https.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<!-- Generated by wpt/upgrade-insecure-requests/support/generate.py -->
+<title>Upgrade Insecure Requests: animation-worklet.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./support/testharness-helper.sub.js"></script>
+<script src="/mixed-content/generic/common.js"></script>
+
+<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
+</head>
+<body>
+<script>
+const tests = generateTests(ResourceType.WORKLET, false);
+tests.forEach(test => testMap['animation-worklet'](test));
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/audio-worklet-import-upgrade.https.html b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/audio-worklet-import-upgrade.https.html
new file mode 100644
index 0000000..56d72596
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/audio-worklet-import-upgrade.https.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<!-- Generated by wpt/upgrade-insecure-requests/support/generate.py -->
+<title>Upgrade Insecure Requests: audio-worklet.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./support/testharness-helper.sub.js"></script>
+<script src="/mixed-content/generic/common.js"></script>
+
+<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
+</head>
+<body>
+<script>
+const tests = generateModuleImportTests(ResourceType.WORKLET, false);
+tests.forEach(test => testMap['audio-worklet'](test));
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/audio-worklet-redirect-upgrade.https.html b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/audio-worklet-redirect-upgrade.https.html
new file mode 100644
index 0000000..2e1984f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/audio-worklet-redirect-upgrade.https.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<!-- Generated by wpt/upgrade-insecure-requests/support/generate.py -->
+<title>Upgrade Insecure Requests: audio-worklet.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./support/testharness-helper.sub.js"></script>
+<script src="/mixed-content/generic/common.js"></script>
+
+<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
+</head>
+<body>
+<script>
+const tests = generateRedirectTests(ResourceType.WORKLET, false);
+tests.forEach(test => testMap['audio-worklet'](test));
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/audio-worklet-upgrade.https.html b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/audio-worklet-upgrade.https.html
new file mode 100644
index 0000000..91d52adb
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/audio-worklet-upgrade.https.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<!-- Generated by wpt/upgrade-insecure-requests/support/generate.py -->
+<title>Upgrade Insecure Requests: audio-worklet.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./support/testharness-helper.sub.js"></script>
+<script src="/mixed-content/generic/common.js"></script>
+
+<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
+</head>
+<body>
+<script>
+const tests = generateTests(ResourceType.WORKLET, false);
+tests.forEach(test => testMap['audio-worklet'](test));
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/iframe-redirect-upgrade.https.html b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/iframe-redirect-upgrade.https.html
index 9a79825a..7204749 100644
--- a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/iframe-redirect-upgrade.https.html
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/iframe-redirect-upgrade.https.html
@@ -1,37 +1,19 @@
 <!DOCTYPE html>
 <html>
 <head>
-<title>Upgrade Insecure Requests: IFrames.</title>
+<!-- Generated by wpt/upgrade-insecure-requests/support/generate.py -->
+<title>Upgrade Insecure Requests: iframe.</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="./support/testharness-helper.sub.js"></script>
+<script src="/mixed-content/generic/common.js"></script>
 
 <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
 </head>
 <body>
 <script>
-var tests = [
-  generateRedirect(Host.SAME_ORIGIN, Protocol.INSECURE, generateURL(Host.SAME_ORIGIN, Protocol.INSECURE, ResourceType.FRAME)),
-  generateRedirect(Host.SAME_ORIGIN, Protocol.INSECURE, generateURL(Host.SAME_ORIGIN, Protocol.SECURE, ResourceType.FRAME)),
-  generateRedirect(Host.SAME_ORIGIN, Protocol.INSECURE, generateURL(Host.CROSS_ORIGIN, Protocol.INSECURE, ResourceType.FRAME)),
-  generateRedirect(Host.SAME_ORIGIN, Protocol.INSECURE, generateURL(Host.CROSS_ORIGIN, Protocol.SECURE, ResourceType.FRAME)),
-  generateRedirect(Host.SAME_ORIGIN, Protocol.SECURE, generateURL(Host.SAME_ORIGIN, Protocol.INSECURE, ResourceType.FRAME)),
-  generateRedirect(Host.SAME_ORIGIN, Protocol.SECURE, generateURL(Host.SAME_ORIGIN, Protocol.SECURE, ResourceType.FRAME)),
-  generateRedirect(Host.SAME_ORIGIN, Protocol.SECURE, generateURL(Host.CROSS_ORIGIN, Protocol.INSECURE, ResourceType.FRAME)),
-  generateRedirect(Host.SAME_ORIGIN, Protocol.SECURE, generateURL(Host.CROSS_ORIGIN, Protocol.SECURE, ResourceType.FRAME)),
-  generateRedirect(Host.CROSS_ORIGIN, Protocol.INSECURE, generateURL(Host.SAME_ORIGIN, Protocol.INSECURE, ResourceType.FRAME)),
-  generateRedirect(Host.CROSS_ORIGIN, Protocol.INSECURE, generateURL(Host.SAME_ORIGIN, Protocol.SECURE, ResourceType.FRAME)),
-  generateRedirect(Host.CROSS_ORIGIN, Protocol.INSECURE, generateURL(Host.CROSS_ORIGIN, Protocol.INSECURE, ResourceType.FRAME)),
-  generateRedirect(Host.CROSS_ORIGIN, Protocol.INSECURE, generateURL(Host.CROSS_ORIGIN, Protocol.SECURE, ResourceType.FRAME)),
-  generateRedirect(Host.CROSS_ORIGIN, Protocol.SECURE, generateURL(Host.SAME_ORIGIN, Protocol.INSECURE, ResourceType.FRAME)),
-  generateRedirect(Host.CROSS_ORIGIN, Protocol.SECURE, generateURL(Host.SAME_ORIGIN, Protocol.SECURE, ResourceType.FRAME)),
-  generateRedirect(Host.CROSS_ORIGIN, Protocol.SECURE, generateURL(Host.CROSS_ORIGIN, Protocol.INSECURE, ResourceType.FRAME)),
-  generateRedirect(Host.CROSS_ORIGIN, Protocol.SECURE, generateURL(Host.CROSS_ORIGIN, Protocol.SECURE, ResourceType.FRAME)),
-];
-
-tests.forEach(test => {
-  async_test(t => assert_frame_loads(t, test.url), test.name);
-});
+const tests = generateRedirectTests(ResourceType.FRAME, false);
+tests.forEach(test => testMap['iframe'](test));
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/iframe-upgrade.https.html b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/iframe-upgrade.https.html
index 8c4bb37..60c5aaaf 100644
--- a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/iframe-upgrade.https.html
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/iframe-upgrade.https.html
@@ -1,25 +1,19 @@
 <!DOCTYPE html>
 <html>
 <head>
-<title>Upgrade Insecure Requests: IFrames.</title>
+<!-- Generated by wpt/upgrade-insecure-requests/support/generate.py -->
+<title>Upgrade Insecure Requests: iframe.</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="./support/testharness-helper.sub.js"></script>
+<script src="/mixed-content/generic/common.js"></script>
 
 <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
 </head>
 <body>
 <script>
-var tests = [
-  generateURL(Host.SAME_ORIGIN, Protocol.INSECURE, ResourceType.FRAME),
-  generateURL(Host.SAME_ORIGIN, Protocol.SECURE, ResourceType.FRAME),
-  generateURL(Host.CROSS_ORIGIN, Protocol.INSECURE, ResourceType.FRAME),
-  generateURL(Host.CROSS_ORIGIN, Protocol.SECURE, ResourceType.FRAME),
-];
-
-tests.forEach(test => {
-  async_test(t => assert_frame_loads(t, test.url), test.name);
-});
+const tests = generateTests(ResourceType.FRAME, false);
+tests.forEach(test => testMap['iframe'](test));
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/image-redirect-upgrade.https.html b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/image-redirect-upgrade.https.html
index 5ed75109d..69c3f14 100644
--- a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/image-redirect-upgrade.https.html
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/image-redirect-upgrade.https.html
@@ -1,39 +1,19 @@
 <!DOCTYPE html>
 <html>
 <head>
-<title>Upgrade Insecure Requests: Redirected Images.</title>
+<!-- Generated by wpt/upgrade-insecure-requests/support/generate.py -->
+<title>Upgrade Insecure Requests: image.</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="./support/testharness-helper.sub.js"></script>
+<script src="/mixed-content/generic/common.js"></script>
 
 <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
 </head>
 <body>
 <script>
-var tests = [
-  generateRedirect(Host.SAME_ORIGIN, Protocol.INSECURE, generateURL(Host.SAME_ORIGIN, Protocol.INSECURE, ResourceType.IMAGE)),
-  generateRedirect(Host.SAME_ORIGIN, Protocol.INSECURE, generateURL(Host.SAME_ORIGIN, Protocol.SECURE, ResourceType.IMAGE)),
-  generateRedirect(Host.SAME_ORIGIN, Protocol.INSECURE, generateURL(Host.CROSS_ORIGIN, Protocol.INSECURE, ResourceType.IMAGE)),
-  generateRedirect(Host.SAME_ORIGIN, Protocol.INSECURE, generateURL(Host.CROSS_ORIGIN, Protocol.SECURE, ResourceType.IMAGE)),
-  generateRedirect(Host.SAME_ORIGIN, Protocol.SECURE, generateURL(Host.SAME_ORIGIN, Protocol.INSECURE, ResourceType.IMAGE)),
-  generateRedirect(Host.SAME_ORIGIN, Protocol.SECURE, generateURL(Host.SAME_ORIGIN, Protocol.SECURE, ResourceType.IMAGE)),
-  generateRedirect(Host.SAME_ORIGIN, Protocol.SECURE, generateURL(Host.CROSS_ORIGIN, Protocol.INSECURE, ResourceType.IMAGE)),
-  generateRedirect(Host.SAME_ORIGIN, Protocol.SECURE, generateURL(Host.CROSS_ORIGIN, Protocol.SECURE, ResourceType.IMAGE)),
-  generateRedirect(Host.CROSS_ORIGIN, Protocol.INSECURE, generateURL(Host.SAME_ORIGIN, Protocol.INSECURE, ResourceType.IMAGE)),
-  generateRedirect(Host.CROSS_ORIGIN, Protocol.INSECURE, generateURL(Host.SAME_ORIGIN, Protocol.SECURE, ResourceType.IMAGE)),
-  generateRedirect(Host.CROSS_ORIGIN, Protocol.INSECURE, generateURL(Host.CROSS_ORIGIN, Protocol.INSECURE, ResourceType.IMAGE)),
-  generateRedirect(Host.CROSS_ORIGIN, Protocol.INSECURE, generateURL(Host.CROSS_ORIGIN, Protocol.SECURE, ResourceType.IMAGE)),
-  generateRedirect(Host.CROSS_ORIGIN, Protocol.SECURE, generateURL(Host.SAME_ORIGIN, Protocol.INSECURE, ResourceType.IMAGE)),
-  generateRedirect(Host.CROSS_ORIGIN, Protocol.SECURE, generateURL(Host.SAME_ORIGIN, Protocol.SECURE, ResourceType.IMAGE)),
-  generateRedirect(Host.CROSS_ORIGIN, Protocol.SECURE, generateURL(Host.CROSS_ORIGIN, Protocol.INSECURE, ResourceType.IMAGE)),
-  generateRedirect(Host.CROSS_ORIGIN, Protocol.SECURE, generateURL(Host.CROSS_ORIGIN, Protocol.SECURE, ResourceType.IMAGE)),
-];
-
-tests.forEach(test => {
-  async_test(t => assert_image_loads(t, test.url, 64, 168), test.name);
-  async_test(t => assert_image_loads_in_srcdoc(t, test.url, 64, 168), test.name + " in <iframe srcdoc>");
-  async_test(t => assert_image_loads_in_blank(t, test.url, 64, 168), test.name + " in <iframe>");
-});
+const tests = generateRedirectTests(ResourceType.IMAGE, false);
+tests.forEach(test => testMap['image'](test));
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/image-upgrade.https.html b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/image-upgrade.https.html
index 515c674..5ab6306e 100644
--- a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/image-upgrade.https.html
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/image-upgrade.https.html
@@ -1,27 +1,19 @@
 <!DOCTYPE html>
 <html>
 <head>
-<title>Upgrade Insecure Requests: Images.</title>
+<!-- Generated by wpt/upgrade-insecure-requests/support/generate.py -->
+<title>Upgrade Insecure Requests: image.</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="./support/testharness-helper.sub.js"></script>
+<script src="/mixed-content/generic/common.js"></script>
 
 <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
 </head>
 <body>
 <script>
-var tests = [
-  generateURL(Host.SAME_ORIGIN, Protocol.INSECURE, ResourceType.IMAGE),
-  generateURL(Host.SAME_ORIGIN, Protocol.SECURE, ResourceType.IMAGE),
-  generateURL(Host.CROSS_ORIGIN, Protocol.INSECURE, ResourceType.IMAGE),
-  generateURL(Host.CROSS_ORIGIN, Protocol.SECURE, ResourceType.IMAGE),
-];
-
-tests.forEach(test => {
-  async_test(t => assert_image_loads(t, test.url, 64, 168), test.name);
-  async_test(t => assert_image_loads_in_srcdoc(t, test.url, 64, 168), test.name + " in <iframe srcdoc>");
-  async_test(t => assert_image_loads_in_blank(t, test.url, 64, 168), test.name + " in <iframe>");
-});
+const tests = generateTests(ResourceType.IMAGE, false);
+tests.forEach(test => testMap['image'](test));
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/layout-worklet-import-upgrade.https.html b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/layout-worklet-import-upgrade.https.html
new file mode 100644
index 0000000..ffc73af
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/layout-worklet-import-upgrade.https.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<!-- Generated by wpt/upgrade-insecure-requests/support/generate.py -->
+<title>Upgrade Insecure Requests: layout-worklet.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./support/testharness-helper.sub.js"></script>
+<script src="/mixed-content/generic/common.js"></script>
+
+<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
+</head>
+<body>
+<script>
+const tests = generateModuleImportTests(ResourceType.WORKLET, false);
+tests.forEach(test => testMap['layout-worklet'](test));
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/layout-worklet-redirect-upgrade.https.html b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/layout-worklet-redirect-upgrade.https.html
new file mode 100644
index 0000000..c9c9531
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/layout-worklet-redirect-upgrade.https.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<!-- Generated by wpt/upgrade-insecure-requests/support/generate.py -->
+<title>Upgrade Insecure Requests: layout-worklet.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./support/testharness-helper.sub.js"></script>
+<script src="/mixed-content/generic/common.js"></script>
+
+<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
+</head>
+<body>
+<script>
+const tests = generateRedirectTests(ResourceType.WORKLET, false);
+tests.forEach(test => testMap['layout-worklet'](test));
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/layout-worklet-upgrade.https.html b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/layout-worklet-upgrade.https.html
new file mode 100644
index 0000000..7cbdff39
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/layout-worklet-upgrade.https.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<!-- Generated by wpt/upgrade-insecure-requests/support/generate.py -->
+<title>Upgrade Insecure Requests: layout-worklet.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./support/testharness-helper.sub.js"></script>
+<script src="/mixed-content/generic/common.js"></script>
+
+<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
+</head>
+<body>
+<script>
+const tests = generateTests(ResourceType.WORKLET, false);
+tests.forEach(test => testMap['layout-worklet'](test));
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/module-worker-import-upgrade.https.html b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/module-worker-import-upgrade.https.html
new file mode 100644
index 0000000..0522051
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/module-worker-import-upgrade.https.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<!-- Generated by wpt/upgrade-insecure-requests/support/generate.py -->
+<title>Upgrade Insecure Requests: module-worker.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./support/testharness-helper.sub.js"></script>
+<script src="/mixed-content/generic/common.js"></script>
+
+<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
+</head>
+<body>
+<script>
+const tests = generateModuleImportTests(ResourceType.WORKER, true);
+tests.forEach(test => testMap['module-worker'](test));
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/module-worker-redirect-upgrade.https-expected.txt b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/module-worker-redirect-upgrade.https-expected.txt
new file mode 100644
index 0000000..0d9e1b9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/module-worker-redirect-upgrade.https-expected.txt
@@ -0,0 +1,7 @@
+This is a testharness.js-based test.
+PASS secure/same-origin => secure/same-origin worker
+FAIL insecure/same-origin => secure/same-origin worker promise_test: Unhandled rejection with value: object "SecurityError: Failed to construct 'Worker': Script at 'http://web-platform.test:8444/upgrade-insecure-requests/support/redirect-cors.py?location=https%3A%2F%2Fweb-platform.test%3A8444%2Fupgrade-insecure-requests%2Fsupport%2Fworker.js' cannot be accessed from origin 'https://web-platform.test:8444'."
+PASS secure/same-origin => insecure/same-origin worker
+FAIL insecure/same-origin => insecure/same-origin worker promise_test: Unhandled rejection with value: object "SecurityError: Failed to construct 'Worker': Script at 'http://web-platform.test:8444/upgrade-insecure-requests/support/redirect-cors.py?location=http%3A%2F%2Fweb-platform.test%3A8444%2Fupgrade-insecure-requests%2Fsupport%2Fworker.js' cannot be accessed from origin 'https://web-platform.test:8444'."
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/module-worker-redirect-upgrade.https.html b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/module-worker-redirect-upgrade.https.html
new file mode 100644
index 0000000..132663e3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/module-worker-redirect-upgrade.https.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<!-- Generated by wpt/upgrade-insecure-requests/support/generate.py -->
+<title>Upgrade Insecure Requests: module-worker.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./support/testharness-helper.sub.js"></script>
+<script src="/mixed-content/generic/common.js"></script>
+
+<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
+</head>
+<body>
+<script>
+const tests = generateRedirectTests(ResourceType.WORKER, true);
+tests.forEach(test => testMap['module-worker'](test));
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/module-worker-upgrade.https-expected.txt b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/module-worker-upgrade.https-expected.txt
new file mode 100644
index 0000000..5132c62
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/module-worker-upgrade.https-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+PASS secure/same-origin worker
+FAIL insecure/same-origin worker promise_test: Unhandled rejection with value: object "SecurityError: Failed to construct 'Worker': Script at 'http://web-platform.test:8444/upgrade-insecure-requests/support/worker.js' cannot be accessed from origin 'https://web-platform.test:8444'."
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/module-worker-upgrade.https.html b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/module-worker-upgrade.https.html
new file mode 100644
index 0000000..a4be5ed
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/module-worker-upgrade.https.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<!-- Generated by wpt/upgrade-insecure-requests/support/generate.py -->
+<title>Upgrade Insecure Requests: module-worker.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./support/testharness-helper.sub.js"></script>
+<script src="/mixed-content/generic/common.js"></script>
+
+<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
+</head>
+<body>
+<script>
+const tests = generateTests(ResourceType.WORKER, true);
+tests.forEach(test => testMap['module-worker'](test));
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/paint-worklet-import-upgrade.https.html b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/paint-worklet-import-upgrade.https.html
new file mode 100644
index 0000000..96d68e2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/paint-worklet-import-upgrade.https.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<!-- Generated by wpt/upgrade-insecure-requests/support/generate.py -->
+<title>Upgrade Insecure Requests: paint-worklet.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./support/testharness-helper.sub.js"></script>
+<script src="/mixed-content/generic/common.js"></script>
+
+<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
+</head>
+<body>
+<script>
+const tests = generateModuleImportTests(ResourceType.WORKLET, false);
+tests.forEach(test => testMap['paint-worklet'](test));
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/paint-worklet-redirect-upgrade.https.html b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/paint-worklet-redirect-upgrade.https.html
new file mode 100644
index 0000000..0675c6a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/paint-worklet-redirect-upgrade.https.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<!-- Generated by wpt/upgrade-insecure-requests/support/generate.py -->
+<title>Upgrade Insecure Requests: paint-worklet.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./support/testharness-helper.sub.js"></script>
+<script src="/mixed-content/generic/common.js"></script>
+
+<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
+</head>
+<body>
+<script>
+const tests = generateRedirectTests(ResourceType.WORKLET, false);
+tests.forEach(test => testMap['paint-worklet'](test));
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/paint-worklet-upgrade.https.html b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/paint-worklet-upgrade.https.html
new file mode 100644
index 0000000..b4f1aac0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/paint-worklet-upgrade.https.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<!-- Generated by wpt/upgrade-insecure-requests/support/generate.py -->
+<title>Upgrade Insecure Requests: paint-worklet.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./support/testharness-helper.sub.js"></script>
+<script src="/mixed-content/generic/common.js"></script>
+
+<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
+</head>
+<body>
+<script>
+const tests = generateTests(ResourceType.WORKLET, false);
+tests.forEach(test => testMap['paint-worklet'](test));
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/generate.py b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/generate.py
new file mode 100644
index 0000000..2676d0c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/generate.py
@@ -0,0 +1,48 @@
+# Usage: execute
+# $ python support/generate.py
+# at wpt/upgrade-insecure-requests/.
+#
+# Note: Some tests (link-upgrade.sub.https.html and
+# websocket-upgrade.https.html) are not covered by this generator script.
+
+template = '''<!DOCTYPE html>
+<html>
+<head>
+<!-- Generated by wpt/upgrade-insecure-requests/support/generate.py -->
+<title>Upgrade Insecure Requests: %(name)s.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./support/testharness-helper.sub.js"></script>
+<script src="/mixed-content/generic/common.js"></script>
+
+<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
+</head>
+<body>
+<script>
+const tests = %(generatorName)s(ResourceType.%(resourceType)s, %(sameOriginOnly)s);
+tests.forEach(test => testMap['%(name)s'](test));
+</script>
+</body>
+</html>
+'''
+
+# resourceType is |ResourceType| in testharness-helper.sub.js.
+for name, resourceType in [
+  ('image', 'IMAGE'), ('iframe', 'FRAME'),
+  ('animation-worklet', 'WORKLET'), ('audio-worklet', 'WORKLET'),
+  ('layout-worklet', 'WORKLET'), ('paint-worklet', 'WORKLET'),
+  ('worker', 'WORKER'),
+  ('module-worker', 'WORKER'),
+  ('worker-subresource-xhr', 'IMAGE'),
+  ('worker-subresource-fetch', 'IMAGE')]:
+  sameOriginOnly = 'true' if resourceType == 'WORKER' else 'false'
+  types = [('', 'generateTests'), ('-redirect', 'generateRedirectTests')]
+  if name == 'module-worker' or resourceType == 'WORKLET':
+    types.append(('-import', 'generateModuleImportTests'))
+  for typeName, generatorName in types:
+    with open('%s%s-upgrade.https.html' % (name, typeName), 'w') as html_file:
+      html_file.write(template % {
+          'name': name,
+          'resourceType': resourceType,
+          'generatorName': generatorName,
+          'sameOriginOnly': sameOriginOnly})
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/pass.png.headers b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/pass.png.headers
new file mode 100644
index 0000000..cb762eff
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/pass.png.headers
@@ -0,0 +1 @@
+Access-Control-Allow-Origin: *
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/redirect-cors.py b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/redirect-cors.py
new file mode 100644
index 0000000..56493e00
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/redirect-cors.py
@@ -0,0 +1,5 @@
+def main(request, response):
+    response.status = 302
+    location = request.GET.first("location")
+    response.headers.set("Location", location)
+    response.headers.set("Access-Control-Allow-Origin", "*")
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/testharness-helper.sub.js b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/testharness-helper.sub.js
index 8bf576c..8b58eb9 100644
--- a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/testharness-helper.sub.js
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/testharness-helper.sub.js
@@ -11,6 +11,8 @@
 const ResourceType = {
   IMAGE: "image",
   FRAME: "frame",
+  WORKER: "worker",
+  WORKLET: "worklet",
   WEBSOCKET: "websocket",
 };
 
@@ -31,6 +33,10 @@
     url.port = {{ports[wss][0]}};
     url.protocol = protocol == Protocol.INSECURE ? "ws" : "wss";
     url.pathname = "echo";
+  } else if (resourceType == ResourceType.WORKER) {
+    url.pathname += "worker.js";
+  } else if (resourceType == ResourceType.WORKLET) {
+    url.pathname = "/worklets/resources/empty-worklet-script-with-cors-header.js";
   }
   return {
     name: protocol + "/" + host + " "  + resourceType,
@@ -38,16 +44,66 @@
   };
 }
 
-function generateRedirect(host, protocol, target) {
-  var url = new URL("http://{{host}}:{{ports[https][0]}}/common/redirect.py?location=" + encodeURIComponent(target.url));
+function generateRedirect(host, protocol, finalTest) {
+  var url = new URL("http://{{host}}:{{ports[https][0]}}/upgrade-insecure-requests/support/redirect-cors.py?location=" + encodeURIComponent(finalTest.url));
   url.protocol = protocol == Protocol.INSECURE ? "http" : "https";
   url.hostname = host == Host.SAME_ORIGIN ? "{{host}}" : "{{domains[天気の良い日]}}";
   return {
-    name: protocol + "/" + host + " => " + target.name,
+    name: protocol + "/" + host + " => " + finalTest.name,
     url: url.toString()
   };
 }
 
+function generateDataImport(finalTest) {
+  return {
+    name: "data: =(import)=> " + finalTest.name,
+    url: workerUrlThatImports(finalTest.url)
+  };
+}
+
+function generateTests(target, sameOriginOnly) {
+  var tests = [];
+
+  tests.push(generateURL(Host.SAME_ORIGIN, Protocol.SECURE, target));
+  tests.push(generateURL(Host.SAME_ORIGIN, Protocol.INSECURE, target));
+  if (!sameOriginOnly) {
+    tests.push(generateURL(Host.CROSS_ORIGIN, Protocol.SECURE, target));
+    tests.push(generateURL(Host.CROSS_ORIGIN, Protocol.INSECURE, target));
+  }
+
+  return tests;
+}
+
+function generateRedirectTests(target, sameOriginOnly) {
+  const finalTests = generateTests(target, sameOriginOnly);
+  var tests = [];
+
+  for (const finalTest of finalTests) {
+    tests.push(generateRedirect(Host.SAME_ORIGIN, Protocol.SECURE, finalTest));
+    tests.push(generateRedirect(Host.SAME_ORIGIN, Protocol.INSECURE, finalTest));
+    if (!sameOriginOnly) {
+      tests.push(generateRedirect(Host.CROSS_ORIGIN, Protocol.SECURE, finalTest));
+      tests.push(generateRedirect(Host.CROSS_ORIGIN, Protocol.INSECURE, finalTest));
+    }
+  }
+  return tests;
+}
+
+function generateModuleImportTests(target, sameOriginOnly) {
+  // |sameOriginOnly| is ignored as the top-level URL (generateDataImport())
+  // is always same-origin (as it is data: URL) and import()ed URLs (URLs in
+  // finalTests) can be cross-origin.
+
+  var finalTests = generateTests(target, false);
+  finalTests = finalTests.concat(generateRedirectTests(target, false));
+
+  var tests = [];
+  for (const finalTest of finalTests) {
+    tests.push(generateDataImport(finalTest));
+  }
+  return tests;
+}
+
 function assert_image_loads(test, url, height, width) {
   var i = document.createElement('img');
   i.onload = test.step_func_done(_ => {
@@ -113,3 +169,42 @@
   });
   w.onclose = test.unreached_func("WebSocket should not close before open is called.");
 }
+
+const testMap = {
+  "image": test => {
+    async_test(t => assert_image_loads(t, test.url, 64, 168), test.name);
+    async_test(t => assert_image_loads_in_srcdoc(t, test.url, 64, 168), test.name + " in <iframe srcdoc>");
+    async_test(t => assert_image_loads_in_blank(t, test.url, 64, 168), test.name + " in <iframe>");
+  },
+  "iframe":
+    test => async_test(t => assert_frame_loads(t, test.url), test.name),
+
+  "worker":
+    test => promise_test(
+        () => requestViaDedicatedWorker(test.url, {}),
+        test.name),
+
+  "module-worker":
+    test => promise_test(
+        () => requestViaDedicatedWorker(test.url, {type: "module"}),
+        test.name),
+
+  "worker-subresource-fetch":
+    test => promise_test(
+        () => requestViaDedicatedWorker(dedicatedWorkerUrlThatFetches(test.url),
+                                        {}),
+        test.name),
+
+  "audio-worklet":
+    test => promise_test(
+        () => requestViaWorklet('audio', test.url), test.name),
+  "animation-worklet":
+    test => promise_test(
+        () => requestViaWorklet('animation', test.url), test.name),
+  "layout-worklet":
+    test => promise_test(
+        () => requestViaWorklet('layout', test.url), test.name),
+  "paint-worklet":
+    test => promise_test(
+        () => requestViaWorklet('paint', test.url), test.name),
+};
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/worker.js b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/worker.js
new file mode 100644
index 0000000..7e2168bc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/worker.js
@@ -0,0 +1 @@
+postMessage('done');
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/worker.js.headers b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/worker.js.headers
new file mode 100644
index 0000000..cb762eff
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/support/worker.js.headers
@@ -0,0 +1 @@
+Access-Control-Allow-Origin: *
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-redirect-upgrade.https-expected.txt b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-redirect-upgrade.https-expected.txt
new file mode 100644
index 0000000..0d9e1b9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-redirect-upgrade.https-expected.txt
@@ -0,0 +1,7 @@
+This is a testharness.js-based test.
+PASS secure/same-origin => secure/same-origin worker
+FAIL insecure/same-origin => secure/same-origin worker promise_test: Unhandled rejection with value: object "SecurityError: Failed to construct 'Worker': Script at 'http://web-platform.test:8444/upgrade-insecure-requests/support/redirect-cors.py?location=https%3A%2F%2Fweb-platform.test%3A8444%2Fupgrade-insecure-requests%2Fsupport%2Fworker.js' cannot be accessed from origin 'https://web-platform.test:8444'."
+PASS secure/same-origin => insecure/same-origin worker
+FAIL insecure/same-origin => insecure/same-origin worker promise_test: Unhandled rejection with value: object "SecurityError: Failed to construct 'Worker': Script at 'http://web-platform.test:8444/upgrade-insecure-requests/support/redirect-cors.py?location=http%3A%2F%2Fweb-platform.test%3A8444%2Fupgrade-insecure-requests%2Fsupport%2Fworker.js' cannot be accessed from origin 'https://web-platform.test:8444'."
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-redirect-upgrade.https.html b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-redirect-upgrade.https.html
new file mode 100644
index 0000000..19fbb1f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-redirect-upgrade.https.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<!-- Generated by wpt/upgrade-insecure-requests/support/generate.py -->
+<title>Upgrade Insecure Requests: worker.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./support/testharness-helper.sub.js"></script>
+<script src="/mixed-content/generic/common.js"></script>
+
+<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
+</head>
+<body>
+<script>
+const tests = generateRedirectTests(ResourceType.WORKER, true);
+tests.forEach(test => testMap['worker'](test));
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-subresource-fetch-redirect-upgrade.https.html b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-subresource-fetch-redirect-upgrade.https.html
new file mode 100644
index 0000000..91ff96d9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-subresource-fetch-redirect-upgrade.https.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<!-- Generated by wpt/upgrade-insecure-requests/support/generate.py -->
+<title>Upgrade Insecure Requests: worker-subresource-fetch.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./support/testharness-helper.sub.js"></script>
+<script src="/mixed-content/generic/common.js"></script>
+
+<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
+</head>
+<body>
+<script>
+const tests = generateRedirectTests(ResourceType.IMAGE, false);
+tests.forEach(test => testMap['worker-subresource-fetch'](test));
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-subresource-fetch-upgrade.https.html b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-subresource-fetch-upgrade.https.html
new file mode 100644
index 0000000..9fb4f85
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-subresource-fetch-upgrade.https.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<!-- Generated by wpt/upgrade-insecure-requests/support/generate.py -->
+<title>Upgrade Insecure Requests: worker-subresource-fetch.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./support/testharness-helper.sub.js"></script>
+<script src="/mixed-content/generic/common.js"></script>
+
+<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
+</head>
+<body>
+<script>
+const tests = generateTests(ResourceType.IMAGE, false);
+tests.forEach(test => testMap['worker-subresource-fetch'](test));
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-upgrade.https-expected.txt b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-upgrade.https-expected.txt
new file mode 100644
index 0000000..5132c62
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-upgrade.https-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+PASS secure/same-origin worker
+FAIL insecure/same-origin worker promise_test: Unhandled rejection with value: object "SecurityError: Failed to construct 'Worker': Script at 'http://web-platform.test:8444/upgrade-insecure-requests/support/worker.js' cannot be accessed from origin 'https://web-platform.test:8444'."
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-upgrade.https.html b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-upgrade.https.html
new file mode 100644
index 0000000..9f2cea1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/upgrade-insecure-requests/worker-upgrade.https.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<!-- Generated by wpt/upgrade-insecure-requests/support/generate.py -->
+<title>Upgrade Insecure Requests: worker.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./support/testharness-helper.sub.js"></script>
+<script src="/mixed-content/generic/common.js"></script>
+
+<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
+</head>
+<body>
+<script>
+const tests = generateTests(ResourceType.WORKER, true);
+tests.forEach(test => testMap['worker'](test));
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/webauthn/createcredential-badargs-challenge.https-expected.txt b/third_party/blink/web_tests/external/wpt/webauthn/createcredential-badargs-challenge.https-expected.txt
index 13bd75df0..f06bd4b 100644
--- a/third_party/blink/web_tests/external/wpt/webauthn/createcredential-badargs-challenge.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webauthn/createcredential-badargs-challenge.https-expected.txt
@@ -4,6 +4,6 @@
 PASS Bad challenge: challenge is null
 PASS Bad challenge: challenge is empty object
 PASS Bad challenge: challenge is empty Array
-FAIL Bad challenge: challenge is empty ArrayBuffer assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
+FAIL Bad challenge: challenge is empty ArrayBuffer assert_unreached: Should have rejected: Expected bad parameters to fail Reached unreachable code
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/webauthn/createcredential-badargs-rp.https-expected.txt b/third_party/blink/web_tests/external/wpt/webauthn/createcredential-badargs-rp.https-expected.txt
index 8f9b546b..487fdb36 100644
--- a/third_party/blink/web_tests/external/wpt/webauthn/createcredential-badargs-rp.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webauthn/createcredential-badargs-rp.https-expected.txt
@@ -4,16 +4,16 @@
 PASS Bad rp: rp is empty object
 FAIL Bad rp: id is object assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "SecurityError: The relying party ID '[object Object]' is not a registrable domain suffix of, nor equal to 'https://web-platform.test:8444'." ("SecurityError") expected object "TypeError" ("TypeError")
 PASS Bad rp: id is null
-FAIL Bad rp: id is empty String assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." that is not a DOMException SecurityError: property "code" is equal to 9, expected 18
+PASS Bad rp: id is empty String
 PASS Bad rp: id is invalid domain (has space)
 PASS Bad rp: id is invalid domain (starts with dash)
 PASS Bad rp: id is invalid domain (starts with number)
 PASS rp missing name
-FAIL Bad rp: name is object assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad rp: name is null assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad rp: name is empty String assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad rp: icon is object assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad rp: icon is null assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad rp: icon is empty String assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
+FAIL Bad rp: name is object assert_unreached: Should have rejected: Expected bad parameters to fail Reached unreachable code
+FAIL Bad rp: name is null assert_unreached: Should have rejected: Expected bad parameters to fail Reached unreachable code
+FAIL Bad rp: name is empty String assert_unreached: Should have rejected: Expected bad parameters to fail Reached unreachable code
+FAIL Bad rp: icon is object assert_unreached: Should have rejected: Expected bad parameters to fail Reached unreachable code
+FAIL Bad rp: icon is null assert_unreached: Should have rejected: Expected bad parameters to fail Reached unreachable code
+FAIL Bad rp: icon is empty String assert_unreached: Should have rejected: Expected bad parameters to fail Reached unreachable code
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/webauthn/createcredential-badargs-user.https-expected.txt b/third_party/blink/web_tests/external/wpt/webauthn/createcredential-badargs-user.https-expected.txt
index f4483f9..7a35adf 100644
--- a/third_party/blink/web_tests/external/wpt/webauthn/createcredential-badargs-user.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webauthn/createcredential-badargs-user.https-expected.txt
@@ -7,23 +7,23 @@
 PASS Bad user: id is null
 PASS Bad user: id is empty String
 PASS Bad user: id is empty Array
-FAIL Bad user: id is empty ArrayBuffer assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad user: ArrayBuffer id is too long (65 bytes) assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad user: Int16Array id is too long (66 bytes) assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad user: Int32Array id is too long (68 bytes) assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad user: Float32Array id is too long (68 bytes) assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad user: Float64Array id is too long (72 bytes) assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad user: id is too long (65 bytes) assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
+FAIL Bad user: id is empty ArrayBuffer assert_unreached: Should have rejected: Expected bad parameters to fail Reached unreachable code
+PASS Bad user: ArrayBuffer id is too long (65 bytes)
+PASS Bad user: Int16Array id is too long (66 bytes)
+PASS Bad user: Int32Array id is too long (68 bytes)
+PASS Bad user: Float32Array id is too long (68 bytes)
+PASS Bad user: Float64Array id is too long (72 bytes)
+PASS Bad user: id is too long (65 bytes)
 PASS user missing name
-FAIL Bad user: name is object assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad user: name is null assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad user: name is empty String assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad user: icon is object assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad user: icon is null assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad user: icon is empty String assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
+FAIL Bad user: name is object assert_unreached: Should have rejected: Expected bad parameters to fail Reached unreachable code
+FAIL Bad user: name is null assert_unreached: Should have rejected: Expected bad parameters to fail Reached unreachable code
+FAIL Bad user: name is empty String assert_unreached: Should have rejected: Expected bad parameters to fail Reached unreachable code
+FAIL Bad user: icon is object assert_unreached: Should have rejected: Expected bad parameters to fail Reached unreachable code
+FAIL Bad user: icon is null assert_unreached: Should have rejected: Expected bad parameters to fail Reached unreachable code
+FAIL Bad user: icon is empty String assert_unreached: Should have rejected: Expected bad parameters to fail Reached unreachable code
 PASS Bad user: displayName is undefined
-FAIL Bad user: displayName is object assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad user: displayName is null assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad user: displayName is empty String assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
+FAIL Bad user: displayName is object assert_unreached: Should have rejected: Expected bad parameters to fail Reached unreachable code
+FAIL Bad user: displayName is null assert_unreached: Should have rejected: Expected bad parameters to fail Reached unreachable code
+FAIL Bad user: displayName is empty String assert_unreached: Should have rejected: Expected bad parameters to fail Reached unreachable code
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/webauthn/createcredential-excludecredentials.https-expected.txt b/third_party/blink/web_tests/external/wpt/webauthn/createcredential-excludecredentials.https-expected.txt
index 38e27530..e0d358c 100644
--- a/third_party/blink/web_tests/external/wpt/webauthn/createcredential-excludecredentials.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webauthn/createcredential-excludecredentials.https-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
 PASS Bad excludeCredentials: string
 PASS Bad excludeCredentials: empty object
-FAIL excludeCredentials missing promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL excludeCredentials empty array promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL exclude existing credential promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL exclude random (non-existing) credential promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
+PASS excludeCredentials missing
+PASS excludeCredentials empty array
+FAIL exclude existing credential assert_throws: expected to fail on excluded credenetial function "function() { throw e }" threw object "InvalidStateError: The user attempted to register an authenticator that contains one of the credentials already registered with the relying party." that is not a DOMException NotAllowedError: property "code" is equal to 11, expected 0
+PASS exclude random (non-existing) credential
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/webauthn/createcredential-extensions.https-expected.txt b/third_party/blink/web_tests/external/wpt/webauthn/createcredential-extensions.https-expected.txt
index fbf6239..cf051341 100644
--- a/third_party/blink/web_tests/external/wpt/webauthn/createcredential-extensions.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webauthn/createcredential-extensions.https-expected.txt
@@ -1,12 +1,12 @@
 This is a testharness.js-based test.
 PASS Bad extensions: extensions is string
-FAIL Bad extensions: extensions is null assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad extensions: extensions is empty Array assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad extensions: extensions is empty ArrayBuffer assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad extensions: malformatted JSON assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad extensions: JavaScript object assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL Bad extensions: extension ID too long assert_throws: Expected bad parameters to fail function "function() { throw e }" threw object "NotSupportedError: The user agent does not implement a password store." ("NotSupportedError") expected object "TypeError" ("TypeError")
-FAIL extensions is a nonsensical JSON string promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
+FAIL Bad extensions: extensions is null assert_unreached: Should have rejected: Expected bad parameters to fail Reached unreachable code
+FAIL Bad extensions: extensions is empty Array assert_unreached: Should have rejected: Expected bad parameters to fail Reached unreachable code
+FAIL Bad extensions: extensions is empty ArrayBuffer assert_unreached: Should have rejected: Expected bad parameters to fail Reached unreachable code
+FAIL Bad extensions: malformatted JSON assert_unreached: Should have rejected: Expected bad parameters to fail Reached unreachable code
+FAIL Bad extensions: JavaScript object assert_unreached: Should have rejected: Expected bad parameters to fail Reached unreachable code
+FAIL Bad extensions: extension ID too long assert_unreached: Should have rejected: Expected bad parameters to fail Reached unreachable code
+PASS extensions is a nonsensical JSON string
 PASS empty appid in create request
 PASS null appid in create request
 PASS appid in create request
diff --git a/third_party/blink/web_tests/external/wpt/webauthn/createcredential-passing.https-expected.txt b/third_party/blink/web_tests/external/wpt/webauthn/createcredential-passing.https-expected.txt
index a02742bd..d2eade1 100644
--- a/third_party/blink/web_tests/external/wpt/webauthn/createcredential-passing.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webauthn/createcredential-passing.https-expected.txt
@@ -1,41 +1,41 @@
 This is a testharness.js-based test.
-FAIL passing credentials.create() with default arguments promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
+PASS passing credentials.create() with default arguments
 FAIL passing credentials.create() with rpId (host and port) promise_test: Unhandled rejection with value: object "SecurityError: The relying party ID 'web-platform.test:8444' is not a registrable domain suffix of, nor equal to 'https://web-platform.test:8444'."
-FAIL passing credentials.create() with rpId (hostname) promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL passing credentials.create() without rp.icon promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL very short user id promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL max length user id promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL Uint8Array user id promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL Int8Array user id promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL Int16Array user id promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL Int32Array user id promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL Float32Array user id promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL DataView user id promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL passing credentials.create() without user.icon promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL Int16Array challenge promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL Int32Array challenge promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL Float32Array challenge promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL Float64Array challenge promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL DataView challenge promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL Absurdly large challenge promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
+PASS passing credentials.create() with rpId (hostname)
+PASS passing credentials.create() without rp.icon
+PASS very short user id
+PASS max length user id
+PASS Uint8Array user id
+PASS Int8Array user id
+PASS Int16Array user id
+PASS Int32Array user id
+PASS Float32Array user id
+PASS DataView user id
+PASS passing credentials.create() without user.icon
+PASS Int16Array challenge
+PASS Int32Array challenge
+PASS Float32Array challenge
+PASS Float64Array challenge
+PASS DataView challenge
+PASS Absurdly large challenge
 FAIL Bad pubKeyCredParams: pubKeyCredParams is empty Array promise_test: Unhandled rejection with value: object "NotSupportedError: Required parameters missing in `options.publicKey`."
-FAIL EC256 pubKeyCredParams promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL SelectEC256 pubKeyCredParams from a list promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL passing credentials.create() with no timeout promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL authenticatorSelection is undefined promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL authenticatorSelection is empty object promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL authenticatorSelection default values promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL authenticatorSelection attachment undefined promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL authenticatorSelection residentKey undefined promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL authenticatorSelection residentKey false promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL authenticatorSelection userVerification undefined promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL authenticatorSelection userVerification discouraged promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL attestation parameter: attestation is "none" promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL attestation parameter: attestation is "indirect" promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL attestation parameter: attestation is "direct" promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL attestation parameter: attestation is undefined promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL extensions undefined promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL extensions are empty object promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
-FAIL extensions are dict of empty strings promise_test: Unhandled rejection with value: object "NotSupportedError: The user agent does not implement a password store."
+PASS EC256 pubKeyCredParams
+PASS SelectEC256 pubKeyCredParams from a list
+PASS passing credentials.create() with no timeout
+PASS authenticatorSelection is undefined
+PASS authenticatorSelection is empty object
+PASS authenticatorSelection default values
+PASS authenticatorSelection attachment undefined
+PASS authenticatorSelection residentKey undefined
+PASS authenticatorSelection residentKey false
+PASS authenticatorSelection userVerification undefined
+PASS authenticatorSelection userVerification discouraged
+PASS attestation parameter: attestation is "none"
+PASS attestation parameter: attestation is "indirect"
+PASS attestation parameter: attestation is "direct"
+PASS attestation parameter: attestation is undefined
+PASS extensions undefined
+PASS extensions are empty object
+PASS extensions are dict of empty strings
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/webauthn/createcredential-timeout.https-expected.txt b/third_party/blink/web_tests/external/wpt/webauthn/createcredential-timeout.https-expected.txt
deleted file mode 100644
index 5510299..0000000
--- a/third_party/blink/web_tests/external/wpt/webauthn/createcredential-timeout.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL ensure create credential times out promise_test: Unhandled rejection with value: object "Error: timed out"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/webauthn/getcredential-badargs-rpid.https-expected.txt b/third_party/blink/web_tests/external/wpt/webauthn/getcredential-badargs-rpid.https-expected.txt
deleted file mode 100644
index 764d364a..0000000
--- a/third_party/blink/web_tests/external/wpt/webauthn/getcredential-badargs-rpid.https-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-This is a testharness.js-based test.
-FAIL Bad rpId: empty string promise_test: Unhandled rejection with value: object "Error: NotSupportedError: The user agent does not implement a password store."
-FAIL Bad rpId: null promise_test: Unhandled rejection with value: object "Error: NotSupportedError: The user agent does not implement a password store."
-FAIL Bad rpId: invalid domain (has space) promise_test: Unhandled rejection with value: object "Error: NotSupportedError: The user agent does not implement a password store."
-FAIL Bad rpId: invalid domain (starts with dash) promise_test: Unhandled rejection with value: object "Error: NotSupportedError: The user agent does not implement a password store."
-FAIL Bad rpId: invalid domain (starts with number) promise_test: Unhandled rejection with value: object "Error: NotSupportedError: The user agent does not implement a password store."
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/webauthn/getcredential-extensions.https-expected.txt b/third_party/blink/web_tests/external/wpt/webauthn/getcredential-extensions.https-expected.txt
index 50dde17..2108982e 100644
--- a/third_party/blink/web_tests/external/wpt/webauthn/getcredential-extensions.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webauthn/getcredential-extensions.https-expected.txt
@@ -1,11 +1,11 @@
 This is a testharness.js-based test.
-FAIL Bad extensions: extensions is string promise_test: Unhandled rejection with value: object "Error: NotSupportedError: The user agent does not implement a password store."
-FAIL Bad extensions: extensions is null promise_test: Unhandled rejection with value: object "Error: NotSupportedError: The user agent does not implement a password store."
-FAIL Bad extensions: extensions is empty Array promise_test: Unhandled rejection with value: object "Error: NotSupportedError: The user agent does not implement a password store."
-FAIL Bad extensions: extensions is empty ArrayBuffer promise_test: Unhandled rejection with value: object "Error: NotSupportedError: The user agent does not implement a password store."
-FAIL Bad extensions: malformatted JSON promise_test: Unhandled rejection with value: object "Error: NotSupportedError: The user agent does not implement a password store."
-FAIL Bad extensions: JavaScript object promise_test: Unhandled rejection with value: object "Error: NotSupportedError: The user agent does not implement a password store."
-FAIL Bad extensions: extension ID too long promise_test: Unhandled rejection with value: object "Error: NotSupportedError: The user agent does not implement a password store."
-FAIL extensions is a nonsensical JSON string promise_test: Unhandled rejection with value: object "Error: NotSupportedError: The user agent does not implement a password store."
+PASS Bad extensions: extensions is string
+FAIL Bad extensions: extensions is null assert_unreached: Should have rejected: Expected bad parameters to fail Reached unreachable code
+FAIL Bad extensions: extensions is empty Array assert_unreached: Should have rejected: Expected bad parameters to fail Reached unreachable code
+FAIL Bad extensions: extensions is empty ArrayBuffer assert_unreached: Should have rejected: Expected bad parameters to fail Reached unreachable code
+FAIL Bad extensions: malformatted JSON assert_unreached: Should have rejected: Expected bad parameters to fail Reached unreachable code
+FAIL Bad extensions: JavaScript object assert_unreached: Should have rejected: Expected bad parameters to fail Reached unreachable code
+FAIL Bad extensions: extension ID too long assert_unreached: Should have rejected: Expected bad parameters to fail Reached unreachable code
+PASS extensions is a nonsensical JSON string
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/webauthn/getcredential-passing.https-expected.txt b/third_party/blink/web_tests/external/wpt/webauthn/getcredential-passing.https-expected.txt
index 7e13307..729d4a6 100644
--- a/third_party/blink/web_tests/external/wpt/webauthn/getcredential-passing.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webauthn/getcredential-passing.https-expected.txt
@@ -1,15 +1,15 @@
 This is a testharness.js-based test.
-FAIL passing credentials.get() with default args promise_test: Unhandled rejection with value: object "Error: NotSupportedError: The user agent does not implement a password store."
-FAIL passing credentials.create() with no timeout promise_test: Unhandled rejection with value: object "Error: NotSupportedError: The user agent does not implement a password store."
-FAIL rpId undefined promise_test: Unhandled rejection with value: object "Error: NotSupportedError: The user agent does not implement a password store."
-FAIL passing credentials.get() with rpId (host and port) promise_test: Unhandled rejection with value: object "Error: NotSupportedError: The user agent does not implement a password store."
-FAIL passing credentials.get() with rpId (hostname) promise_test: Unhandled rejection with value: object "Error: NotSupportedError: The user agent does not implement a password store."
+PASS passing credentials.get() with default args
+PASS passing credentials.create() with no timeout
+PASS rpId undefined
+FAIL passing credentials.get() with rpId (host and port) promise_test: Unhandled rejection with value: object "SecurityError: The relying party ID 'web-platform.test:8444' is not a registrable domain suffix of, nor equal to 'https://web-platform.test:8444'."
+PASS passing credentials.get() with rpId (hostname)
 FAIL no credential specified promise_test: Unhandled rejection with value: object "Error: Attempting list without defining credential to test"
-FAIL authenticatorSelection userVerification undefined promise_test: Unhandled rejection with value: object "Error: NotSupportedError: The user agent does not implement a password store."
-FAIL authenticatorSelection userVerification preferred promise_test: Unhandled rejection with value: object "Error: NotSupportedError: The user agent does not implement a password store."
-FAIL authenticatorSelection userVerification discouraged promise_test: Unhandled rejection with value: object "Error: NotSupportedError: The user agent does not implement a password store."
-FAIL extensions undefined promise_test: Unhandled rejection with value: object "Error: NotSupportedError: The user agent does not implement a password store."
-FAIL extensions are empty object promise_test: Unhandled rejection with value: object "Error: NotSupportedError: The user agent does not implement a password store."
-FAIL extensions are dict of empty strings promise_test: Unhandled rejection with value: object "Error: NotSupportedError: The user agent does not implement a password store."
+PASS authenticatorSelection userVerification undefined
+PASS authenticatorSelection userVerification preferred
+PASS authenticatorSelection userVerification discouraged
+PASS extensions undefined
+PASS extensions are empty object
+PASS extensions are dict of empty strings
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/webauthn/getcredential-timeout.https-expected.txt b/third_party/blink/web_tests/external/wpt/webauthn/getcredential-timeout.https-expected.txt
deleted file mode 100644
index 5510299..0000000
--- a/third_party/blink/web_tests/external/wpt/webauthn/getcredential-timeout.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL ensure create credential times out promise_test: Unhandled rejection with value: object "Error: timed out"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/webauthn/idlharness.https.window-expected.txt b/third_party/blink/web_tests/external/wpt/webauthn/idlharness.https.window-expected.txt
deleted file mode 100644
index 3d8b620..0000000
--- a/third_party/blink/web_tests/external/wpt/webauthn/idlharness.https.window-expected.txt
+++ /dev/null
@@ -1,69 +0,0 @@
-This is a testharness.js-based test.
-FAIL idlharness promise_test: Unhandled rejection with value: object "NotAllowedError: The operation either timed out or was not allowed. See: https://w3c.github.io/webauthn/#sec-assertion-privacy."
-PASS idl_test setup
-PASS Partial dictionary CredentialCreationOptions: original dictionary defined
-PASS Partial dictionary CredentialRequestOptions: original dictionary defined
-PASS Partial interface PublicKeyCredential: original interface defined
-PASS Partial dictionary AuthenticationExtensionsClientInputs: original dictionary defined
-PASS Partial dictionary AuthenticationExtensionsClientOutputs: original dictionary defined
-PASS Partial dictionary AuthenticationExtensionsClientInputs[2]: original dictionary defined
-PASS Partial dictionary AuthenticationExtensionsClientOutputs[2]: original dictionary defined
-PASS Partial dictionary AuthenticationExtensionsClientInputs[3]: original dictionary defined
-PASS Partial dictionary AuthenticationExtensionsClientOutputs[3]: original dictionary defined
-PASS Partial dictionary AuthenticationExtensionsClientInputs[4]: original dictionary defined
-PASS Partial dictionary AuthenticationExtensionsClientOutputs[4]: original dictionary defined
-PASS Partial dictionary AuthenticationExtensionsClientInputs[5]: original dictionary defined
-PASS Partial dictionary AuthenticationExtensionsClientOutputs[5]: original dictionary defined
-PASS Partial dictionary AuthenticationExtensionsClientInputs[6]: original dictionary defined
-PASS Partial dictionary AuthenticationExtensionsClientOutputs[6]: original dictionary defined
-PASS Partial dictionary AuthenticationExtensionsClientInputs[7]: original dictionary defined
-PASS Partial dictionary AuthenticationExtensionsClientOutputs[7]: original dictionary defined
-PASS Partial dictionary AuthenticationExtensionsClientInputs[8]: original dictionary defined
-PASS Partial dictionary AuthenticationExtensionsClientOutputs[8]: original dictionary defined
-PASS PublicKeyCredential interface: existence and properties of interface object
-PASS PublicKeyCredential interface object length
-PASS PublicKeyCredential interface object name
-PASS PublicKeyCredential interface: existence and properties of interface prototype object
-PASS PublicKeyCredential interface: existence and properties of interface prototype object's "constructor" property
-PASS PublicKeyCredential interface: existence and properties of interface prototype object's @@unscopables property
-PASS PublicKeyCredential interface: attribute rawId
-PASS PublicKeyCredential interface: attribute response
-PASS PublicKeyCredential interface: operation getClientExtensionResults()
-PASS PublicKeyCredential interface: operation isUserVerifyingPlatformAuthenticatorAvailable()
-FAIL PublicKeyCredential must be primary interface of cred assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: cred is not defined"
-FAIL Stringification of cred assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: cred is not defined"
-FAIL PublicKeyCredential interface: cred must inherit property "rawId" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: cred is not defined"
-FAIL PublicKeyCredential interface: cred must inherit property "response" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: cred is not defined"
-FAIL PublicKeyCredential interface: cred must inherit property "getClientExtensionResults()" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: cred is not defined"
-FAIL PublicKeyCredential interface: cred must inherit property "isUserVerifyingPlatformAuthenticatorAvailable()" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: cred is not defined"
-PASS AuthenticatorResponse interface: existence and properties of interface object
-PASS AuthenticatorResponse interface object length
-PASS AuthenticatorResponse interface object name
-PASS AuthenticatorResponse interface: existence and properties of interface prototype object
-PASS AuthenticatorResponse interface: existence and properties of interface prototype object's "constructor" property
-PASS AuthenticatorResponse interface: existence and properties of interface prototype object's @@unscopables property
-PASS AuthenticatorResponse interface: attribute clientDataJSON
-PASS AuthenticatorAttestationResponse interface: existence and properties of interface object
-PASS AuthenticatorAttestationResponse interface object length
-PASS AuthenticatorAttestationResponse interface object name
-PASS AuthenticatorAttestationResponse interface: existence and properties of interface prototype object
-PASS AuthenticatorAttestationResponse interface: existence and properties of interface prototype object's "constructor" property
-PASS AuthenticatorAttestationResponse interface: existence and properties of interface prototype object's @@unscopables property
-PASS AuthenticatorAttestationResponse interface: attribute attestationObject
-PASS AuthenticatorAssertionResponse interface: existence and properties of interface object
-PASS AuthenticatorAssertionResponse interface object length
-PASS AuthenticatorAssertionResponse interface object name
-PASS AuthenticatorAssertionResponse interface: existence and properties of interface prototype object
-PASS AuthenticatorAssertionResponse interface: existence and properties of interface prototype object's "constructor" property
-PASS AuthenticatorAssertionResponse interface: existence and properties of interface prototype object's @@unscopables property
-PASS AuthenticatorAssertionResponse interface: attribute authenticatorData
-PASS AuthenticatorAssertionResponse interface: attribute signature
-PASS AuthenticatorAssertionResponse interface: attribute userHandle
-FAIL AuthenticatorAssertionResponse must be primary interface of assertionResponse assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: assertionResponse is not defined"
-FAIL Stringification of assertionResponse assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: assertionResponse is not defined"
-FAIL AuthenticatorAssertionResponse interface: assertionResponse must inherit property "authenticatorData" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: assertionResponse is not defined"
-FAIL AuthenticatorAssertionResponse interface: assertionResponse must inherit property "signature" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: assertionResponse is not defined"
-FAIL AuthenticatorAssertionResponse interface: assertionResponse must inherit property "userHandle" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: assertionResponse is not defined"
-FAIL AuthenticatorResponse interface: assertionResponse must inherit property "clientDataJSON" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: assertionResponse is not defined"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCDtlsTransport-state.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCDtlsTransport-state.html
index 283ab08..fd7215f 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCDtlsTransport-state.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCDtlsTransport-state.html
@@ -42,16 +42,54 @@
   });
 }
 
-promise_test(async t => {
+// Helper class to exchange ice candidates between
+// two local peer connections
+class CandidateChannel {
+  constructor(source, dest) {
+    source.addEventListener('icecandidate', event => {
+      const { candidate } = event;
+      if (candidate && this.activated
+          && this.destination.signalingState !== 'closed') {
+        this.destination.addIceCandidate(candidate);
+      } else {
+        this.queue.push(candidate);
+      }
+    });
+    this.destination = dest;
+    this.activated = false;
+    this.queue = [];
+  }
+  activate() {
+    this.activated = true;
+    for (const candidate of this.queue) {
+      this.destination.addIceCandidate(candidate);
+    }
+  }
+}
+
+function coupleCandidates(pc1, pc2) {
+  const ch1 = new CandidateChannel(pc1, pc2);
+  const ch2 = new CandidateChannel(pc2, pc1);
+  return [ch1, ch2];
+}
+
+async function setupConnections(t) {
   const pc1 = new RTCPeerConnection();
   t.add_cleanup(() => pc1.close());
   const pc2 = new RTCPeerConnection();
   t.add_cleanup(() => pc2.close());
 
   pc1.addTrack(trackFactories.audio());
-  exchangeIceCandidates(pc1, pc2);
-
+  const channels = coupleCandidates(pc1, pc2);
   await doSignalingHandshake(pc1, pc2);
+  for (const channel of channels) {
+    channel.activate();
+  }
+  return [pc1, pc2];
+}
+
+promise_test(async t => {
+  const [pc1, pc2] = await setupConnections(t);
   const dtlsTransport1 = pc1.getTransceivers()[0].sender.transport;
   const dtlsTransport2 = pc2.getTransceivers()[0].sender.transport;
   assert_true(dtlsTransport1 instanceof RTCDtlsTransport);
@@ -61,15 +99,8 @@
 }, 'DTLS transport goes to connected state');
 
 promise_test(async t => {
-  const pc1 = new RTCPeerConnection();
-  t.add_cleanup(() => pc1.close());
-  const pc2 = new RTCPeerConnection();
-  t.add_cleanup(() => pc2.close());
+  const [pc1, pc2] = await setupConnections(t);
 
-  pc1.addTrack(trackFactories.audio());
-  exchangeIceCandidates(pc1, pc2);
-
-  await doSignalingHandshake(pc1, pc2);
   const dtlsTransport1 = pc1.getTransceivers()[0].sender.transport;
   const dtlsTransport2 = pc2.getTransceivers()[0].sender.transport;
   await Promise.all([resolveWhen(t, dtlsTransport1, 'connected'),
@@ -79,15 +110,7 @@
 }, 'close() causes the local transport to close immediately');
 
 promise_test(async t => {
-  const pc1 = new RTCPeerConnection();
-  t.add_cleanup(() => pc1.close());
-  const pc2 = new RTCPeerConnection();
-  t.add_cleanup(() => pc2.close());
-
-  pc1.addTrack(trackFactories.audio());
-  exchangeIceCandidates(pc1, pc2);
-
-  await doSignalingHandshake(pc1, pc2);
+  const [pc1, pc2] = await setupConnections(t);
   const dtlsTransport1 = pc1.getTransceivers()[0].sender.transport;
   const dtlsTransport2 = pc2.getTransceivers()[0].sender.transport;
   await Promise.all([resolveWhen(t, dtlsTransport1, 'connected'),
diff --git a/third_party/blink/web_tests/external/wpt/worklets/resources/csp-tests.js b/third_party/blink/web_tests/external/wpt/worklets/resources/csp-tests.js
index d2ca05f..ab698d0 100644
--- a/third_party/blink/web_tests/external/wpt/worklets/resources/csp-tests.js
+++ b/third_party/blink/web_tests/external/wpt/worklets/resources/csp-tests.js
@@ -24,7 +24,6 @@
 function runContentSecurityPolicyTests(workletType) {
   runSrcTests(workletType);
   runMixedContentTests(workletType);
-  runUpgradeInsecureRequestsTests(workletType);
 }
 
 // script-src and worker-src tests.
@@ -146,41 +145,3 @@
       scriptConfig.message + ' should be blocked because of mixed contents.');
   }
 }
-
-// upgrade-insecure-requests tests.
-function runUpgradeInsecureRequestsTests(workletType) {
-  // |kToBeUpgradedURL| is expected to upgraded/loaded successfully with
-  // upgrade-insecure-requests is specified.
-  // This relies on some unintuitive cleverness due to WPT's test setup:
-  // 'Upgrade-Insecure-Requests' does not upgrade the port number, so we use
-  // URLs in the form `http://[host]:[https-port]`. If the upgrade fails, the
-  // load will fail, as we don't serve HTTP over the secure port.
-  const kHost = get_host_info().ORIGINAL_HOST;
-  const kPort = get_host_info().HTTPS_PORT;
-  const kToBeUpgradedURL =
-      `http://${kHost}:${kPort}/worklets/resources/empty-worklet-script-with-cors-header.js`;
-
-  const kScriptConfigs = [
-    {URL: kToBeUpgradedURL,
-     message: 'An insecure-origin worklet'},
-    {URL: '/common/redirect.py?location=' +
-          encodeURIComponent(kToBeUpgradedURL),
-     message: 'An insecure-origin-redirected worklet'},
-    {URL: 'import-insecure-origin-empty-worklet-script.sub.js',
-     message: 'A same-origin worklet importing an insecure-origin script'},
-    {URL: 'import-insecure-origin-redirected-empty-worklet-script.sub.js',
-     message: 'A same-origin worklet ' +
-              'importing an insecure-origin-redirected script'}
-  ];
-  for (const scriptConfig of kScriptConfigs) {
-    promise_test(t => {
-        const kWindowURL =
-          'resources/addmodule-window.html?pipe=header(' +
-          'Content-Security-Policy, upgrade-insecure-requests)';
-        return openWindowAndExpectResult(
-          kWindowURL, scriptConfig.URL, workletType, 'RESOLVED');
-      },
-      scriptConfig.message +
-      ' should not be blocked because of upgrade-insecure-requests.');
-  }
-}
diff --git a/third_party/blink/web_tests/fast/mediarecorder/MediaRecorder-disabled-tracks.html b/third_party/blink/web_tests/fast/mediarecorder/MediaRecorder-disabled-tracks.html
deleted file mode 100644
index c73597d..0000000
--- a/third_party/blink/web_tests/fast/mediarecorder/MediaRecorder-disabled-tracks.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<!DOCTYPE html>
-<script src=../../resources/testharness.js></script>
-<script src=../../resources/testharnessreport.js></script>
-<script>
-
-// This test verifies that MediaStream with disabled tracks can be correctly
-// recorded. See crbug.com/878255 for more context.
-var makeAsyncTest = function(value, expected) {
-  var recorder;
-
-  async_test(function(test) {
-    const recorderOnDataAvailable = this.step_func(function(event) {
-      if (recorder.state != "recording")
-        return;
-
-      recorder.onstop = recorderOnStopExpected;
-      recorder.stop();
-    });
-
-    const recorderOnStopExpected = this.step_func_done();
-    const recorderOnStopUnexpected = test.unreached_func('Recording stopped.');
-    const recorderOnError = test.unreached_func('Recording error.');
-
-    const gotStream = this.step_func(function(stream) {
-      for (track in stream.getTracks())
-        track.enabled = true;
-
-      recorder = new MediaRecorder(stream);
-
-      assert_equals(recorder.state, "inactive");
-      recorder.ondataavailable = recorderOnDataAvailable;
-      recorder.onstop = recorderOnStopUnexpected;
-      recorder.onerror = recorderOnError;
-      recorder.start();
-
-      assert_equals(recorder.state, "recording");
-      recorder.requestData();
-    });
-
-    const onError = test.unreached_func('Error creating MediaStream.');
-    navigator.webkitGetUserMedia(value, gotStream, onError);
-  });
-};
-
-generate_tests(makeAsyncTest,
-               [["video-only",  {video: true,  audio: false}],
-                ["audio-only",  {video: false, audio: true}],
-                ["audio-video", {video: true,  audio: true}]]);
-
-</script>
-
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-animation-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-animation-expected.txt
new file mode 100644
index 0000000..fb210c5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-animation-expected.txt
@@ -0,0 +1,13 @@
+This test verifies the hit test regions are updated correctly when composited layer are created and destroyed without triggering layout update during fast path animation.
+
+[object HTMLDivElement]: layer(0,0 800x600) has hit test rect (200,200 50x50)
+
+[object HTMLDivElement]: layer(0,0 50x50) has hit test rect (0,0 50x50)
+
+[object HTMLDivElement]: layer(0,0 800x600) has hit test rect (175,175 100x100)
+
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-expected.txt
new file mode 100644
index 0000000..041106b
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-expected.txt
@@ -0,0 +1,49 @@
+This tests verifies the hit test regions given to the compositor. It can only be run in DumpRenderTree. The outputted rects should cover the hit test regions of all the listed elements. Enable visualize mode to quickly validate graphically.
+
+normalFlow: layer(0,0 785x1530) has hit test rect (13,128 290x12)
+
+inlineOverflow: layer(0,0 785x1578) has hit test rect (13,145 152x12)
+inlineOverflow: layer(0,0 785x1578) has hit test rect (13,157 42x10)
+
+absoluteChildContainer: layer(0,0 785x1658) has hit test rect (13,172 290x12)
+absoluteChildContainer: layer(0,0 785x1658) has hit test rect (320,173 142x12)
+
+relativeChildContainer: layer(0,0 785x1738) has hit test rect (13,189 290x22)
+relativeChildContainer: layer(0,0 785x1738) has hit test rect (314,199 142x12)
+
+fixed: layer(405,0 395x600) has hit test rect (0,85 52x12)
+
+translate: layer(0,0 288x12) has hit test rect (0,0 288x12)
+translate: layer(0,0 785x1866) has hit test rect (13,216 290x14)
+
+transform2d: layer(0,0 785x1946) has hit test rect (16,236 284x20)
+
+overhangingContainer: layer(0,0 785x1994) has hit test rect (13,262 290x12)
+overhangingContainer: layer(0,0 785x1994) has hit test rect (14,274 102x10)
+overhangingContainer: layer(0,0 785x1994) has hit test rect (14,284 111x10)
+overhangingContainer: layer(0,0 785x1994) has hit test rect (14,294 102x11)
+
+transform3d: layer(0,0 288x12) has hit test rect (0,0 288x12)
+transform3d: layer(0,0 785x2138) has hit test rect (13,315 290x14)
+
+negativeOffsetChild: layer(-109,0 211x13) has hit test rect (0,1 102x12)
+
+continuation: layer(0,0 785x2266) has hit test rect (13,355 101x11)
+continuation: layer(0,0 785x2266) has hit test rect (13,366 290x12)
+continuation: layer(0,0 785x2266) has hit test rect (13,378 121x11)
+
+inlineAbsoluteChildContainer: layer(320,393 282x33) has hit test rect (0,0 252x12)
+inlineAbsoluteChildContainer: layer(0,0 785x2378) has hit test rect (13,392 262x12)
+
+list: layer(320,393 282x33) has hit test rect (34,21 248x12)
+list: layer(0,0 785x2458) has hit test rect (13,413 290x14)
+
+styleModified: layer(0,0 785x2548) has hit test rect (13,437 290x22)
+
+containsSvg: layer(0,0 785x2596) has hit test rect (13,464 290x16)
+
+svgline: layer(0,0 785x2644) has hit test rect (13,489 22x3)
+
+tablecell: layer(0,0 785x2692) has hit test rect (45,518 32x11)
+
+
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-global-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-global-expected.txt
new file mode 100644
index 0000000..7da5ff3
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-global-expected.txt
@@ -0,0 +1,12 @@
+This tests verifies the hit test regions given to the compositor in the simple case where touch handles cover (or nearly cover) the entire document. It can only be run in DumpRenderTree.
+
+document: layer(0,0 800x600) has hit test rect (0,0 785x600)
+document: layer(0,0 785x2000) has hit test rect (0,0 785x2000)
+
+html: layer(0,0 785x2000) has hit test rect (0,0 785x2000)
+
+body: layer(0,0 785x2000) has hit test rect (5,16 775x1968)
+
+webPageOverlay: no rects
+
+
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-many-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-many-expected.txt
new file mode 100644
index 0000000..e026dbf
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-many-expected.txt
@@ -0,0 +1,111 @@
+Tests that there is an upper limit on the number of hit rects generated per layer. http://crbug.com/299177.
+
+Test node has 99 children with 100 rects
+Test node has 100 children with 101 rects
+FAIL - got 101 rects, expected 1.
+Test node has 101 children with 102 rects
+FAIL - got 102 rects, expected 1.
+manychildren: layer(0,0 308x1228) has hit test rect (0,0 290x12)
+manychildren: layer(0,0 308x1228) has hit test rect (301,21 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,33 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,45 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,57 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,69 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,81 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,93 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,105 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,117 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,129 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,141 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,153 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,165 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,177 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,189 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,201 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,213 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,225 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,237 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,249 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,261 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,273 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,285 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,297 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,309 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,321 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,333 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,345 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,357 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,369 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,381 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,393 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,405 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,417 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,429 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,441 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,453 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,465 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,477 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,489 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,501 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,513 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,525 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,537 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,549 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,561 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,573 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,585 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,597 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,609 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,621 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,633 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,645 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,657 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,669 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,681 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,693 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,705 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,717 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,729 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,741 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,753 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,765 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,777 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,789 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,801 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,813 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,825 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,837 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,849 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,861 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,873 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,885 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,897 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,909 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,921 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,933 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,945 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,957 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,969 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,981 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,993 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,1005 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,1017 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,1029 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,1041 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,1053 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,1065 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,1077 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,1089 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,1101 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,1113 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,1125 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,1137 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,1149 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,1161 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,1173 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,1185 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,1197 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,1209 7x7)
+manychildren: layer(0,0 308x1228) has hit test rect (301,1221 7x7)
+
+
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-non-composited-scroll-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-non-composited-scroll-expected.txt
new file mode 100644
index 0000000..3a468435
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-non-composited-scroll-expected.txt
@@ -0,0 +1,23 @@
+This test verifies the hit test regions given to the compositor specifically around non-composited overflow scroll elements.
+
+scrollContent: layer(1,1 288x30) has hit test rect (0,10 273x12)
+
+scrollContainerWithHandler: layer(1,1 288x30) has hit test rect (0,0 273x30)
+scrollContainerWithHandler: layer(0,0 800x600) has hit test rect (13,89 290x32)
+
+nestedContent: layer(1,1 271x30) has hit test rect (0,10 256x12)
+
+fixedPositionContentContainer: layer(1,1 288x30) has hit test rect (0,10 273x12)
+fixedPositionContentContainer: layer(0,0 800x600) has hit test rect (310,190 132x12)
+
+overflowwithhandler: layer(1,1 271x25) has hit test rect (0,0 256x25)
+overflowwithhandler: layer(1,1 288x30) has hit test rect (0,10 273x20)
+
+divInsideNonScrollableLayer: layer(1,1 288x30) has hit test rect (0,20 273x10)
+
+divInsideCompositedLayer: layer(0,10 273x12) has hit test rect (0,0 273x12)
+
+overflowwithborder: layer(10,6 274x38) has hit test rect (0,4 255x34)
+overflowwithborder: layer(0,0 785x831) has hit test rect (13,336 290x50)
+
+
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-non-composited-scroll-overflow-with-handler-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-non-composited-scroll-overflow-with-handler-expected.txt
new file mode 100644
index 0000000..558f8bdcd
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-non-composited-scroll-overflow-with-handler-expected.txt
@@ -0,0 +1,5 @@
+notclipped: layer(1,1 300x100) has hit test rect (0,50 200x25)
+
+clipped: no rects
+
+
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-scroll-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-scroll-expected.txt
new file mode 100644
index 0000000..01bdec5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-scroll-expected.txt
@@ -0,0 +1,20 @@
+This test verifies the hit test regions given to the compositor specifically around composited overflow scroll elements.
+
+scrollContent: layer(1,1 288x50) has hit test rect (0,0 273x10)
+
+scrollContent5: layer(1,1 288x50) has hit test rect (0,8 273x12)
+
+scrollContent6: layer(0,0 785x601) has hit test rect (14,203 273x12)
+
+nestedContent: layer(1,1 271x50) has hit test rect (0,12 256x12)
+
+overflowwithhandler: layer(1,1 271x50) has hit test rect (0,0 256x50)
+overflowwithhandler: layer(1,1 288x50) has hit test rect (0,10 273x40)
+
+overflowwithborder: layer(10,6 274x58) has hit test rect (0,0 255x58)
+overflowwithborder: layer(0,0 785x777) has hit test rect (13,365 290x70)
+
+withTransform: layer(0,0 271x12) has hit test rect (0,0 271x12)
+withTransform: layer(1,1 288x50) has hit test rect (0,0 273x7)
+
+
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-squashing-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-squashing-expected.txt
new file mode 100644
index 0000000..961afa6d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-squashing-expected.txt
@@ -0,0 +1,9 @@
+This test verifies the hit test regions given to the compositor for composited layer squashing.
+
+behind: layer(0,0 52x52) has hit test rect (0,0 52x52)
+
+middle: layer(25,55 132x132) has hit test rect (0,0 52x52)
+
+top: layer(25,55 132x132) has hit test rect (80,80 52x52)
+
+
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-with-negative-child-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-with-negative-child-expected.txt
new file mode 100644
index 0000000..920d6bc0
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/fast/events/touch/compositor-touch-hit-rects-with-negative-child-expected.txt
@@ -0,0 +1,5 @@
+This tests verifies the hit test regions given to the compositor for an element with child at negative offset. It can only be run in DumpRenderTree.
+
+negativeOffsetChild: layer(-109,0 211x13) has hit test rect (0,1 102x12)
+
+
diff --git a/third_party/blink/web_tests/media/picture-in-picture/clear-after-pip.html b/third_party/blink/web_tests/media/picture-in-picture/clear-after-pip.html
new file mode 100644
index 0000000..4a777424
--- /dev/null
+++ b/third_party/blink/web_tests/media/picture-in-picture/clear-after-pip.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<title>No crash when resetting player after entering PIP</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<video></video>
+<script>
+async_test(t => {
+  if (!document.pictureInPictureEnabled)
+    t.done();
+
+  const video = document.querySelector('video');
+  video.src = '../content/test.ogv';
+
+  video.addEventListener('click', t.step_func(() => {
+    video.requestPictureInPicture();
+  }), { once: true });
+
+  video.addEventListener('enterpictureinpicture', t.step_func_done(() => {
+    video.src = '';
+    // Do not crash.
+  }), { once: true });
+
+  video.play().then(t.step_func(() => {
+    const bounds = video.getBoundingClientRect();
+
+    chrome.gpuBenchmarking.pointerActionSequence([{
+      source: 'mouse',
+      actions: [
+        { name: 'pointerDown',
+          x: bounds.left + bounds.width / 2,
+          y: bounds.top + bounds.height / 2
+        },
+        { name: 'pointerUp' }
+      ]
+    }]);
+  }));
+});
+</script>
diff --git a/third_party/snappy/BUILD.gn b/third_party/snappy/BUILD.gn
index 324a06a..734dadb 100644
--- a/third_party/snappy/BUILD.gn
+++ b/third_party/snappy/BUILD.gn
@@ -21,12 +21,6 @@
 config("snappy_warnings") {
   cflags = []
 
-  if (is_clang) {
-    # ComputeTable is unused,
-    # https://code.google.com/p/snappy/issues/detail?id=96
-    cflags += [ "-Wno-unused-function" ]
-  }
-
   if (is_win) {
     cflags += [ "/wd4018" ]  # Signed/unsigned mismatch in comparison.
   }
diff --git a/third_party/snappy/README.chromium b/third_party/snappy/README.chromium
index ab39894f..b7d03c4 100644
--- a/third_party/snappy/README.chromium
+++ b/third_party/snappy/README.chromium
@@ -1,7 +1,7 @@
 Name: Snappy: A fast compressor/decompressor
 Short Name: snappy
 URL: http://google.github.io/snappy/
-Version: 1.1.7.git.ea660b57d65d68d521287c903459b6dd3b2804d0
+Version: 1.1.7.git.3f194acb57e0487531c96b97af61dcbd025a78a3
 License: New BSD
 License File: src/COPYING
 Security Critical: yes
diff --git a/third_party/snappy/linux/config.h b/third_party/snappy/linux/config.h
index 5dc7a4b..66e9658 100644
--- a/third_party/snappy/linux/config.h
+++ b/third_party/snappy/linux/config.h
@@ -52,6 +52,9 @@
 /* Define to 1 if you target processors with SSSE3+ and have <tmmintrin.h>. */
 #define SNAPPY_HAVE_SSSE3 0
 
+/* Define to 1 if you target processors with BMI2+ and have <bmi2intrin.h>. */
+#define SNAPPY_HAVE_BMI2 0
+
 /* Define to 1 if your processor stores words with the most significant byte
    first (like Motorola and SPARC, unlike Intel and VAX). */
 /* #undef SNAPPY_IS_BIG_ENDIAN */
diff --git a/third_party/snappy/mac/config.h b/third_party/snappy/mac/config.h
index a0d92285..cac13de 100644
--- a/third_party/snappy/mac/config.h
+++ b/third_party/snappy/mac/config.h
@@ -52,6 +52,9 @@
 /* Define to 1 if you target processors with SSSE3+ and have <tmmintrin.h>. */
 #define SNAPPY_HAVE_SSSE3 0
 
+/* Define to 1 if you target processors with BMI2+ and have <bmi2intrin.h>. */
+#define SNAPPY_HAVE_BMI2 0
+
 /* Define to 1 if your processor stores words with the most significant byte
    first (like Motorola and SPARC, unlike Intel and VAX). */
 /* #undef SNAPPY_IS_BIG_ENDIAN */
diff --git a/third_party/snappy/win32/config.h b/third_party/snappy/win32/config.h
index 995a8014..a762400 100644
--- a/third_party/snappy/win32/config.h
+++ b/third_party/snappy/win32/config.h
@@ -52,6 +52,9 @@
 /* Define to 1 if you target processors with SSSE3+ and have <tmmintrin.h>. */
 #define SNAPPY_HAVE_SSSE3 0
 
+/* Define to 1 if you target processors with BMI2+ and have <bmi2intrin.h>. */
+#define SNAPPY_HAVE_BMI2 0
+
 /* Define to 1 if your processor stores words with the most significant byte
    first (like Motorola and SPARC, unlike Intel and VAX). */
 /* #undef SNAPPY_IS_BIG_ENDIAN */
diff --git a/third_party/webdriver/atoms.cc b/third_party/webdriver/atoms.cc
index ad0da6d..fb76a42 100644
--- a/third_party/webdriver/atoms.cc
+++ b/third_party/webdriver/atoms.cc
@@ -643,122 +643,122 @@
     "fa,b,c);if(A(a,\"INPUT\")&&\"hidden\"==a.type.toLowerCase()||A(a,\"NOSC",
     "RIPT\"))return!1;f=W(a,\"visibility\");return\"collapse\"!=f&&\"hidden",
     "\"!=f&&c(a)&&(b||0!=wc(a))&&d(a)?!e(a):!1}\nfunction xc(a){function b(a",
-    "){if(A(a)&&\"none\"==W(a,\"display\"))return!1;var c;(c=a.parentNode)&&",
-    "c.shadowRoot&&void 0!==a.assignedSlot?c=a.assignedSlot?a.assignedSlot.p",
-    "arentNode:null:a.getDestinationInsertionPoints&&(a=a.getDestinationInse",
-    "rtionPoints(),0<a.length&&(c=a[a.length-1]));return ic&&c instanceof Sh",
-    "adowRoot||c&&(9==c.nodeType||11==c.nodeType)?!0:!!c&&b(c)}return sc(a,!",
-    "0,b)}var X=\"hidden\";\nfunction uc(a){function b(a){function b(a){retu",
-    "rn a==h?!0:0==W(a,\"display\").lastIndexOf(\"inline\",0)||\"absolute\"=",
-    "=c&&\"static\"==W(a,\"position\")?!1:!0}var c=W(a,\"position\");if(\"fi",
-    "xed\"==c)return G=!0,a==h?null:h;for(a=qc(a);a&&!b(a);)a=qc(a);return a",
-    "}function c(a){var b=a;if(\"visible\"==y)if(a==h&&m)b=m;else if(a==m)re",
-    "turn{x:\"visible\",y:\"visible\"};b={x:W(b,\"overflow-x\"),y:W(b,\"over",
-    "flow-y\")};a==h&&(b.x=\"visible\"==b.x?\"auto\":b.x,b.y=\"visible\"==b.",
-    "y?\"auto\":b.y);return b}function d(a){if(a==h){var b=(new Xa(f)).M;\na",
-    "=b.scrollingElement?b.scrollingElement:b.body||b.documentElement;b=b.pa",
-    "rentWindow||b.defaultView;a=new w(b.pageXOffset||a.scrollLeft,b.pageYOf",
-    "fset||a.scrollTop)}else a=new w(a.scrollLeft,a.scrollTop);return a}var ",
-    "e=yc(a);var f=x(a),h=f.documentElement,m=f.body,y=W(h,\"overflow\"),G;f",
-    "or(a=b(a);a;a=b(a)){var t=c(a);if(\"visible\"!=t.x||\"visible\"!=t.y){v",
-    "ar z=tc(a);if(0==z.width||0==z.height)return X;var M=e.right<z.left,T=e",
-    ".bottom<z.top;if(M&&\"hidden\"==t.x||T&&\"hidden\"==t.y)return X;if(M&&",
-    "\"visible\"!=t.x||\nT&&\"visible\"!=t.y){M=d(a);T=e.bottom<z.top-M.y;if",
-    "(e.right<z.left-M.x&&\"visible\"!=t.x||T&&\"visible\"!=t.x)return X;e=u",
-    "c(a);return e==X?X:\"scroll\"}M=e.left>=z.left+z.width;z=e.top>=z.top+z",
-    ".height;if(M&&\"hidden\"==t.x||z&&\"hidden\"==t.y)return X;if(M&&\"visi",
-    "ble\"!=t.x||z&&\"visible\"!=t.y){if(G&&(t=d(a),e.left>=h.scrollWidth-t.",
-    "x||e.right>=h.scrollHeight-t.y))return X;e=uc(a);return e==X?X:\"scroll",
-    "\"}}}return\"none\"}\nfunction tc(a){var b=vc(a);if(b)return b.rect;if(",
-    "A(a,\"HTML\"))return a=x(a),a=((a?a.parentWindow||a.defaultView:window)",
-    "||window).document,a=\"CSS1Compat\"==a.compatMode?a.documentElement:a.b",
-    "ody,a=new Na(a.clientWidth,a.clientHeight),new U(0,0,a.width,a.height);",
-    "try{var c=a.getBoundingClientRect()}catch(d){return new U(0,0,0,0)}retu",
-    "rn new U(c.left,c.top,c.right-c.left,c.bottom-c.top)}\nfunction vc(a){v",
-    "ar b=A(a,\"MAP\");if(!b&&!A(a,\"AREA\"))return null;var c=b?a:A(a.paren",
-    "tNode,\"MAP\")?a.parentNode:null,d=null,e=null;c&&c.name&&(d=S.za('/des",
-    "cendant::*[@usemap = \"#'+c.name+'\"]',x(c)))&&(e=tc(d),b||\"default\"=",
-    "=a.shape.toLowerCase()||(a=zc(a),b=Math.min(Math.max(a.left,0),e.width)",
-    ",c=Math.min(Math.max(a.top,0),e.height),e=new U(b+e.left,c+e.top,Math.m",
-    "in(a.width,e.width-b),Math.min(a.height,e.height-c))));return{fa:d,rect",
-    ":e||new U(0,0,0,0)}}\nfunction zc(a){var b=a.shape.toLowerCase();a=a.co",
-    "ords.split(\",\");if(\"rect\"==b&&4==a.length){var b=a[0],c=a[1];return",
-    " new U(b,c,a[2]-b,a[3]-c)}if(\"circle\"==b&&3==a.length)return b=a[2],n",
-    "ew U(a[0]-b,a[1]-b,2*b,2*b);if(\"poly\"==b&&2<a.length){for(var b=a[0],",
-    "c=a[1],d=b,e=c,f=2;f+1<a.length;f+=2)b=Math.min(b,a[f]),d=Math.max(d,a[",
-    "f]),c=Math.min(c,a[f+1]),e=Math.max(e,a[f+1]);return new U(b,c,d-b,e-c)",
-    "}return new U(0,0,0,0)}function yc(a){a=tc(a);return new hc(a.top,a.lef",
-    "t+a.width,a.top+a.height,a.left)}\nfunction wc(a){var b=1,c=W(a,\"opaci",
-    "ty\");c&&(b=Number(c));(a=qc(a))&&(b*=wc(a));return b};Ma();Ma();functi",
-    "on Ac(a,b,c){this.B=a;this.pa=b;this.qa=c}Ac.prototype.create=function(",
-    "a){a=x(a).createEvent(\"HTMLEvents\");a.initEvent(this.B,this.pa,this.q",
-    "a);return a};Ac.prototype.toString=function(){return this.B};var Bc=new",
-    " Ac(\"blur\",!1,!1),Cc=new Ac(\"change\",!0,!1);function Dc(a,b){b=b.cr",
-    "eate(a,void 0);\"isTrusted\"in b||(b.isTrusted=!1);a.dispatchEvent(b)};",
-    "function Ec(){this.N=ka.document.documentElement;var a=Wa(x(this.N));a&",
-    "&Fc(this,a)}function Fc(a,b){a.N=b;A(b,\"OPTION\")&&Va(b,function(a){re",
-    "turn A(a,\"SELECT\")})}function Gc(a){var b=Va(a.N,function(a){return!!",
-    "a&&A(a)&&kc(a)},!0),b=b||a.N;a=Wa(x(b));if(b!=a){if(a&&ea(a.blur)&&!A(a",
-    ",\"BODY\"))try{a.blur()}catch(c){throw c;}ea(b.focus)&&b.focus()}};func",
-    "tion Hc(a,b){this.w={};this.g=[];this.G=0;var c=arguments.length;if(1<c",
-    "){if(c%2)throw Error(\"Uneven number of arguments\");for(var d=0;d<c;d+",
-    "=2)this.set(arguments[d],arguments[d+1])}else a&&this.addAll(a)}functio",
-    "n Ic(a){Jc(a);return a.g.concat()}g=Hc.prototype;g.clear=function(){thi",
-    "s.w={};this.G=this.g.length=0};g.remove=function(a){return Object.proto",
-    "type.hasOwnProperty.call(this.w,a)?(delete this.w[a],this.G--,this.g.le",
-    "ngth>2*this.G&&Jc(this),!0):!1};\nfunction Jc(a){var b,c;if(a.G!=a.g.le",
-    "ngth){for(b=c=0;c<a.g.length;){var d=a.g[c];Object.prototype.hasOwnProp",
-    "erty.call(a.w,d)&&(a.g[b++]=d);c++}a.g.length=b}if(a.G!=a.g.length){var",
-    " e={};for(b=c=0;c<a.g.length;)d=a.g[c],Object.prototype.hasOwnProperty.",
-    "call(e,d)||(a.g[b++]=d,e[d]=1),c++;a.g.length=b}}g.get=function(a,b){re",
-    "turn Object.prototype.hasOwnProperty.call(this.w,a)?this.w[a]:b};g.set=",
-    "function(a,b){Object.prototype.hasOwnProperty.call(this.w,a)||(this.G++",
-    ",this.g.push(a));this.w[a]=b};\ng.addAll=function(a){if(a instanceof Hc",
-    "){var b=Ic(a);Jc(a);for(var c=[],d=0;d<a.g.length;d++)c.push(a.w[a.g[d]",
-    "]);a=c}else{b=[];var d=0;for(e in a)b[d++]=e;d=[];var e=0;for(c in a)d[",
-    "e++]=a[c];a=d}for(c=0;c<b.length;c++)this.set(b[c],a[c])};g.forEach=fun",
-    "ction(a,b){for(var c=Ic(this),d=0;d<c.length;d++){var e=c[d],f=this.get",
-    "(e);a.call(b,f,e,this)}};g.clone=function(){return new Hc(this)};var Kc",
-    "={};function Y(a,b,c){fa(a)&&(a=a.b);a=new Lc(a);!b||b in Kc&&!c||(Kc[b",
-    "]={key:a,shift:!1},c&&(Kc[c]={key:a,shift:!0}));return a}function Lc(a)",
-    "{this.code=a}Y(8);Y(9);Y(13);var Mc=Y(16),Nc=Y(17),Oc=Y(18);Y(19);Y(20)",
-    ";Y(27);Y(32,\" \");Y(33);Y(34);Y(35);Y(36);Y(37);Y(38);Y(39);Y(40);Y(44",
-    ");Y(45);Y(46);Y(48,\"0\",\")\");Y(49,\"1\",\"!\");Y(50,\"2\",\"@\");Y(5",
-    "1,\"3\",\"#\");Y(52,\"4\",\"$\");Y(53,\"5\",\"%\");Y(54,\"6\",\"^\");Y(",
-    "55,\"7\",\"&\");Y(56,\"8\",\"*\");Y(57,\"9\",\"(\");Y(65,\"a\",\"A\");Y",
-    "(66,\"b\",\"B\");Y(67,\"c\",\"C\");Y(68,\"d\",\"D\");\nY(69,\"e\",\"E\"",
-    ");Y(70,\"f\",\"F\");Y(71,\"g\",\"G\");Y(72,\"h\",\"H\");Y(73,\"i\",\"I",
-    "\");Y(74,\"j\",\"J\");Y(75,\"k\",\"K\");Y(76,\"l\",\"L\");Y(77,\"m\",\"",
-    "M\");Y(78,\"n\",\"N\");Y(79,\"o\",\"O\");Y(80,\"p\",\"P\");Y(81,\"q\",",
-    "\"Q\");Y(82,\"r\",\"R\");Y(83,\"s\",\"S\");Y(84,\"t\",\"T\");Y(85,\"u\"",
-    ",\"U\");Y(86,\"v\",\"V\");Y(87,\"w\",\"W\");Y(88,\"x\",\"X\");Y(89,\"y",
-    "\",\"Y\");Y(90,\"z\",\"Z\");var Pc=Y(Ia?{c:91,b:91}:Ha?{c:224,b:91}:{c:",
-    "0,b:91});Y(Ia?{c:92,b:92}:Ha?{c:224,b:93}:{c:0,b:92});Y(Ia?{c:93,b:93}:",
-    "Ha?{c:0,b:0}:{c:93,b:null});Y({c:96,b:96},\"0\");Y({c:97,b:97},\"1\");",
-    "\nY({c:98,b:98},\"2\");Y({c:99,b:99},\"3\");Y({c:100,b:100},\"4\");Y({c",
-    ":101,b:101},\"5\");Y({c:102,b:102},\"6\");Y({c:103,b:103},\"7\");Y({c:1",
-    "04,b:104},\"8\");Y({c:105,b:105},\"9\");Y({c:106,b:106},\"*\");Y({c:107",
-    ",b:107},\"+\");Y({c:109,b:109},\"-\");Y({c:110,b:110},\".\");Y({c:111,b",
-    ":111},\"/\");Y(144);Y(112);Y(113);Y(114);Y(115);Y(116);Y(117);Y(118);Y(",
-    "119);Y(120);Y(121);Y(122);Y(123);Y({c:107,b:187},\"=\",\"+\");Y(108,\",",
-    "\");Y({c:109,b:189},\"-\",\"_\");Y(188,\",\",\"<\");Y(190,\".\",\">\");",
-    "Y(191,\"/\",\"?\");Y(192,\"`\",\"~\");Y(219,\"[\",\"{\");\nY(220,\"",
-    "\\\\\",\"|\");Y(221,\"]\",\"}\");Y({c:59,b:186},\";\",\":\");Y(222,\"'",
-    "\",'\"');var Qc=new Hc;Qc.set(1,Mc);Qc.set(2,Nc);Qc.set(4,Oc);Qc.set(8,",
-    "Pc);(function(a){var b=new Hc;q(Ic(a),function(c){b.set(a.get(c).code,c",
-    ")});return b})(Qc);function Z(){Ec.call(this)}p(Z,Ec);Z.W=void 0;Z.ra=f",
-    "unction(){return Z.W?Z.W:Z.W=new Z};function Rc(a){var b=Z.ra();Fc(b,a)",
-    ";Gc(b)};ba(\"_\",function(a){if(!xc(a)||!nc(a)||\"none\"==W(a,\"pointer",
-    "-events\"))throw new u(12,\"Element is not currently interactable and m",
-    "ay not be manipulated\");if(!lc(a))throw new u(12,\"Element must be use",
-    "r-editable in order to clear it.\");if(a.value){Rc(a);a.value=\"\";Dc(a",
-    ",Cc);Dc(a,Bc);var b=ka.document.body;if(b)Rc(b);else throw new u(13,\"C",
-    "annot unfocus element after clearing.\");}else A(a,\"INPUT\")&&a.getAtt",
-    "ribute(\"type\")&&\"number\"==a.getAttribute(\"type\").toLowerCase()&&(",
-    "Rc(a),a.value=\"\");pc(a)&&(Rc(a),a.innerHTML=\n\" \")});; return this.",
-    "_.apply(null,arguments);}.apply({navigator:typeof window!='undefined'?w",
-    "indow.navigator:null,document:typeof window!='undefined'?window.documen",
-    "t:null}, arguments);}",
+    "){if(A(a)&&\"none\"==W(a,\"display\"))return!1;a:{var c=a.parentNode;if",
+    "(a.getDestinationInsertionPoints){var e=a.getDestinationInsertionPoints",
+    "();if(0<e.length){a=e[e.length-1];break a}}a=c&&c.shadowRoot&&void 0!==",
+    "a.assignedSlot?a.assignedSlot?a.assignedSlot.parentNode:null:c}return i",
+    "c&&a instanceof ShadowRoot||a&&(9==a.nodeType||11==a.nodeType)?!0:!!a&&",
+    "b(a)}return sc(a,!0,b)}var X=\"hidden\";\nfunction uc(a){function b(a){",
+    "function b(a){return a==h?!0:0==W(a,\"display\").lastIndexOf(\"inline\"",
+    ",0)||\"absolute\"==c&&\"static\"==W(a,\"position\")?!1:!0}var c=W(a,\"p",
+    "osition\");if(\"fixed\"==c)return G=!0,a==h?null:h;for(a=qc(a);a&&!b(a)",
+    ";)a=qc(a);return a}function c(a){var b=a;if(\"visible\"==y)if(a==h&&m)b",
+    "=m;else if(a==m)return{x:\"visible\",y:\"visible\"};b={x:W(b,\"overflow",
+    "-x\"),y:W(b,\"overflow-y\")};a==h&&(b.x=\"visible\"==b.x?\"auto\":b.x,b",
+    ".y=\"visible\"==b.y?\"auto\":b.y);return b}function d(a){if(a==h){var b",
+    "=(new Xa(f)).M;\na=b.scrollingElement?b.scrollingElement:b.body||b.docu",
+    "mentElement;b=b.parentWindow||b.defaultView;a=new w(b.pageXOffset||a.sc",
+    "rollLeft,b.pageYOffset||a.scrollTop)}else a=new w(a.scrollLeft,a.scroll",
+    "Top);return a}var e=yc(a);var f=x(a),h=f.documentElement,m=f.body,y=W(h",
+    ",\"overflow\"),G;for(a=b(a);a;a=b(a)){var t=c(a);if(\"visible\"!=t.x||",
+    "\"visible\"!=t.y){var z=tc(a);if(0==z.width||0==z.height)return X;var M",
+    "=e.right<z.left,T=e.bottom<z.top;if(M&&\"hidden\"==t.x||T&&\"hidden\"==",
+    "t.y)return X;if(M&&\"visible\"!=t.x||\nT&&\"visible\"!=t.y){M=d(a);T=e.",
+    "bottom<z.top-M.y;if(e.right<z.left-M.x&&\"visible\"!=t.x||T&&\"visible",
+    "\"!=t.x)return X;e=uc(a);return e==X?X:\"scroll\"}M=e.left>=z.left+z.wi",
+    "dth;z=e.top>=z.top+z.height;if(M&&\"hidden\"==t.x||z&&\"hidden\"==t.y)r",
+    "eturn X;if(M&&\"visible\"!=t.x||z&&\"visible\"!=t.y){if(G&&(t=d(a),e.le",
+    "ft>=h.scrollWidth-t.x||e.right>=h.scrollHeight-t.y))return X;e=uc(a);re",
+    "turn e==X?X:\"scroll\"}}}return\"none\"}\nfunction tc(a){var b=vc(a);if",
+    "(b)return b.rect;if(A(a,\"HTML\"))return a=x(a),a=((a?a.parentWindow||a",
+    ".defaultView:window)||window).document,a=\"CSS1Compat\"==a.compatMode?a",
+    ".documentElement:a.body,a=new Na(a.clientWidth,a.clientHeight),new U(0,",
+    "0,a.width,a.height);try{var c=a.getBoundingClientRect()}catch(d){return",
+    " new U(0,0,0,0)}return new U(c.left,c.top,c.right-c.left,c.bottom-c.top",
+    ")}\nfunction vc(a){var b=A(a,\"MAP\");if(!b&&!A(a,\"AREA\"))return null",
+    ";var c=b?a:A(a.parentNode,\"MAP\")?a.parentNode:null,d=null,e=null;c&&c",
+    ".name&&(d=S.za('/descendant::*[@usemap = \"#'+c.name+'\"]',x(c)))&&(e=t",
+    "c(d),b||\"default\"==a.shape.toLowerCase()||(a=zc(a),b=Math.min(Math.ma",
+    "x(a.left,0),e.width),c=Math.min(Math.max(a.top,0),e.height),e=new U(b+e",
+    ".left,c+e.top,Math.min(a.width,e.width-b),Math.min(a.height,e.height-c)",
+    ")));return{fa:d,rect:e||new U(0,0,0,0)}}\nfunction zc(a){var b=a.shape.",
+    "toLowerCase();a=a.coords.split(\",\");if(\"rect\"==b&&4==a.length){var ",
+    "b=a[0],c=a[1];return new U(b,c,a[2]-b,a[3]-c)}if(\"circle\"==b&&3==a.le",
+    "ngth)return b=a[2],new U(a[0]-b,a[1]-b,2*b,2*b);if(\"poly\"==b&&2<a.len",
+    "gth){for(var b=a[0],c=a[1],d=b,e=c,f=2;f+1<a.length;f+=2)b=Math.min(b,a",
+    "[f]),d=Math.max(d,a[f]),c=Math.min(c,a[f+1]),e=Math.max(e,a[f+1]);retur",
+    "n new U(b,c,d-b,e-c)}return new U(0,0,0,0)}function yc(a){a=tc(a);retur",
+    "n new hc(a.top,a.left+a.width,a.top+a.height,a.left)}\nfunction wc(a){v",
+    "ar b=1,c=W(a,\"opacity\");c&&(b=Number(c));(a=qc(a))&&(b*=wc(a));return",
+    " b};Ma();Ma();function Ac(a,b,c){this.B=a;this.pa=b;this.qa=c}Ac.protot",
+    "ype.create=function(a){a=x(a).createEvent(\"HTMLEvents\");a.initEvent(t",
+    "his.B,this.pa,this.qa);return a};Ac.prototype.toString=function(){retur",
+    "n this.B};var Bc=new Ac(\"blur\",!1,!1),Cc=new Ac(\"change\",!0,!1);fun",
+    "ction Dc(a,b){b=b.create(a,void 0);\"isTrusted\"in b||(b.isTrusted=!1);",
+    "a.dispatchEvent(b)};function Ec(){this.N=ka.document.documentElement;va",
+    "r a=Wa(x(this.N));a&&Fc(this,a)}function Fc(a,b){a.N=b;A(b,\"OPTION\")&",
+    "&Va(b,function(a){return A(a,\"SELECT\")})}function Gc(a){var b=Va(a.N,",
+    "function(a){return!!a&&A(a)&&kc(a)},!0),b=b||a.N;a=Wa(x(b));if(b!=a){if",
+    "(a&&ea(a.blur)&&!A(a,\"BODY\"))try{a.blur()}catch(c){throw c;}ea(b.focu",
+    "s)&&b.focus()}};function Hc(a,b){this.w={};this.g=[];this.G=0;var c=arg",
+    "uments.length;if(1<c){if(c%2)throw Error(\"Uneven number of arguments\"",
+    ");for(var d=0;d<c;d+=2)this.set(arguments[d],arguments[d+1])}else a&&th",
+    "is.addAll(a)}function Ic(a){Jc(a);return a.g.concat()}g=Hc.prototype;g.",
+    "clear=function(){this.w={};this.G=this.g.length=0};g.remove=function(a)",
+    "{return Object.prototype.hasOwnProperty.call(this.w,a)?(delete this.w[a",
+    "],this.G--,this.g.length>2*this.G&&Jc(this),!0):!1};\nfunction Jc(a){va",
+    "r b,c;if(a.G!=a.g.length){for(b=c=0;c<a.g.length;){var d=a.g[c];Object.",
+    "prototype.hasOwnProperty.call(a.w,d)&&(a.g[b++]=d);c++}a.g.length=b}if(",
+    "a.G!=a.g.length){var e={};for(b=c=0;c<a.g.length;)d=a.g[c],Object.proto",
+    "type.hasOwnProperty.call(e,d)||(a.g[b++]=d,e[d]=1),c++;a.g.length=b}}g.",
+    "get=function(a,b){return Object.prototype.hasOwnProperty.call(this.w,a)",
+    "?this.w[a]:b};g.set=function(a,b){Object.prototype.hasOwnProperty.call(",
+    "this.w,a)||(this.G++,this.g.push(a));this.w[a]=b};\ng.addAll=function(a",
+    "){if(a instanceof Hc){var b=Ic(a);Jc(a);for(var c=[],d=0;d<a.g.length;d",
+    "++)c.push(a.w[a.g[d]]);a=c}else{b=[];var d=0;for(e in a)b[d++]=e;d=[];v",
+    "ar e=0;for(c in a)d[e++]=a[c];a=d}for(c=0;c<b.length;c++)this.set(b[c],",
+    "a[c])};g.forEach=function(a,b){for(var c=Ic(this),d=0;d<c.length;d++){v",
+    "ar e=c[d],f=this.get(e);a.call(b,f,e,this)}};g.clone=function(){return ",
+    "new Hc(this)};var Kc={};function Y(a,b,c){fa(a)&&(a=a.b);a=new Lc(a);!b",
+    "||b in Kc&&!c||(Kc[b]={key:a,shift:!1},c&&(Kc[c]={key:a,shift:!0}));ret",
+    "urn a}function Lc(a){this.code=a}Y(8);Y(9);Y(13);var Mc=Y(16),Nc=Y(17),",
+    "Oc=Y(18);Y(19);Y(20);Y(27);Y(32,\" \");Y(33);Y(34);Y(35);Y(36);Y(37);Y(",
+    "38);Y(39);Y(40);Y(44);Y(45);Y(46);Y(48,\"0\",\")\");Y(49,\"1\",\"!\");Y",
+    "(50,\"2\",\"@\");Y(51,\"3\",\"#\");Y(52,\"4\",\"$\");Y(53,\"5\",\"%\");",
+    "Y(54,\"6\",\"^\");Y(55,\"7\",\"&\");Y(56,\"8\",\"*\");Y(57,\"9\",\"(\")",
+    ";Y(65,\"a\",\"A\");Y(66,\"b\",\"B\");Y(67,\"c\",\"C\");Y(68,\"d\",\"D\"",
+    ");\nY(69,\"e\",\"E\");Y(70,\"f\",\"F\");Y(71,\"g\",\"G\");Y(72,\"h\",\"",
+    "H\");Y(73,\"i\",\"I\");Y(74,\"j\",\"J\");Y(75,\"k\",\"K\");Y(76,\"l\",",
+    "\"L\");Y(77,\"m\",\"M\");Y(78,\"n\",\"N\");Y(79,\"o\",\"O\");Y(80,\"p\"",
+    ",\"P\");Y(81,\"q\",\"Q\");Y(82,\"r\",\"R\");Y(83,\"s\",\"S\");Y(84,\"t",
+    "\",\"T\");Y(85,\"u\",\"U\");Y(86,\"v\",\"V\");Y(87,\"w\",\"W\");Y(88,\"",
+    "x\",\"X\");Y(89,\"y\",\"Y\");Y(90,\"z\",\"Z\");var Pc=Y(Ia?{c:91,b:91}:",
+    "Ha?{c:224,b:91}:{c:0,b:91});Y(Ia?{c:92,b:92}:Ha?{c:224,b:93}:{c:0,b:92}",
+    ");Y(Ia?{c:93,b:93}:Ha?{c:0,b:0}:{c:93,b:null});Y({c:96,b:96},\"0\");Y({",
+    "c:97,b:97},\"1\");\nY({c:98,b:98},\"2\");Y({c:99,b:99},\"3\");Y({c:100,",
+    "b:100},\"4\");Y({c:101,b:101},\"5\");Y({c:102,b:102},\"6\");Y({c:103,b:",
+    "103},\"7\");Y({c:104,b:104},\"8\");Y({c:105,b:105},\"9\");Y({c:106,b:10",
+    "6},\"*\");Y({c:107,b:107},\"+\");Y({c:109,b:109},\"-\");Y({c:110,b:110}",
+    ",\".\");Y({c:111,b:111},\"/\");Y(144);Y(112);Y(113);Y(114);Y(115);Y(116",
+    ");Y(117);Y(118);Y(119);Y(120);Y(121);Y(122);Y(123);Y({c:107,b:187},\"=",
+    "\",\"+\");Y(108,\",\");Y({c:109,b:189},\"-\",\"_\");Y(188,\",\",\"<\");",
+    "Y(190,\".\",\">\");Y(191,\"/\",\"?\");Y(192,\"`\",\"~\");Y(219,\"[\",\"",
+    "{\");\nY(220,\"\\\\\",\"|\");Y(221,\"]\",\"}\");Y({c:59,b:186},\";\",\"",
+    ":\");Y(222,\"'\",'\"');var Qc=new Hc;Qc.set(1,Mc);Qc.set(2,Nc);Qc.set(4",
+    ",Oc);Qc.set(8,Pc);(function(a){var b=new Hc;q(Ic(a),function(c){b.set(a",
+    ".get(c).code,c)});return b})(Qc);function Z(){Ec.call(this)}p(Z,Ec);Z.W",
+    "=void 0;Z.ra=function(){return Z.W?Z.W:Z.W=new Z};function Rc(a){var b=",
+    "Z.ra();Fc(b,a);Gc(b)};ba(\"_\",function(a){if(!xc(a)||!nc(a)||\"none\"=",
+    "=W(a,\"pointer-events\"))throw new u(12,\"Element is not currently inte",
+    "ractable and may not be manipulated\");if(!lc(a))throw new u(12,\"Eleme",
+    "nt must be user-editable in order to clear it.\");if(a.value){Rc(a);a.v",
+    "alue=\"\";Dc(a,Cc);Dc(a,Bc);var b=ka.document.body;if(b)Rc(b);else thro",
+    "w new u(13,\"Cannot unfocus element after clearing.\");}else A(a,\"INPU",
+    "T\")&&a.getAttribute(\"type\")&&\"number\"==a.getAttribute(\"type\").to",
+    "LowerCase()&&(Rc(a),a.value=\"\");pc(a)&&(Rc(a),a.innerHTML=\n\" \")});",
+    "; return this._.apply(null,arguments);}.apply({navigator:typeof window!",
+    "='undefined'?window.navigator:null,document:typeof window!='undefined'?",
+    "window.document:null}, arguments);}",
     NULL
 };
 
@@ -1397,208 +1397,208 @@
     "ight&&Ec(f.sa,b,c);if(B(a,\"INPUT\")&&\"hidden\"==a.type.toLowerCase()|",
     "|B(a,\"NOSCRIPT\"))return!1;f=T(a,\"visibility\");return\"collapse\"!=f",
     "&&\"hidden\"!=f&&c(a)&&(b||0!=Ic(a))&&d(a)?!e(a):!1}\nfunction uc(a){fu",
-    "nction b(a){if(B(a)&&\"none\"==T(a,\"display\"))return!1;var c;(c=a.par",
-    "entNode)&&c.shadowRoot&&void 0!==a.assignedSlot?c=a.assignedSlot?a.assi",
-    "gnedSlot.parentNode:null:a.getDestinationInsertionPoints&&(a=a.getDesti",
-    "nationInsertionPoints(),0<a.length&&(c=a[a.length-1]));return sc&&c ins",
-    "tanceof ShadowRoot||c&&(9==c.nodeType||11==c.nodeType)?!0:!!c&&b(c)}ret",
-    "urn Ec(a,!0,b)}var V=\"hidden\";\nfunction Gc(a,b){function c(a){functi",
-    "on b(a){return a==h?!0:0==T(a,\"display\").lastIndexOf(\"inline\",0)||",
-    "\"absolute\"==c&&\"static\"==T(a,\"position\")?!1:!0}var c=T(a,\"positi",
-    "on\");if(\"fixed\"==c)return y=!0,a==h?null:h;for(a=Cc(a);a&&!b(a);)a=C",
-    "c(a);return a}function d(a){var b=a;if(\"visible\"==q)if(a==h&&l)b=l;el",
-    "se if(a==l)return{x:\"visible\",y:\"visible\"};b={x:T(b,\"overflow-x\")",
-    ",y:T(b,\"overflow-y\")};a==h&&(b.x=\"visible\"==b.x?\"auto\":b.x,b.y=\"",
-    "visible\"==b.y?\"auto\":b.y);return b}function e(a){if(a==h){var b=(new",
-    " bb(f)).R;\na=b.scrollingElement?b.scrollingElement:b.body||b.documentE",
-    "lement;b=b.parentWindow||b.defaultView;a=new z(b.pageXOffset||a.scrollL",
-    "eft,b.pageYOffset||a.scrollTop)}else a=new z(a.scrollLeft,a.scrollTop);",
-    "return a}b=Jc(a,b);var f=A(a),h=f.documentElement,l=f.body,q=T(h,\"over",
-    "flow\"),y;for(a=c(a);a;a=c(a)){var r=d(a);if(\"visible\"!=r.x||\"visibl",
-    "e\"!=r.y){var v=Fc(a);if(0==v.width||0==v.height)return V;var J=b.right",
-    "<v.left,U=b.bottom<v.top;if(J&&\"hidden\"==r.x||U&&\"hidden\"==r.y)retu",
-    "rn V;if(J&&\"visible\"!=r.x||\nU&&\"visible\"!=r.y){J=e(a);U=b.bottom<v",
-    ".top-J.y;if(b.right<v.left-J.x&&\"visible\"!=r.x||U&&\"visible\"!=r.x)r",
-    "eturn V;b=Gc(a);return b==V?V:\"scroll\"}J=b.left>=v.left+v.width;v=b.t",
-    "op>=v.top+v.height;if(J&&\"hidden\"==r.x||v&&\"hidden\"==r.y)return V;i",
-    "f(J&&\"visible\"!=r.x||v&&\"visible\"!=r.y){if(y&&(r=e(a),b.left>=h.scr",
-    "ollWidth-r.x||b.right>=h.scrollHeight-r.y))return V;b=Gc(a);return b==V",
-    "?V:\"scroll\"}}}return\"none\"}\nfunction Fc(a){var b=Hc(a);if(b)return",
-    " b.rect;if(B(a,\"HTML\"))return a=A(a),a=(Sa(a)||window).document,a=\"C",
-    "SS1Compat\"==a.compatMode?a.documentElement:a.body,a=new Ra(a.clientWid",
-    "th,a.clientHeight),new S(0,0,a.width,a.height);try{var c=a.getBoundingC",
-    "lientRect()}catch(d){return new S(0,0,0,0)}return new S(c.left,c.top,c.",
-    "right-c.left,c.bottom-c.top)}\nfunction Hc(a){var b=B(a,\"MAP\");if(!b&",
-    "&!B(a,\"AREA\"))return null;var c=b?a:B(a.parentNode,\"MAP\")?a.parentN",
-    "ode:null,d=null,e=null;c&&c.name&&(d=R.Ja('/descendant::*[@usemap = \"#",
-    "'+c.name+'\"]',A(c)))&&(e=Fc(d),b||\"default\"==a.shape.toLowerCase()||",
-    "(a=Kc(a),b=Math.min(Math.max(a.left,0),e.width),c=Math.min(Math.max(a.t",
-    "op,0),e.height),e=new S(b+e.left,c+e.top,Math.min(a.width,e.width-b),Ma",
-    "th.min(a.height,e.height-c))));return{sa:d,rect:e||new S(0,0,0,0)}}\nfu",
-    "nction Kc(a){var b=a.shape.toLowerCase();a=a.coords.split(\",\");if(\"r",
-    "ect\"==b&&4==a.length){var b=a[0],c=a[1];return new S(b,c,a[2]-b,a[3]-c",
-    ")}if(\"circle\"==b&&3==a.length)return b=a[2],new S(a[0]-b,a[1]-b,2*b,2",
-    "*b);if(\"poly\"==b&&2<a.length){for(var b=a[0],c=a[1],d=b,e=c,f=2;f+1<a",
-    ".length;f+=2)b=Math.min(b,a[f]),d=Math.max(d,a[f]),c=Math.min(c,a[f+1])",
-    ",e=Math.max(e,a[f+1]);return new S(b,c,d-b,e-c)}return new S(0,0,0,0)}",
-    "\nfunction Jc(a,b){a=Fc(a);a=new pc(a.top,a.left+a.width,a.top+a.height",
-    ",a.left);b&&(b=b instanceof S?b:new S(b.x,b.y,1,1),a.left=Math.min(Math",
-    ".max(a.left+b.left,a.left),a.right),a.top=Math.min(Math.max(a.top+b.top",
-    ",a.top),a.bottom),a.right=Math.min(Math.max(a.left+b.width,a.left),a.ri",
-    "ght),a.bottom=Math.min(Math.max(a.top+b.height,a.top),a.bottom));return",
-    " a}function Ic(a){var b=1,c=T(a,\"opacity\");c&&(b=Number(c));(a=Cc(a))",
-    "&&(b*=Ic(a));return b};Na();Na();function Lc(a,b,c){this.B=a;this.la=b;",
-    "this.ma=c}Lc.prototype.create=function(a){a=A(a).createEvent(\"HTMLEven",
-    "ts\");a.initEvent(this.B,this.la,this.ma);return a};Lc.prototype.toStri",
-    "ng=function(){return this.B};function W(a,b,c){Lc.call(this,a,b,c)}p(W,",
-    "Lc);\nW.prototype.create=function(a,b){if(this==Mc)throw new u(9,\"Brow",
-    "ser does not support a mouse pixel scroll event.\");var c=A(a);a=Sa(c);",
-    "c=c.createEvent(\"MouseEvents\");this==Nc&&(c.wheelDelta=b.wheelDelta);",
-    "c.initMouseEvent(this.B,this.la,this.ma,a,1,b.clientX,b.clientY,b.clien",
-    "tX,b.clientY,b.ctrlKey,b.altKey,b.shiftKey,b.metaKey,b.button,b.related",
-    "Target);return c};function X(a,b,c){Lc.call(this,a,b,c)}p(X,Lc);X.proto",
-    "type.create=function(){throw new u(9,\"Browser does not support MSPoint",
-    "er events.\");};\nvar Oc=new Lc(\"change\",!0,!1),Pc=new W(\"click\",!0",
-    ",!0),Qc=new W(\"contextmenu\",!0,!0),Rc=new W(\"dblclick\",!0,!0),Sc=ne",
-    "w W(\"mousedown\",!0,!0),Tc=new W(\"mousemove\",!0,!1),Uc=new W(\"mouse",
-    "out\",!0,!0),Vc=new W(\"mouseover\",!0,!0),Wc=new W(\"mouseup\",!0,!0),",
-    "Nc=new W(\"mousewheel\",!0,!0),Mc=new W(\"MozMousePixelScroll\",!0,!0),",
-    "Xc=new X(\"MSGotPointerCapture\",!0,!1),Yc=new X(\"MSLostPointerCapture",
-    "\",!0,!1),Zc=new X(\"MSPointerDown\",!0,!0),$c=new X(\"MSPointerMove\",",
-    "!0,!0),ad=new X(\"MSPointerOver\",!0,!0),bd=new X(\"MSPointerOut\",\n!0",
-    ",!0),cd=new X(\"MSPointerUp\",!0,!0);function dd(a,b,c){b=b.create(a,c)",
-    ";\"isTrusted\"in b||(b.isTrusted=!1);return a.dispatchEvent(b)};functio",
-    "n ed(a,b){this.g=ka.document.documentElement;this.G=null;var c=ab(A(thi",
-    "s.g));c&&fd(this,c);this.$=a||new gd;this.pa=b||new hd}ed.prototype.I=f",
-    "unction(){return this.g};function fd(a,b){a.g=b;a.G=B(b,\"OPTION\")?$a(",
-    "b,function(a){return B(a,\"SELECT\")}):null}\ned.prototype.W=function(a",
-    ",b,c,d,e,f,h,l){if(!f&&!tc(this.g))return!1;if(d&&Vc!=a&&Uc!=a)throw ne",
-    "w u(12,\"Event type does not allow related target: \"+a);b={clientX:b.x",
-    ",clientY:b.y,button:c,altKey:0!=(this.$.ca&4),ctrlKey:0!=(this.$.ca&2),",
-    "shiftKey:0!=(this.$.ca&1),metaKey:0!=(this.$.ca&8),wheelDelta:e||0,rela",
-    "tedTarget:d||null,count:l||1};h=h||1;c=this.g;a!=Pc&&a!=Sc&&h in id?c=i",
-    "d[h]:this.G&&(c=jd(this,a));return c?this.pa.W(c,a,b):!0};\ned.prototyp",
-    "e.S=function(a,b,c,d,e,f,h,l){if(!l&&!tc(this.g))return!1;if(h&&ad!=a&&",
-    "bd!=a)throw new u(12,\"Event type does not allow related target: \"+a);",
-    "b={clientX:b.x,clientY:b.y,button:c,altKey:!1,ctrlKey:!1,shiftKey:!1,me",
-    "taKey:!1,relatedTarget:h||null,width:0,height:0,pressure:0,rotation:0,p",
-    "ointerId:d,tiltX:0,tiltY:0,pointerType:e,isPrimary:f};c=this.G?jd(this,",
-    "a):this.g;id[d]&&(c=id[d]);d=Sa(A(this.g));if(d&&a==Zc){var q=d.Element",
-    ".prototype.msSetPointerCapture;d.Element.prototype.msSetPointerCapture=",
-    "\nfunction(a){id[a]=this}}a=c?this.pa.S(c,a,b):!0;q&&(d.Element.prototy",
-    "pe.msSetPointerCapture=q);return a};function jd(a,b){switch(b){case Pc:",
-    "case Wc:return a.G.multiple?a.g:a.G;default:return a.G.multiple?a.g:nul",
-    "l}}function kd(a){var b=$a(a.g,function(a){return!!a&&B(a)&&xc(a)},!0),",
-    "b=b||a.g;a=ab(A(b));if(b!=a){if(a&&ea(a.blur)&&!B(a,\"BODY\"))try{a.blu",
-    "r()}catch(c){throw c;}ea(b.focus)&&b.focus()}}function gd(){this.ca=0}v",
-    "ar id={};function hd(){}hd.prototype.W=function(a,b,c){return dd(a,b,c)",
-    "};\nhd.prototype.S=function(a,b,c){return dd(a,b,c)};function ld(a,b){t",
-    "his.D={};this.h=[];this.M=0;var c=arguments.length;if(1<c){if(c%2)throw",
-    " Error(\"Uneven number of arguments\");for(var d=0;d<c;d+=2)this.set(ar",
-    "guments[d],arguments[d+1])}else a&&this.addAll(a)}function md(a){nd(a);",
-    "return a.h.concat()}g=ld.prototype;g.clear=function(){this.D={};this.M=",
-    "this.h.length=0};g.remove=function(a){return Object.prototype.hasOwnPro",
-    "perty.call(this.D,a)?(delete this.D[a],this.M--,this.h.length>2*this.M&",
-    "&nd(this),!0):!1};\nfunction nd(a){var b,c;if(a.M!=a.h.length){for(b=c=",
-    "0;c<a.h.length;){var d=a.h[c];Object.prototype.hasOwnProperty.call(a.D,",
-    "d)&&(a.h[b++]=d);c++}a.h.length=b}if(a.M!=a.h.length){var e={};for(b=c=",
-    "0;c<a.h.length;)d=a.h[c],Object.prototype.hasOwnProperty.call(e,d)||(a.",
-    "h[b++]=d,e[d]=1),c++;a.h.length=b}}g.get=function(a,b){return Object.pr",
-    "ototype.hasOwnProperty.call(this.D,a)?this.D[a]:b};g.set=function(a,b){",
-    "Object.prototype.hasOwnProperty.call(this.D,a)||(this.M++,this.h.push(a",
-    "));this.D[a]=b};\ng.addAll=function(a){if(a instanceof ld){var b=md(a);",
-    "nd(a);for(var c=[],d=0;d<a.h.length;d++)c.push(a.D[a.h[d]]);a=c}else{b=",
-    "[];var d=0;for(e in a)b[d++]=e;d=[];var e=0;for(c in a)d[e++]=a[c];a=d}",
-    "for(c=0;c<b.length;c++)this.set(b[c],a[c])};g.forEach=function(a,b){for",
-    "(var c=md(this),d=0;d<c.length;d++){var e=c[d],f=this.get(e);a.call(b,f",
-    ",e,this)}};g.clone=function(){return new ld(this)};var od={};function Y",
-    "(a,b,c){fa(a)&&(a=a.b);a=new pd(a);!b||b in od&&!c||(od[b]={key:a,shift",
-    ":!1},c&&(od[c]={key:a,shift:!0}));return a}function pd(a){this.code=a}Y",
-    "(8);Y(9);Y(13);var qd=Y(16),rd=Y(17),sd=Y(18);Y(19);Y(20);Y(27);Y(32,\"",
-    " \");Y(33);Y(34);Y(35);Y(36);Y(37);Y(38);Y(39);Y(40);Y(44);Y(45);Y(46);",
-    "Y(48,\"0\",\")\");Y(49,\"1\",\"!\");Y(50,\"2\",\"@\");Y(51,\"3\",\"#\")",
-    ";Y(52,\"4\",\"$\");Y(53,\"5\",\"%\");Y(54,\"6\",\"^\");Y(55,\"7\",\"&\"",
-    ");Y(56,\"8\",\"*\");Y(57,\"9\",\"(\");Y(65,\"a\",\"A\");Y(66,\"b\",\"B",
-    "\");Y(67,\"c\",\"C\");Y(68,\"d\",\"D\");\nY(69,\"e\",\"E\");Y(70,\"f\",",
-    "\"F\");Y(71,\"g\",\"G\");Y(72,\"h\",\"H\");Y(73,\"i\",\"I\");Y(74,\"j\"",
-    ",\"J\");Y(75,\"k\",\"K\");Y(76,\"l\",\"L\");Y(77,\"m\",\"M\");Y(78,\"n",
-    "\",\"N\");Y(79,\"o\",\"O\");Y(80,\"p\",\"P\");Y(81,\"q\",\"Q\");Y(82,\"",
-    "r\",\"R\");Y(83,\"s\",\"S\");Y(84,\"t\",\"T\");Y(85,\"u\",\"U\");Y(86,",
-    "\"v\",\"V\");Y(87,\"w\",\"W\");Y(88,\"x\",\"X\");Y(89,\"y\",\"Y\");Y(90",
-    ",\"z\",\"Z\");var td=Y(Ja?{c:91,b:91}:Ia?{c:224,b:91}:{c:0,b:91});Y(Ja?",
-    "{c:92,b:92}:Ia?{c:224,b:93}:{c:0,b:92});Y(Ja?{c:93,b:93}:Ia?{c:0,b:0}:{",
-    "c:93,b:null});Y({c:96,b:96},\"0\");Y({c:97,b:97},\"1\");\nY({c:98,b:98}",
-    ",\"2\");Y({c:99,b:99},\"3\");Y({c:100,b:100},\"4\");Y({c:101,b:101},\"5",
-    "\");Y({c:102,b:102},\"6\");Y({c:103,b:103},\"7\");Y({c:104,b:104},\"8\"",
-    ");Y({c:105,b:105},\"9\");Y({c:106,b:106},\"*\");Y({c:107,b:107},\"+\");",
-    "Y({c:109,b:109},\"-\");Y({c:110,b:110},\".\");Y({c:111,b:111},\"/\");Y(",
-    "144);Y(112);Y(113);Y(114);Y(115);Y(116);Y(117);Y(118);Y(119);Y(120);Y(1",
-    "21);Y(122);Y(123);Y({c:107,b:187},\"=\",\"+\");Y(108,\",\");Y({c:109,b:",
-    "189},\"-\",\"_\");Y(188,\",\",\"<\");Y(190,\".\",\">\");Y(191,\"/\",\"?",
-    "\");Y(192,\"`\",\"~\");Y(219,\"[\",\"{\");\nY(220,\"\\\\\",\"|\");Y(221",
-    ",\"]\",\"}\");Y({c:59,b:186},\";\",\":\");Y(222,\"'\",'\"');var ud=new ",
-    "ld;ud.set(1,qd);ud.set(2,rd);ud.set(4,sd);ud.set(8,td);(function(a){var",
-    " b=new ld;t(md(a),function(c){b.set(a.get(c).code,c)});return b})(ud);f",
-    "unction vd(a,b,c){ed.call(this,b,c);this.K=this.j=null;this.C=new z(0,0",
-    ");this.Y=this.N=!1;if(a){n(a.buttonPressed)&&(this.j=a.buttonPressed);t",
-    "ry{B(a.elementPressed)&&(this.K=a.elementPressed)}catch(d){this.j=null}",
-    "this.C=new z(a.clientXY.x,a.clientXY.y);this.N=!!a.nextClickIsDoubleCli",
-    "ck;this.Y=!!a.hasEverInteracted;try{a.element&&B(a.element)&&fd(this,a.",
-    "element)}catch(d){this.j=null}}}p(vd,ed);var Z={};Z[Pc]=[0,1,2,null];Z[",
-    "Qc]=[null,null,2,null];Z[Wc]=[0,1,2,null];Z[Uc]=[0,1,2,4];Z[Tc]=[0,1,2,",
-    "4];\nQa&&(Z[Zc]=Z[Wc],Z[cd]=Z[Wc],Z[$c]=[-1,-1,-1,-1],Z[bd]=Z[$c],Z[ad]",
-    "=Z[$c]);Z[Rc]=Z[Pc];Z[Sc]=Z[Wc];Z[Vc]=Z[Uc];var wd={};wd[Sc]=Zc;wd[Tc]=",
-    "$c;wd[Uc]=bd;wd[Vc]=ad;wd[Wc]=cd;vd.prototype.move=function(a,b){var c=",
-    "tc(a),d=Fc(a);this.C.x=b.x+d.left;this.C.y=b.y+d.top;b=this.I();if(a!=b",
-    "){try{Sa(A(b)).closed&&(b=null)}catch(e){b=null}b&&(d=b===ka.document.d",
-    "ocumentElement||b===ka.document.body,b=!this.Y&&d?null:b,xd(this,Uc,a))",
-    ";fd(this,a);xd(this,Vc,b,null,c)}xd(this,Tc,null,null,c);this.N=!1};\nv",
-    "d.prototype.scroll=function(a){if(0==a)throw new u(13,\"Must scroll a n",
-    "on-zero number of ticks.\");for(var b=0<a?-120:120,c=0;c<Math.abs(a);c+",
-    "+)xd(this,Nc,null,b)};function xd(a,b,c,d,e,f){a.Y=!0;if(Qa){var h=wd[b",
-    "];if(h&&!a.S(h,a.C,yd(a,h),1,MSPointerEvent.MSPOINTER_TYPE_MOUSE,!0,c,e",
-    "))return!1}return a.W(b,a.C,yd(a,b),c,d,e,null,f)}function yd(a,b){if(!",
-    "(b in Z))return 0;a=Z[b][null===a.j?3:a.j];if(null===a)throw new u(13,",
-    "\"Event does not permit the specified mouse button.\");return a}\nvd.pr",
-    "ototype.getState=function(){return{buttonPressed:this.j,elementPressed:",
-    "this.K,clientXY:{x:this.C.x,y:this.C.y},nextClickIsDoubleClick:this.N,h",
-    "asEverInteracted:this.Y,element:this.I()}};function zd(a,b){this.x=a;th",
-    "is.y=b}p(zd,z);g=zd.prototype;g.clone=function(){return new zd(this.x,t",
-    "his.y)};g.scale=z.prototype.scale;g.normalize=function(){return this.sc",
-    "ale(1/Math.sqrt(this.x*this.x+this.y*this.y))};g.add=function(a){this.x",
-    "+=a.x;this.y+=a.y;return this};g.rotate=function(a){var b=Math.cos(a);a",
-    "=Math.sin(a);var c=this.y*b+this.x*a;this.x=this.x*b-this.y*a;this.y=c;",
-    "return this};function Ad(a){var b;(b=qc(a,\"display\"))||(b=a.currentSt",
-    "yle?a.currentStyle.display:null);if(\"none\"!=(b||a.style&&a.style.disp",
-    "lay))b=rc(a);else{b=a.style;var c=b.display,d=b.visibility,e=b.position",
-    ";b.visibility=\"hidden\";b.position=\"absolute\";b.display=\"inline\";v",
-    "ar f=rc(a);b.display=c;b.position=e;b.visibility=d;b=f}return 0<b.width",
-    "&&0<b.height||!a.offsetParent?b:Ad(a.offsetParent)};ba(\"_\",function(a",
-    ",b,c,d){if(!uc(a))throw new u(11,\"Element is not currently visible and",
-    " may not be manipulated\");b:{var e=b||void 0;if(\"scroll\"==Gc(a,e)){i",
-    "f(a.scrollIntoView&&(a.scrollIntoView(),\"none\"==Gc(a,e)))break b;for(",
-    "var f=Jc(a,e),h=Cc(a);h;h=Cc(h)){var l=h,q=Fc(l);var y=l;var r=qc(y,\"b",
-    "orderLeftWidth\");var v=qc(y,\"borderRightWidth\");var J=qc(y,\"borderT",
-    "opWidth\");y=qc(y,\"borderBottomWidth\");v=new pc(parseFloat(J),parseFl",
-    "oat(v),parseFloat(y),parseFloat(r));r=f.left-q.left-v.left;q=f.top-q.to",
-    "p-\nv.top;v=l.clientHeight+f.top-f.bottom;l.scrollLeft+=Math.min(r,Math",
-    ".max(r-(l.clientWidth+f.left-f.right),0));l.scrollTop+=Math.min(q,Math.",
-    "max(q-v,0))}Gc(a,e)}}b?b=new zd(b.x,b.y):(b=Ad(a),b=new zd(b.width/2,b.",
-    "height/2));c=c||new vd;c.move(a,b);if(null!==c.j)throw new u(13,\"Canno",
-    "t press more than one button or an already pressed button.\");c.j=0;c.K",
-    "=c.I();if(B(c.I(),\"OPTION\")||B(c.I(),\"SELECT\")||xd(c,Sc,null,null,!",
-    "1,void 0))Qa&&0==c.j&&B(c.K,\"OPTION\")&&c.S(Xc,c.C,0,1,MSPointerEvent.",
-    "MSPOINTER_TYPE_MOUSE,\n!0),kd(c);if(null===c.j)throw new u(13,\"Cannot ",
-    "release a button when no button is pressed.\");c.G&&tc(c.g)&&(a=c.G,b=g",
-    "b(c.g),!b||a.multiple)&&(c.g.selected=!b,a.multiple&&!(0<=na(Pa,28))||d",
-    "d(a,Oc));a=tc(c.I());xd(c,Wc,null,null,d,void 0);try{if(0==c.j&&c.I()==",
-    "c.K){var U=c.C,ma=yd(c,Pc);if(a||tc(c.g))!c.G&&fb(c.g)&&gb(c.g),c.W(Pc,",
-    "U,ma,null,0,a,void 0);c.N&&xd(c,Rc);c.N=!c.N;Qa&&0==c.j&&B(c.K,\"OPTION",
-    "\")&&c.S(Yc,new z(0,0),0,1,MSPointerEvent.MSPOINTER_TYPE_MOUSE,!1)}else",
-    " 2==c.j&&xd(c,Qc)}catch(Bd){}id=\n{};c.j=null;c.K=null});; return this.",
-    "_.apply(null,arguments);}.apply({navigator:typeof window!='undefined'?w",
-    "indow.navigator:null,document:typeof window!='undefined'?window.documen",
-    "t:null}, arguments);}",
+    "nction b(a){if(B(a)&&\"none\"==T(a,\"display\"))return!1;a:{var c=a.par",
+    "entNode;if(a.getDestinationInsertionPoints){var e=a.getDestinationInser",
+    "tionPoints();if(0<e.length){a=e[e.length-1];break a}}a=c&&c.shadowRoot&",
+    "&void 0!==a.assignedSlot?a.assignedSlot?a.assignedSlot.parentNode:null:",
+    "c}return sc&&a instanceof ShadowRoot||a&&(9==a.nodeType||11==a.nodeType",
+    ")?!0:!!a&&b(a)}return Ec(a,!0,b)}var V=\"hidden\";\nfunction Gc(a,b){fu",
+    "nction c(a){function b(a){return a==h?!0:0==T(a,\"display\").lastIndexO",
+    "f(\"inline\",0)||\"absolute\"==c&&\"static\"==T(a,\"position\")?!1:!0}v",
+    "ar c=T(a,\"position\");if(\"fixed\"==c)return y=!0,a==h?null:h;for(a=Cc",
+    "(a);a&&!b(a);)a=Cc(a);return a}function d(a){var b=a;if(\"visible\"==q)",
+    "if(a==h&&l)b=l;else if(a==l)return{x:\"visible\",y:\"visible\"};b={x:T(",
+    "b,\"overflow-x\"),y:T(b,\"overflow-y\")};a==h&&(b.x=\"visible\"==b.x?\"",
+    "auto\":b.x,b.y=\"visible\"==b.y?\"auto\":b.y);return b}function e(a){if",
+    "(a==h){var b=(new bb(f)).R;\na=b.scrollingElement?b.scrollingElement:b.",
+    "body||b.documentElement;b=b.parentWindow||b.defaultView;a=new z(b.pageX",
+    "Offset||a.scrollLeft,b.pageYOffset||a.scrollTop)}else a=new z(a.scrollL",
+    "eft,a.scrollTop);return a}b=Jc(a,b);var f=A(a),h=f.documentElement,l=f.",
+    "body,q=T(h,\"overflow\"),y;for(a=c(a);a;a=c(a)){var r=d(a);if(\"visible",
+    "\"!=r.x||\"visible\"!=r.y){var v=Fc(a);if(0==v.width||0==v.height)retur",
+    "n V;var J=b.right<v.left,U=b.bottom<v.top;if(J&&\"hidden\"==r.x||U&&\"h",
+    "idden\"==r.y)return V;if(J&&\"visible\"!=r.x||\nU&&\"visible\"!=r.y){J=",
+    "e(a);U=b.bottom<v.top-J.y;if(b.right<v.left-J.x&&\"visible\"!=r.x||U&&",
+    "\"visible\"!=r.x)return V;b=Gc(a);return b==V?V:\"scroll\"}J=b.left>=v.",
+    "left+v.width;v=b.top>=v.top+v.height;if(J&&\"hidden\"==r.x||v&&\"hidden",
+    "\"==r.y)return V;if(J&&\"visible\"!=r.x||v&&\"visible\"!=r.y){if(y&&(r=",
+    "e(a),b.left>=h.scrollWidth-r.x||b.right>=h.scrollHeight-r.y))return V;b",
+    "=Gc(a);return b==V?V:\"scroll\"}}}return\"none\"}\nfunction Fc(a){var b",
+    "=Hc(a);if(b)return b.rect;if(B(a,\"HTML\"))return a=A(a),a=(Sa(a)||wind",
+    "ow).document,a=\"CSS1Compat\"==a.compatMode?a.documentElement:a.body,a=",
+    "new Ra(a.clientWidth,a.clientHeight),new S(0,0,a.width,a.height);try{va",
+    "r c=a.getBoundingClientRect()}catch(d){return new S(0,0,0,0)}return new",
+    " S(c.left,c.top,c.right-c.left,c.bottom-c.top)}\nfunction Hc(a){var b=B",
+    "(a,\"MAP\");if(!b&&!B(a,\"AREA\"))return null;var c=b?a:B(a.parentNode,",
+    "\"MAP\")?a.parentNode:null,d=null,e=null;c&&c.name&&(d=R.Ja('/descendan",
+    "t::*[@usemap = \"#'+c.name+'\"]',A(c)))&&(e=Fc(d),b||\"default\"==a.sha",
+    "pe.toLowerCase()||(a=Kc(a),b=Math.min(Math.max(a.left,0),e.width),c=Mat",
+    "h.min(Math.max(a.top,0),e.height),e=new S(b+e.left,c+e.top,Math.min(a.w",
+    "idth,e.width-b),Math.min(a.height,e.height-c))));return{sa:d,rect:e||ne",
+    "w S(0,0,0,0)}}\nfunction Kc(a){var b=a.shape.toLowerCase();a=a.coords.s",
+    "plit(\",\");if(\"rect\"==b&&4==a.length){var b=a[0],c=a[1];return new S",
+    "(b,c,a[2]-b,a[3]-c)}if(\"circle\"==b&&3==a.length)return b=a[2],new S(a",
+    "[0]-b,a[1]-b,2*b,2*b);if(\"poly\"==b&&2<a.length){for(var b=a[0],c=a[1]",
+    ",d=b,e=c,f=2;f+1<a.length;f+=2)b=Math.min(b,a[f]),d=Math.max(d,a[f]),c=",
+    "Math.min(c,a[f+1]),e=Math.max(e,a[f+1]);return new S(b,c,d-b,e-c)}retur",
+    "n new S(0,0,0,0)}\nfunction Jc(a,b){a=Fc(a);a=new pc(a.top,a.left+a.wid",
+    "th,a.top+a.height,a.left);b&&(b=b instanceof S?b:new S(b.x,b.y,1,1),a.l",
+    "eft=Math.min(Math.max(a.left+b.left,a.left),a.right),a.top=Math.min(Mat",
+    "h.max(a.top+b.top,a.top),a.bottom),a.right=Math.min(Math.max(a.left+b.w",
+    "idth,a.left),a.right),a.bottom=Math.min(Math.max(a.top+b.height,a.top),",
+    "a.bottom));return a}function Ic(a){var b=1,c=T(a,\"opacity\");c&&(b=Num",
+    "ber(c));(a=Cc(a))&&(b*=Ic(a));return b};Na();Na();function Lc(a,b,c){th",
+    "is.B=a;this.la=b;this.ma=c}Lc.prototype.create=function(a){a=A(a).creat",
+    "eEvent(\"HTMLEvents\");a.initEvent(this.B,this.la,this.ma);return a};Lc",
+    ".prototype.toString=function(){return this.B};function W(a,b,c){Lc.call",
+    "(this,a,b,c)}p(W,Lc);\nW.prototype.create=function(a,b){if(this==Mc)thr",
+    "ow new u(9,\"Browser does not support a mouse pixel scroll event.\");va",
+    "r c=A(a);a=Sa(c);c=c.createEvent(\"MouseEvents\");this==Nc&&(c.wheelDel",
+    "ta=b.wheelDelta);c.initMouseEvent(this.B,this.la,this.ma,a,1,b.clientX,",
+    "b.clientY,b.clientX,b.clientY,b.ctrlKey,b.altKey,b.shiftKey,b.metaKey,b",
+    ".button,b.relatedTarget);return c};function X(a,b,c){Lc.call(this,a,b,c",
+    ")}p(X,Lc);X.prototype.create=function(){throw new u(9,\"Browser does no",
+    "t support MSPointer events.\");};\nvar Oc=new Lc(\"change\",!0,!1),Pc=n",
+    "ew W(\"click\",!0,!0),Qc=new W(\"contextmenu\",!0,!0),Rc=new W(\"dblcli",
+    "ck\",!0,!0),Sc=new W(\"mousedown\",!0,!0),Tc=new W(\"mousemove\",!0,!1)",
+    ",Uc=new W(\"mouseout\",!0,!0),Vc=new W(\"mouseover\",!0,!0),Wc=new W(\"",
+    "mouseup\",!0,!0),Nc=new W(\"mousewheel\",!0,!0),Mc=new W(\"MozMousePixe",
+    "lScroll\",!0,!0),Xc=new X(\"MSGotPointerCapture\",!0,!1),Yc=new X(\"MSL",
+    "ostPointerCapture\",!0,!1),Zc=new X(\"MSPointerDown\",!0,!0),$c=new X(",
+    "\"MSPointerMove\",!0,!0),ad=new X(\"MSPointerOver\",!0,!0),bd=new X(\"M",
+    "SPointerOut\",\n!0,!0),cd=new X(\"MSPointerUp\",!0,!0);function dd(a,b,",
+    "c){b=b.create(a,c);\"isTrusted\"in b||(b.isTrusted=!1);return a.dispatc",
+    "hEvent(b)};function ed(a,b){this.g=ka.document.documentElement;this.G=n",
+    "ull;var c=ab(A(this.g));c&&fd(this,c);this.$=a||new gd;this.pa=b||new h",
+    "d}ed.prototype.I=function(){return this.g};function fd(a,b){a.g=b;a.G=B",
+    "(b,\"OPTION\")?$a(b,function(a){return B(a,\"SELECT\")}):null}\ned.prot",
+    "otype.W=function(a,b,c,d,e,f,h,l){if(!f&&!tc(this.g))return!1;if(d&&Vc!",
+    "=a&&Uc!=a)throw new u(12,\"Event type does not allow related target: \"",
+    "+a);b={clientX:b.x,clientY:b.y,button:c,altKey:0!=(this.$.ca&4),ctrlKey",
+    ":0!=(this.$.ca&2),shiftKey:0!=(this.$.ca&1),metaKey:0!=(this.$.ca&8),wh",
+    "eelDelta:e||0,relatedTarget:d||null,count:l||1};h=h||1;c=this.g;a!=Pc&&",
+    "a!=Sc&&h in id?c=id[h]:this.G&&(c=jd(this,a));return c?this.pa.W(c,a,b)",
+    ":!0};\ned.prototype.S=function(a,b,c,d,e,f,h,l){if(!l&&!tc(this.g))retu",
+    "rn!1;if(h&&ad!=a&&bd!=a)throw new u(12,\"Event type does not allow rela",
+    "ted target: \"+a);b={clientX:b.x,clientY:b.y,button:c,altKey:!1,ctrlKey",
+    ":!1,shiftKey:!1,metaKey:!1,relatedTarget:h||null,width:0,height:0,press",
+    "ure:0,rotation:0,pointerId:d,tiltX:0,tiltY:0,pointerType:e,isPrimary:f}",
+    ";c=this.G?jd(this,a):this.g;id[d]&&(c=id[d]);d=Sa(A(this.g));if(d&&a==Z",
+    "c){var q=d.Element.prototype.msSetPointerCapture;d.Element.prototype.ms",
+    "SetPointerCapture=\nfunction(a){id[a]=this}}a=c?this.pa.S(c,a,b):!0;q&&",
+    "(d.Element.prototype.msSetPointerCapture=q);return a};function jd(a,b){",
+    "switch(b){case Pc:case Wc:return a.G.multiple?a.g:a.G;default:return a.",
+    "G.multiple?a.g:null}}function kd(a){var b=$a(a.g,function(a){return!!a&",
+    "&B(a)&&xc(a)},!0),b=b||a.g;a=ab(A(b));if(b!=a){if(a&&ea(a.blur)&&!B(a,",
+    "\"BODY\"))try{a.blur()}catch(c){throw c;}ea(b.focus)&&b.focus()}}functi",
+    "on gd(){this.ca=0}var id={};function hd(){}hd.prototype.W=function(a,b,",
+    "c){return dd(a,b,c)};\nhd.prototype.S=function(a,b,c){return dd(a,b,c)}",
+    ";function ld(a,b){this.D={};this.h=[];this.M=0;var c=arguments.length;i",
+    "f(1<c){if(c%2)throw Error(\"Uneven number of arguments\");for(var d=0;d",
+    "<c;d+=2)this.set(arguments[d],arguments[d+1])}else a&&this.addAll(a)}fu",
+    "nction md(a){nd(a);return a.h.concat()}g=ld.prototype;g.clear=function(",
+    "){this.D={};this.M=this.h.length=0};g.remove=function(a){return Object.",
+    "prototype.hasOwnProperty.call(this.D,a)?(delete this.D[a],this.M--,this",
+    ".h.length>2*this.M&&nd(this),!0):!1};\nfunction nd(a){var b,c;if(a.M!=a",
+    ".h.length){for(b=c=0;c<a.h.length;){var d=a.h[c];Object.prototype.hasOw",
+    "nProperty.call(a.D,d)&&(a.h[b++]=d);c++}a.h.length=b}if(a.M!=a.h.length",
+    "){var e={};for(b=c=0;c<a.h.length;)d=a.h[c],Object.prototype.hasOwnProp",
+    "erty.call(e,d)||(a.h[b++]=d,e[d]=1),c++;a.h.length=b}}g.get=function(a,",
+    "b){return Object.prototype.hasOwnProperty.call(this.D,a)?this.D[a]:b};g",
+    ".set=function(a,b){Object.prototype.hasOwnProperty.call(this.D,a)||(thi",
+    "s.M++,this.h.push(a));this.D[a]=b};\ng.addAll=function(a){if(a instance",
+    "of ld){var b=md(a);nd(a);for(var c=[],d=0;d<a.h.length;d++)c.push(a.D[a",
+    ".h[d]]);a=c}else{b=[];var d=0;for(e in a)b[d++]=e;d=[];var e=0;for(c in",
+    " a)d[e++]=a[c];a=d}for(c=0;c<b.length;c++)this.set(b[c],a[c])};g.forEac",
+    "h=function(a,b){for(var c=md(this),d=0;d<c.length;d++){var e=c[d],f=thi",
+    "s.get(e);a.call(b,f,e,this)}};g.clone=function(){return new ld(this)};v",
+    "ar od={};function Y(a,b,c){fa(a)&&(a=a.b);a=new pd(a);!b||b in od&&!c||",
+    "(od[b]={key:a,shift:!1},c&&(od[c]={key:a,shift:!0}));return a}function ",
+    "pd(a){this.code=a}Y(8);Y(9);Y(13);var qd=Y(16),rd=Y(17),sd=Y(18);Y(19);",
+    "Y(20);Y(27);Y(32,\" \");Y(33);Y(34);Y(35);Y(36);Y(37);Y(38);Y(39);Y(40)",
+    ";Y(44);Y(45);Y(46);Y(48,\"0\",\")\");Y(49,\"1\",\"!\");Y(50,\"2\",\"@\"",
+    ");Y(51,\"3\",\"#\");Y(52,\"4\",\"$\");Y(53,\"5\",\"%\");Y(54,\"6\",\"^",
+    "\");Y(55,\"7\",\"&\");Y(56,\"8\",\"*\");Y(57,\"9\",\"(\");Y(65,\"a\",\"",
+    "A\");Y(66,\"b\",\"B\");Y(67,\"c\",\"C\");Y(68,\"d\",\"D\");\nY(69,\"e\"",
+    ",\"E\");Y(70,\"f\",\"F\");Y(71,\"g\",\"G\");Y(72,\"h\",\"H\");Y(73,\"i",
+    "\",\"I\");Y(74,\"j\",\"J\");Y(75,\"k\",\"K\");Y(76,\"l\",\"L\");Y(77,\"",
+    "m\",\"M\");Y(78,\"n\",\"N\");Y(79,\"o\",\"O\");Y(80,\"p\",\"P\");Y(81,",
+    "\"q\",\"Q\");Y(82,\"r\",\"R\");Y(83,\"s\",\"S\");Y(84,\"t\",\"T\");Y(85",
+    ",\"u\",\"U\");Y(86,\"v\",\"V\");Y(87,\"w\",\"W\");Y(88,\"x\",\"X\");Y(8",
+    "9,\"y\",\"Y\");Y(90,\"z\",\"Z\");var td=Y(Ja?{c:91,b:91}:Ia?{c:224,b:91",
+    "}:{c:0,b:91});Y(Ja?{c:92,b:92}:Ia?{c:224,b:93}:{c:0,b:92});Y(Ja?{c:93,b",
+    ":93}:Ia?{c:0,b:0}:{c:93,b:null});Y({c:96,b:96},\"0\");Y({c:97,b:97},\"1",
+    "\");\nY({c:98,b:98},\"2\");Y({c:99,b:99},\"3\");Y({c:100,b:100},\"4\");",
+    "Y({c:101,b:101},\"5\");Y({c:102,b:102},\"6\");Y({c:103,b:103},\"7\");Y(",
+    "{c:104,b:104},\"8\");Y({c:105,b:105},\"9\");Y({c:106,b:106},\"*\");Y({c",
+    ":107,b:107},\"+\");Y({c:109,b:109},\"-\");Y({c:110,b:110},\".\");Y({c:1",
+    "11,b:111},\"/\");Y(144);Y(112);Y(113);Y(114);Y(115);Y(116);Y(117);Y(118",
+    ");Y(119);Y(120);Y(121);Y(122);Y(123);Y({c:107,b:187},\"=\",\"+\");Y(108",
+    ",\",\");Y({c:109,b:189},\"-\",\"_\");Y(188,\",\",\"<\");Y(190,\".\",\">",
+    "\");Y(191,\"/\",\"?\");Y(192,\"`\",\"~\");Y(219,\"[\",\"{\");\nY(220,\"",
+    "\\\\\",\"|\");Y(221,\"]\",\"}\");Y({c:59,b:186},\";\",\":\");Y(222,\"'",
+    "\",'\"');var ud=new ld;ud.set(1,qd);ud.set(2,rd);ud.set(4,sd);ud.set(8,",
+    "td);(function(a){var b=new ld;t(md(a),function(c){b.set(a.get(c).code,c",
+    ")});return b})(ud);function vd(a,b,c){ed.call(this,b,c);this.K=this.j=n",
+    "ull;this.C=new z(0,0);this.Y=this.N=!1;if(a){n(a.buttonPressed)&&(this.",
+    "j=a.buttonPressed);try{B(a.elementPressed)&&(this.K=a.elementPressed)}c",
+    "atch(d){this.j=null}this.C=new z(a.clientXY.x,a.clientXY.y);this.N=!!a.",
+    "nextClickIsDoubleClick;this.Y=!!a.hasEverInteracted;try{a.element&&B(a.",
+    "element)&&fd(this,a.element)}catch(d){this.j=null}}}p(vd,ed);var Z={};Z",
+    "[Pc]=[0,1,2,null];Z[Qc]=[null,null,2,null];Z[Wc]=[0,1,2,null];Z[Uc]=[0,",
+    "1,2,4];Z[Tc]=[0,1,2,4];\nQa&&(Z[Zc]=Z[Wc],Z[cd]=Z[Wc],Z[$c]=[-1,-1,-1,-",
+    "1],Z[bd]=Z[$c],Z[ad]=Z[$c]);Z[Rc]=Z[Pc];Z[Sc]=Z[Wc];Z[Vc]=Z[Uc];var wd=",
+    "{};wd[Sc]=Zc;wd[Tc]=$c;wd[Uc]=bd;wd[Vc]=ad;wd[Wc]=cd;vd.prototype.move=",
+    "function(a,b){var c=tc(a),d=Fc(a);this.C.x=b.x+d.left;this.C.y=b.y+d.to",
+    "p;b=this.I();if(a!=b){try{Sa(A(b)).closed&&(b=null)}catch(e){b=null}b&&",
+    "(d=b===ka.document.documentElement||b===ka.document.body,b=!this.Y&&d?n",
+    "ull:b,xd(this,Uc,a));fd(this,a);xd(this,Vc,b,null,c)}xd(this,Tc,null,nu",
+    "ll,c);this.N=!1};\nvd.prototype.scroll=function(a){if(0==a)throw new u(",
+    "13,\"Must scroll a non-zero number of ticks.\");for(var b=0<a?-120:120,",
+    "c=0;c<Math.abs(a);c++)xd(this,Nc,null,b)};function xd(a,b,c,d,e,f){a.Y=",
+    "!0;if(Qa){var h=wd[b];if(h&&!a.S(h,a.C,yd(a,h),1,MSPointerEvent.MSPOINT",
+    "ER_TYPE_MOUSE,!0,c,e))return!1}return a.W(b,a.C,yd(a,b),c,d,e,null,f)}f",
+    "unction yd(a,b){if(!(b in Z))return 0;a=Z[b][null===a.j?3:a.j];if(null=",
+    "==a)throw new u(13,\"Event does not permit the specified mouse button.",
+    "\");return a}\nvd.prototype.getState=function(){return{buttonPressed:th",
+    "is.j,elementPressed:this.K,clientXY:{x:this.C.x,y:this.C.y},nextClickIs",
+    "DoubleClick:this.N,hasEverInteracted:this.Y,element:this.I()}};function",
+    " zd(a,b){this.x=a;this.y=b}p(zd,z);g=zd.prototype;g.clone=function(){re",
+    "turn new zd(this.x,this.y)};g.scale=z.prototype.scale;g.normalize=funct",
+    "ion(){return this.scale(1/Math.sqrt(this.x*this.x+this.y*this.y))};g.ad",
+    "d=function(a){this.x+=a.x;this.y+=a.y;return this};g.rotate=function(a)",
+    "{var b=Math.cos(a);a=Math.sin(a);var c=this.y*b+this.x*a;this.x=this.x*",
+    "b-this.y*a;this.y=c;return this};function Ad(a){var b;(b=qc(a,\"display",
+    "\"))||(b=a.currentStyle?a.currentStyle.display:null);if(\"none\"!=(b||a",
+    ".style&&a.style.display))b=rc(a);else{b=a.style;var c=b.display,d=b.vis",
+    "ibility,e=b.position;b.visibility=\"hidden\";b.position=\"absolute\";b.",
+    "display=\"inline\";var f=rc(a);b.display=c;b.position=e;b.visibility=d;",
+    "b=f}return 0<b.width&&0<b.height||!a.offsetParent?b:Ad(a.offsetParent)}",
+    ";ba(\"_\",function(a,b,c,d){if(!uc(a))throw new u(11,\"Element is not c",
+    "urrently visible and may not be manipulated\");b:{var e=b||void 0;if(\"",
+    "scroll\"==Gc(a,e)){if(a.scrollIntoView&&(a.scrollIntoView(),\"none\"==G",
+    "c(a,e)))break b;for(var f=Jc(a,e),h=Cc(a);h;h=Cc(h)){var l=h,q=Fc(l);va",
+    "r y=l;var r=qc(y,\"borderLeftWidth\");var v=qc(y,\"borderRightWidth\");",
+    "var J=qc(y,\"borderTopWidth\");y=qc(y,\"borderBottomWidth\");v=new pc(p",
+    "arseFloat(J),parseFloat(v),parseFloat(y),parseFloat(r));r=f.left-q.left",
+    "-v.left;q=f.top-q.top-\nv.top;v=l.clientHeight+f.top-f.bottom;l.scrollL",
+    "eft+=Math.min(r,Math.max(r-(l.clientWidth+f.left-f.right),0));l.scrollT",
+    "op+=Math.min(q,Math.max(q-v,0))}Gc(a,e)}}b?b=new zd(b.x,b.y):(b=Ad(a),b",
+    "=new zd(b.width/2,b.height/2));c=c||new vd;c.move(a,b);if(null!==c.j)th",
+    "row new u(13,\"Cannot press more than one button or an already pressed ",
+    "button.\");c.j=0;c.K=c.I();if(B(c.I(),\"OPTION\")||B(c.I(),\"SELECT\")|",
+    "|xd(c,Sc,null,null,!1,void 0))Qa&&0==c.j&&B(c.K,\"OPTION\")&&c.S(Xc,c.C",
+    ",0,1,MSPointerEvent.MSPOINTER_TYPE_MOUSE,\n!0),kd(c);if(null===c.j)thro",
+    "w new u(13,\"Cannot release a button when no button is pressed.\");c.G&",
+    "&tc(c.g)&&(a=c.G,b=gb(c.g),!b||a.multiple)&&(c.g.selected=!b,a.multiple",
+    "&&!(0<=na(Pa,28))||dd(a,Oc));a=tc(c.I());xd(c,Wc,null,null,d,void 0);tr",
+    "y{if(0==c.j&&c.I()==c.K){var U=c.C,ma=yd(c,Pc);if(a||tc(c.g))!c.G&&fb(c",
+    ".g)&&gb(c.g),c.W(Pc,U,ma,null,0,a,void 0);c.N&&xd(c,Rc);c.N=!c.N;Qa&&0=",
+    "=c.j&&B(c.K,\"OPTION\")&&c.S(Yc,new z(0,0),0,1,MSPointerEvent.MSPOINTER",
+    "_TYPE_MOUSE,!1)}else 2==c.j&&xd(c,Qc)}catch(Bd){}id=\n{};c.j=null;c.K=n",
+    "ull});; return this._.apply(null,arguments);}.apply({navigator:typeof w",
+    "indow!='undefined'?window.navigator:null,document:typeof window!='undef",
+    "ined'?window.document:null}, arguments);}",
     NULL
 };
 
@@ -2447,117 +2447,117 @@
     ")&&\"hidden\"==a.type.toLowerCase()||C(a,\"NOSCRIPT\"))return!1;f=X(a,",
     "\"visibility\");return\"collapse\"!=f&&\"hidden\"!=f&&c(a)&&(b||0!=ic(a",
     "))&&d(a)?!e(a):!1}\nfunction jc(a){function b(a){if(C(a)&&\"none\"==X(a",
-    ",\"display\"))return!1;var c;(c=a.parentNode)&&c.shadowRoot&&void 0!==a",
-    ".assignedSlot?c=a.assignedSlot?a.assignedSlot.parentNode:null:a.getDest",
-    "inationInsertionPoints&&(a=a.getDestinationInsertionPoints(),0<a.length",
-    "&&(c=a[a.length-1]));return bc&&c instanceof ShadowRoot||c&&(9==c.nodeT",
-    "ype||11==c.nodeType)?!0:!!c&&b(c)}return ec(a,!1,b)}var Y=\"hidden\";\n",
-    "function gc(a){function b(a){function b(a){return a==g?!0:0==X(a,\"disp",
-    "lay\").lastIndexOf(\"inline\",0)||\"absolute\"==c&&\"static\"==X(a,\"po",
-    "sition\")?!1:!0}var c=X(a,\"position\");if(\"fixed\"==c)return D=!0,a==",
-    "g?null:g;for(a=cc(a);a&&!b(a);)a=cc(a);return a}function c(a){var b=a;i",
-    "f(\"visible\"==u)if(a==g&&k)b=k;else if(a==k)return{x:\"visible\",y:\"v",
-    "isible\"};b={x:X(b,\"overflow-x\"),y:X(b,\"overflow-y\")};a==g&&(b.x=\"",
-    "visible\"==b.x?\"auto\":b.x,b.y=\"visible\"==b.y?\"auto\":b.y);return b",
-    "}function d(a){if(a==g){var b=(new za(f)).C;\na=b.scrollingElement?b.sc",
-    "rollingElement:b.body||b.documentElement;b=b.parentWindow||b.defaultVie",
-    "w;a=new x(b.pageXOffset||a.scrollLeft,b.pageYOffset||a.scrollTop)}else ",
-    "a=new x(a.scrollLeft,a.scrollTop);return a}var e=kc(a);var f=z(a),g=f.d",
-    "ocumentElement,k=f.body,u=X(g,\"overflow\"),D;for(a=b(a);a;a=b(a)){var ",
-    "r=c(a);if(\"visible\"!=r.x||\"visible\"!=r.y){var A=fc(a);if(0==A.width",
-    "||0==A.height)return Y;var L=e.right<A.left,W=e.bottom<A.top;if(L&&\"hi",
-    "dden\"==r.x||W&&\"hidden\"==r.y)return Y;if(L&&\"visible\"!=r.x||\nW&&",
-    "\"visible\"!=r.y){L=d(a);W=e.bottom<A.top-L.y;if(e.right<A.left-L.x&&\"",
-    "visible\"!=r.x||W&&\"visible\"!=r.x)return Y;e=gc(a);return e==Y?Y:\"sc",
-    "roll\"}L=e.left>=A.left+A.width;A=e.top>=A.top+A.height;if(L&&\"hidden",
-    "\"==r.x||A&&\"hidden\"==r.y)return Y;if(L&&\"visible\"!=r.x||A&&\"visib",
-    "le\"!=r.y){if(D&&(r=d(a),e.left>=g.scrollWidth-r.x||e.right>=g.scrollHe",
-    "ight-r.y))return Y;e=gc(a);return e==Y?Y:\"scroll\"}}}return\"none\"}\n",
-    "function fc(a){var b=hc(a);if(b)return b.rect;if(C(a,\"HTML\"))return a",
-    "=z(a),a=((a?a.parentWindow||a.defaultView:window)||window).document,a=",
-    "\"CSS1Compat\"==a.compatMode?a.documentElement:a.body,a=new ya(a.client",
-    "Width,a.clientHeight),new V(0,0,a.width,a.height);try{var c=a.getBoundi",
-    "ngClientRect()}catch(d){return new V(0,0,0,0)}return new V(c.left,c.top",
-    ",c.right-c.left,c.bottom-c.top)}\nfunction hc(a){var b=C(a,\"MAP\");if(",
-    "!b&&!C(a,\"AREA\"))return null;var c=b?a:C(a.parentNode,\"MAP\")?a.pare",
-    "ntNode:null,d=null,e=null;c&&c.name&&(d=U.A('/descendant::*[@usemap = ",
-    "\"#'+c.name+'\"]',z(c)))&&(e=fc(d),b||\"default\"==a.shape.toLowerCase(",
-    ")||(a=lc(a),b=Math.min(Math.max(a.left,0),e.width),c=Math.min(Math.max(",
-    "a.top,0),e.height),e=new V(b+e.left,c+e.top,Math.min(a.width,e.width-b)",
-    ",Math.min(a.height,e.height-c))));return{ba:d,rect:e||new V(0,0,0,0)}}",
-    "\nfunction lc(a){var b=a.shape.toLowerCase();a=a.coords.split(\",\");if",
-    "(\"rect\"==b&&4==a.length){var b=a[0],c=a[1];return new V(b,c,a[2]-b,a[",
-    "3]-c)}if(\"circle\"==b&&3==a.length)return b=a[2],new V(a[0]-b,a[1]-b,2",
-    "*b,2*b);if(\"poly\"==b&&2<a.length){for(var b=a[0],c=a[1],d=b,e=c,f=2;f",
-    "+1<a.length;f+=2)b=Math.min(b,a[f]),d=Math.max(d,a[f]),c=Math.min(c,a[f",
-    "+1]),e=Math.max(e,a[f+1]);return new V(b,c,d-b,e-c)}return new V(0,0,0,",
-    "0)}function kc(a){a=fc(a);return new ac(a.top,a.left+a.width,a.top+a.he",
-    "ight,a.left)}\nfunction mc(a){return a.replace(/^[^\\S\\xa0]+|[^\\S\\xa",
-    "0]+$/g,\"\")}function nc(a){var b=[];bc?oc(a,b):pc(a,b);var c=b;a=c.len",
-    "gth;for(var b=Array(a),c=m(c)?c.split(\"\"):c,d=0;d<a;d++)d in c&&(b[d]",
-    "=mc.call(void 0,c[d]));return mc(b.join(\"\\n\")).replace(/\\xa0/g,\" ",
-    "\")}\nfunction qc(a,b,c){if(C(a,\"BR\"))b.push(\"\");else{var d=C(a,\"T",
-    "D\"),e=X(a,\"display\"),f=!d&&!(0<=pa(rc,e)),g=l(a.previousElementSibli",
-    "ng)?a.previousElementSibling:Ca(a.previousSibling),g=g?X(g,\"display\")",
-    ":\"\",k=X(a,\"float\")||X(a,\"cssFloat\")||X(a,\"styleFloat\");!f||\"ru",
-    "n-in\"==g&&\"none\"==k||/^[\\s\\xa0]*$/.test(b[b.length-1]||\"\")||b.pu",
-    "sh(\"\");var u=jc(a),D=null,r=null;u&&(D=X(a,\"white-space\"),r=X(a,\"t",
-    "ext-transform\"));w(a.childNodes,function(a){c(a,b,u,D,r)});a=b[b.lengt",
-    "h-1]||\"\";!d&&\"table-cell\"!=e||!a||ma(a)||(b[b.length-\n1]+=\" \");f",
-    "&&\"run-in\"!=e&&!/^[\\s\\xa0]*$/.test(a)&&b.push(\"\")}}function pc(a,",
-    "b){qc(a,b,function(a,b,e,f,g){3==a.nodeType&&e?sc(a,b,f,g):C(a)&&pc(a,b",
-    ")})}var rc=\"inline inline-block inline-table none table-cell table-col",
-    "umn table-column-group\".split(\" \");\nfunction sc(a,b,c,d){a=a.nodeVa",
-    "lue.replace(/[\\u200b\\u200e\\u200f]/g,\"\");a=a.replace(/(\\r\\n|\\r|",
-    "\\n)/g,\"\\n\");if(\"normal\"==c||\"nowrap\"==c)a=a.replace(/\\n/g,\" ",
-    "\");a=\"pre\"==c||\"pre-wrap\"==c?a.replace(/[ \\f\\t\\v\\u2028\\u2029]",
-    "/g,\"\\u00a0\"):a.replace(/[\\ \\f\\t\\v\\u2028\\u2029]+/g,\" \");\"cap",
-    "italize\"==d?a=a.replace(/(^|\\s)(\\S)/g,function(a,b,c){return b+c.toU",
-    "pperCase()}):\"uppercase\"==d?a=a.toUpperCase():\"lowercase\"==d&&(a=a.",
-    "toLowerCase());c=b.pop()||\"\";ma(c)&&0==a.lastIndexOf(\" \",0)&&(a=a.s",
-    "ubstr(1));b.push(c+a)}\nfunction ic(a){var b=1,c=X(a,\"opacity\");c&&(b",
-    "=Number(c));(a=cc(a))&&(b*=ic(a));return b}\nfunction tc(a,b,c,d,e){var",
-    " f;if(3==a.nodeType&&c)sc(a,b,d,e);else if(C(a))if(C(a,\"CONTENT\")||C(",
-    "a,\"SLOT\")){for(f=a;f.parentNode;)f=f.parentNode;f instanceof ShadowRo",
-    "ot?(a=C(a,\"CONTENT\")?a.getDistributedNodes():a.assignedNodes(),w(a,fu",
-    "nction(a){tc(a,b,c,d,e)})):oc(a,b)}else if(C(a,\"SHADOW\")){for(f=a;f.p",
-    "arentNode;)f=f.parentNode;if(f instanceof ShadowRoot&&(a=f))for(a=a.old",
-    "erShadowRoot;a;)w(a.childNodes,function(a){tc(a,b,c,d,e)}),a=a.olderSha",
-    "dowRoot}else oc(a,b)}\nfunction oc(a,b){a.shadowRoot&&w(a.shadowRoot.ch",
-    "ildNodes,function(a){tc(a,b,!0,null,null)});qc(a,b,function(a,b,e,f,g){",
-    "var c=null;1==a.nodeType?c=a:3==a.nodeType&&(c=a);null!=c&&(null!=c.ass",
-    "ignedSlot||c.getDestinationInsertionPoints&&0<c.getDestinationInsertion",
-    "Points().length)||tc(a,b,e,f,g)})};var uc={K:function(a,b){return!(!a.q",
-    "uerySelectorAll||!a.querySelector)&&!/^\\d.*/.test(b)},A:function(a,b){",
-    "var c=y(b),d=m(a)?c.C.getElementById(a):a;return d?Ra(d,\"id\")==a&&b!=",
-    "d&&Da(b,d)?d:ua(B(c,\"*\"),function(c){return Ra(c,\"id\")==a&&b!=c&&Da",
-    "(b,c)}):null},l:function(a,b){if(!a)return[];if(uc.K(b,a))try{return b.",
-    "querySelectorAll(\"#\"+uc.na(a))}catch(c){return[]}b=B(y(b),\"*\",null,",
-    "b);return qa(b,function(b){return Ra(b,\"id\")==a})},na:function(a){ret",
-    "urn a.replace(/([\\s'\"\\\\#.:;,!?+<>=~*^$|%&@`{}\\-\\/\\[\\]\\(\\)])/g",
-    ",\n\"\\\\$1\")}};var Z={},vc={};Z.ja=function(a,b,c){try{var d=Ka.l(\"a",
-    "\",b)}catch(e){d=B(y(b),\"A\",null,b)}return ua(d,function(b){b=nc(b);b",
-    "=b.replace(/^[\\s]+|[\\s]+$/g,\"\");return c&&-1!=b.indexOf(a)||b==a})}",
-    ";Z.ea=function(a,b,c){try{var d=Ka.l(\"a\",b)}catch(e){d=B(y(b),\"A\",n",
-    "ull,b)}return qa(d,function(b){b=nc(b);b=b.replace(/^[\\s]+|[\\s]+$/g,",
-    "\"\");return c&&-1!=b.indexOf(a)||b==a})};Z.A=function(a,b){return Z.ja",
-    "(a,b,!1)};Z.l=function(a,b){return Z.ea(a,b,!1)};vc.A=function(a,b){ret",
-    "urn Z.ja(a,b,!0)};\nvc.l=function(a,b){return Z.ea(a,b,!0)};var wc={A:f",
-    "unction(a,b){if(\"\"===a)throw new t(32,'Unable to locate an element wi",
-    "th the tagName \"\"');return b.getElementsByTagName(a)[0]||null},l:func",
-    "tion(a,b){if(\"\"===a)throw new t(32,'Unable to locate an element with ",
-    "the tagName \"\"');return b.getElementsByTagName(a)}};var xc={className",
-    ":Ja,\"class name\":Ja,css:Ka,\"css selector\":Ka,id:uc,linkText:Z,\"lin",
-    "k text\":Z,name:{A:function(a,b){b=B(y(b),\"*\",null,b);return ua(b,fun",
-    "ction(b){return Ra(b,\"name\")==a})},l:function(a,b){b=B(y(b),\"*\",nul",
-    "l,b);return qa(b,function(b){return Ra(b,\"name\")==a})}},partialLinkTe",
-    "xt:vc,\"partial link text\":vc,tagName:wc,\"tag name\":wc,xpath:U};ba(",
-    "\"_\",function(a,b){a:{for(c in a)if(a.hasOwnProperty(c))break a;var c=",
-    "null}if(c){var d=xc[c];if(d&&p(d.l))return d.l(a[c],b||ja.document)}thr",
-    "ow new t(61,\"Unsupported locator strategy: \"+c);});; return this._.ap",
-    "ply(null,arguments);}.apply({navigator:typeof window!='undefined'?windo",
-    "w.navigator:null,document:typeof window!='undefined'?window.document:nu",
-    "ll}, arguments);}",
+    ",\"display\"))return!1;a:{var c=a.parentNode;if(a.getDestinationInserti",
+    "onPoints){var e=a.getDestinationInsertionPoints();if(0<e.length){a=e[e.",
+    "length-1];break a}}a=c&&c.shadowRoot&&void 0!==a.assignedSlot?a.assigne",
+    "dSlot?a.assignedSlot.parentNode:null:c}return bc&&a instanceof ShadowRo",
+    "ot||a&&(9==a.nodeType||11==a.nodeType)?!0:!!a&&b(a)}return ec(a,!1,b)}v",
+    "ar Y=\"hidden\";\nfunction gc(a){function b(a){function b(a){return a==",
+    "g?!0:0==X(a,\"display\").lastIndexOf(\"inline\",0)||\"absolute\"==c&&\"",
+    "static\"==X(a,\"position\")?!1:!0}var c=X(a,\"position\");if(\"fixed\"=",
+    "=c)return D=!0,a==g?null:g;for(a=cc(a);a&&!b(a);)a=cc(a);return a}funct",
+    "ion c(a){var b=a;if(\"visible\"==u)if(a==g&&k)b=k;else if(a==k)return{x",
+    ":\"visible\",y:\"visible\"};b={x:X(b,\"overflow-x\"),y:X(b,\"overflow-y",
+    "\")};a==g&&(b.x=\"visible\"==b.x?\"auto\":b.x,b.y=\"visible\"==b.y?\"au",
+    "to\":b.y);return b}function d(a){if(a==g){var b=(new za(f)).C;\na=b.scr",
+    "ollingElement?b.scrollingElement:b.body||b.documentElement;b=b.parentWi",
+    "ndow||b.defaultView;a=new x(b.pageXOffset||a.scrollLeft,b.pageYOffset||",
+    "a.scrollTop)}else a=new x(a.scrollLeft,a.scrollTop);return a}var e=kc(a",
+    ");var f=z(a),g=f.documentElement,k=f.body,u=X(g,\"overflow\"),D;for(a=b",
+    "(a);a;a=b(a)){var r=c(a);if(\"visible\"!=r.x||\"visible\"!=r.y){var A=f",
+    "c(a);if(0==A.width||0==A.height)return Y;var L=e.right<A.left,W=e.botto",
+    "m<A.top;if(L&&\"hidden\"==r.x||W&&\"hidden\"==r.y)return Y;if(L&&\"visi",
+    "ble\"!=r.x||\nW&&\"visible\"!=r.y){L=d(a);W=e.bottom<A.top-L.y;if(e.rig",
+    "ht<A.left-L.x&&\"visible\"!=r.x||W&&\"visible\"!=r.x)return Y;e=gc(a);r",
+    "eturn e==Y?Y:\"scroll\"}L=e.left>=A.left+A.width;A=e.top>=A.top+A.heigh",
+    "t;if(L&&\"hidden\"==r.x||A&&\"hidden\"==r.y)return Y;if(L&&\"visible\"!",
+    "=r.x||A&&\"visible\"!=r.y){if(D&&(r=d(a),e.left>=g.scrollWidth-r.x||e.r",
+    "ight>=g.scrollHeight-r.y))return Y;e=gc(a);return e==Y?Y:\"scroll\"}}}r",
+    "eturn\"none\"}\nfunction fc(a){var b=hc(a);if(b)return b.rect;if(C(a,\"",
+    "HTML\"))return a=z(a),a=((a?a.parentWindow||a.defaultView:window)||wind",
+    "ow).document,a=\"CSS1Compat\"==a.compatMode?a.documentElement:a.body,a=",
+    "new ya(a.clientWidth,a.clientHeight),new V(0,0,a.width,a.height);try{va",
+    "r c=a.getBoundingClientRect()}catch(d){return new V(0,0,0,0)}return new",
+    " V(c.left,c.top,c.right-c.left,c.bottom-c.top)}\nfunction hc(a){var b=C",
+    "(a,\"MAP\");if(!b&&!C(a,\"AREA\"))return null;var c=b?a:C(a.parentNode,",
+    "\"MAP\")?a.parentNode:null,d=null,e=null;c&&c.name&&(d=U.A('/descendant",
+    "::*[@usemap = \"#'+c.name+'\"]',z(c)))&&(e=fc(d),b||\"default\"==a.shap",
+    "e.toLowerCase()||(a=lc(a),b=Math.min(Math.max(a.left,0),e.width),c=Math",
+    ".min(Math.max(a.top,0),e.height),e=new V(b+e.left,c+e.top,Math.min(a.wi",
+    "dth,e.width-b),Math.min(a.height,e.height-c))));return{ba:d,rect:e||new",
+    " V(0,0,0,0)}}\nfunction lc(a){var b=a.shape.toLowerCase();a=a.coords.sp",
+    "lit(\",\");if(\"rect\"==b&&4==a.length){var b=a[0],c=a[1];return new V(",
+    "b,c,a[2]-b,a[3]-c)}if(\"circle\"==b&&3==a.length)return b=a[2],new V(a[",
+    "0]-b,a[1]-b,2*b,2*b);if(\"poly\"==b&&2<a.length){for(var b=a[0],c=a[1],",
+    "d=b,e=c,f=2;f+1<a.length;f+=2)b=Math.min(b,a[f]),d=Math.max(d,a[f]),c=M",
+    "ath.min(c,a[f+1]),e=Math.max(e,a[f+1]);return new V(b,c,d-b,e-c)}return",
+    " new V(0,0,0,0)}function kc(a){a=fc(a);return new ac(a.top,a.left+a.wid",
+    "th,a.top+a.height,a.left)}\nfunction mc(a){return a.replace(/^[^\\S\\xa",
+    "0]+|[^\\S\\xa0]+$/g,\"\")}function nc(a){var b=[];bc?oc(a,b):pc(a,b);va",
+    "r c=b;a=c.length;for(var b=Array(a),c=m(c)?c.split(\"\"):c,d=0;d<a;d++)",
+    "d in c&&(b[d]=mc.call(void 0,c[d]));return mc(b.join(\"\\n\")).replace(",
+    "/\\xa0/g,\" \")}\nfunction qc(a,b,c){if(C(a,\"BR\"))b.push(\"\");else{v",
+    "ar d=C(a,\"TD\"),e=X(a,\"display\"),f=!d&&!(0<=pa(rc,e)),g=l(a.previous",
+    "ElementSibling)?a.previousElementSibling:Ca(a.previousSibling),g=g?X(g,",
+    "\"display\"):\"\",k=X(a,\"float\")||X(a,\"cssFloat\")||X(a,\"styleFloat",
+    "\");!f||\"run-in\"==g&&\"none\"==k||/^[\\s\\xa0]*$/.test(b[b.length-1]|",
+    "|\"\")||b.push(\"\");var u=jc(a),D=null,r=null;u&&(D=X(a,\"white-space",
+    "\"),r=X(a,\"text-transform\"));w(a.childNodes,function(a){c(a,b,u,D,r)}",
+    ");a=b[b.length-1]||\"\";!d&&\"table-cell\"!=e||!a||ma(a)||(b[b.length-",
+    "\n1]+=\" \");f&&\"run-in\"!=e&&!/^[\\s\\xa0]*$/.test(a)&&b.push(\"\")}}",
+    "function pc(a,b){qc(a,b,function(a,b,e,f,g){3==a.nodeType&&e?sc(a,b,f,g",
+    "):C(a)&&pc(a,b)})}var rc=\"inline inline-block inline-table none table-",
+    "cell table-column table-column-group\".split(\" \");\nfunction sc(a,b,c",
+    ",d){a=a.nodeValue.replace(/[\\u200b\\u200e\\u200f]/g,\"\");a=a.replace(",
+    "/(\\r\\n|\\r|\\n)/g,\"\\n\");if(\"normal\"==c||\"nowrap\"==c)a=a.replac",
+    "e(/\\n/g,\" \");a=\"pre\"==c||\"pre-wrap\"==c?a.replace(/[ \\f\\t\\v\\u",
+    "2028\\u2029]/g,\"\\u00a0\"):a.replace(/[\\ \\f\\t\\v\\u2028\\u2029]+/g,",
+    "\" \");\"capitalize\"==d?a=a.replace(/(^|\\s)(\\S)/g,function(a,b,c){re",
+    "turn b+c.toUpperCase()}):\"uppercase\"==d?a=a.toUpperCase():\"lowercase",
+    "\"==d&&(a=a.toLowerCase());c=b.pop()||\"\";ma(c)&&0==a.lastIndexOf(\" ",
+    "\",0)&&(a=a.substr(1));b.push(c+a)}\nfunction ic(a){var b=1,c=X(a,\"opa",
+    "city\");c&&(b=Number(c));(a=cc(a))&&(b*=ic(a));return b}\nfunction tc(a",
+    ",b,c,d,e){var f;if(3==a.nodeType&&c)sc(a,b,d,e);else if(C(a))if(C(a,\"C",
+    "ONTENT\")||C(a,\"SLOT\")){for(f=a;f.parentNode;)f=f.parentNode;f instan",
+    "ceof ShadowRoot?(a=C(a,\"CONTENT\")?a.getDistributedNodes():a.assignedN",
+    "odes(),w(a,function(a){tc(a,b,c,d,e)})):oc(a,b)}else if(C(a,\"SHADOW\")",
+    "){for(f=a;f.parentNode;)f=f.parentNode;if(f instanceof ShadowRoot&&(a=f",
+    "))for(a=a.olderShadowRoot;a;)w(a.childNodes,function(a){tc(a,b,c,d,e)})",
+    ",a=a.olderShadowRoot}else oc(a,b)}\nfunction oc(a,b){a.shadowRoot&&w(a.",
+    "shadowRoot.childNodes,function(a){tc(a,b,!0,null,null)});qc(a,b,functio",
+    "n(a,b,e,f,g){var c=null;1==a.nodeType?c=a:3==a.nodeType&&(c=a);null!=c&",
+    "&(null!=c.assignedSlot||c.getDestinationInsertionPoints&&0<c.getDestina",
+    "tionInsertionPoints().length)||tc(a,b,e,f,g)})};var uc={K:function(a,b)",
+    "{return!(!a.querySelectorAll||!a.querySelector)&&!/^\\d.*/.test(b)},A:f",
+    "unction(a,b){var c=y(b),d=m(a)?c.C.getElementById(a):a;return d?Ra(d,\"",
+    "id\")==a&&b!=d&&Da(b,d)?d:ua(B(c,\"*\"),function(c){return Ra(c,\"id\")",
+    "==a&&b!=c&&Da(b,c)}):null},l:function(a,b){if(!a)return[];if(uc.K(b,a))",
+    "try{return b.querySelectorAll(\"#\"+uc.na(a))}catch(c){return[]}b=B(y(b",
+    "),\"*\",null,b);return qa(b,function(b){return Ra(b,\"id\")==a})},na:fu",
+    "nction(a){return a.replace(/([\\s'\"\\\\#.:;,!?+<>=~*^$|%&@`{}\\-\\/\\[",
+    "\\]\\(\\)])/g,\n\"\\\\$1\")}};var Z={},vc={};Z.ja=function(a,b,c){try{v",
+    "ar d=Ka.l(\"a\",b)}catch(e){d=B(y(b),\"A\",null,b)}return ua(d,function",
+    "(b){b=nc(b);b=b.replace(/^[\\s]+|[\\s]+$/g,\"\");return c&&-1!=b.indexO",
+    "f(a)||b==a})};Z.ea=function(a,b,c){try{var d=Ka.l(\"a\",b)}catch(e){d=B",
+    "(y(b),\"A\",null,b)}return qa(d,function(b){b=nc(b);b=b.replace(/^[\\s]",
+    "+|[\\s]+$/g,\"\");return c&&-1!=b.indexOf(a)||b==a})};Z.A=function(a,b)",
+    "{return Z.ja(a,b,!1)};Z.l=function(a,b){return Z.ea(a,b,!1)};vc.A=funct",
+    "ion(a,b){return Z.ja(a,b,!0)};\nvc.l=function(a,b){return Z.ea(a,b,!0)}",
+    ";var wc={A:function(a,b){if(\"\"===a)throw new t(32,'Unable to locate a",
+    "n element with the tagName \"\"');return b.getElementsByTagName(a)[0]||",
+    "null},l:function(a,b){if(\"\"===a)throw new t(32,'Unable to locate an e",
+    "lement with the tagName \"\"');return b.getElementsByTagName(a)}};var x",
+    "c={className:Ja,\"class name\":Ja,css:Ka,\"css selector\":Ka,id:uc,link",
+    "Text:Z,\"link text\":Z,name:{A:function(a,b){b=B(y(b),\"*\",null,b);ret",
+    "urn ua(b,function(b){return Ra(b,\"name\")==a})},l:function(a,b){b=B(y(",
+    "b),\"*\",null,b);return qa(b,function(b){return Ra(b,\"name\")==a})}},p",
+    "artialLinkText:vc,\"partial link text\":vc,tagName:wc,\"tag name\":wc,x",
+    "path:U};ba(\"_\",function(a,b){a:{for(c in a)if(a.hasOwnProperty(c))bre",
+    "ak a;var c=null}if(c){var d=xc[c];if(d&&p(d.l))return d.l(a[c],b||ja.do",
+    "cument)}throw new t(61,\"Unsupported locator strategy: \"+c);});; retur",
+    "n this._.apply(null,arguments);}.apply({navigator:typeof window!='undef",
+    "ined'?window.navigator:null,document:typeof window!='undefined'?window.",
+    "document:null}, arguments);}",
     NULL
 };
 
@@ -3724,14 +3724,14 @@
     ",0,0)}function Vb(a){a=Rb(a);return new Mb(a.top,a.left+a.width,a.top+a",
     ".height,a.left)}\nfunction Ub(a){var b=1,c=Y(a,\"opacity\");c&&(b=Numbe",
     "r(c));(a=Ob(a))&&(b*=Ub(a));return b};ba(\"_\",function(a,b){function c",
-    "(a){if(A(a)&&\"none\"==Y(a,\"display\"))return!1;var b;(b=a.parentNode)",
-    "&&b.shadowRoot&&void 0!==a.assignedSlot?b=a.assignedSlot?a.assignedSlot",
-    ".parentNode:null:a.getDestinationInsertionPoints&&(a=a.getDestinationIn",
-    "sertionPoints(),0<a.length&&(b=a[a.length-1]));return Nb&&b instanceof ",
-    "ShadowRoot||b&&(9==b.nodeType||11==b.nodeType)?!0:!!b&&c(b)}return Qb(a",
-    ",!!b,c)});; return this._.apply(null,arguments);}.apply({navigator:type",
-    "of window!='undefined'?window.navigator:null,document:typeof window!='u",
-    "ndefined'?window.document:null}, arguments);}",
+    "(a){if(A(a)&&\"none\"==Y(a,\"display\"))return!1;a:{var b=a.parentNode;",
+    "if(a.getDestinationInsertionPoints){var d=a.getDestinationInsertionPoin",
+    "ts();if(0<d.length){a=d[d.length-1];break a}}a=b&&b.shadowRoot&&void 0!",
+    "==a.assignedSlot?a.assignedSlot?a.assignedSlot.parentNode:null:b}return",
+    " Nb&&a instanceof ShadowRoot||a&&(9==a.nodeType||11==a.nodeType)?!0:!!a",
+    "&&c(a)}return Qb(a,!!b,c)});; return this._.apply(null,arguments);}.app",
+    "ly({navigator:typeof window!='undefined'?window.navigator:null,document",
+    ":typeof window!='undefined'?window.document:null}, arguments);}",
     NULL
 };
 
@@ -5209,138 +5209,139 @@
     "NPUT\")&&\"hidden\"==a.type.toLowerCase()||C(a,\"NOSCRIPT\"))return!1;f",
     "=X(a,\"visibility\");return\"collapse\"!=f&&\"hidden\"!=f&&c(a)&&(b||0!",
     "=gc(a))&&d(a)?!e(a):!1}\nfunction hc(a){function b(a){if(C(a)&&\"none\"",
-    "==X(a,\"display\"))return!1;var c;(c=a.parentNode)&&c.shadowRoot&&void ",
-    "0!==a.assignedSlot?c=a.assignedSlot?a.assignedSlot.parentNode:null:a.ge",
-    "tDestinationInsertionPoints&&(a=a.getDestinationInsertionPoints(),0<a.l",
-    "ength&&(c=a[a.length-1]));return $b&&c instanceof ShadowRoot||c&&(9==c.",
-    "nodeType||11==c.nodeType)?!0:!!c&&b(c)}return cc(a,!1,b)}var Y=\"hidden",
-    "\";\nfunction ec(a){function b(a){function b(a){return a==g?!0:0==X(a,",
-    "\"display\").lastIndexOf(\"inline\",0)||\"absolute\"==c&&\"static\"==X(",
-    "a,\"position\")?!1:!0}var c=X(a,\"position\");if(\"fixed\"==c)return D=",
-    "!0,a==g?null:g;for(a=ac(a);a&&!b(a);)a=ac(a);return a}function c(a){var",
-    " b=a;if(\"visible\"==u)if(a==g&&k)b=k;else if(a==k)return{x:\"visible\"",
-    ",y:\"visible\"};b={x:X(b,\"overflow-x\"),y:X(b,\"overflow-y\")};a==g&&(",
-    "b.x=\"visible\"==b.x?\"auto\":b.x,b.y=\"visible\"==b.y?\"auto\":b.y);re",
-    "turn b}function d(a){if(a==g){var b=(new Ga(f)).C;\na=b.scrollingElemen",
-    "t?b.scrollingElement:b.body||b.documentElement;b=b.parentWindow||b.defa",
-    "ultView;a=new x(b.pageXOffset||a.scrollLeft,b.pageYOffset||a.scrollTop)",
-    "}else a=new x(a.scrollLeft,a.scrollTop);return a}var e=ic(a);var f=z(a)",
-    ",g=f.documentElement,k=f.body,u=X(g,\"overflow\"),D;for(a=b(a);a;a=b(a)",
-    "){var r=c(a);if(\"visible\"!=r.x||\"visible\"!=r.y){var A=dc(a);if(0==A",
-    ".width||0==A.height)return Y;var L=e.right<A.left,W=e.bottom<A.top;if(L",
-    "&&\"hidden\"==r.x||W&&\"hidden\"==r.y)return Y;if(L&&\"visible\"!=r.x||",
-    "\nW&&\"visible\"!=r.y){L=d(a);W=e.bottom<A.top-L.y;if(e.right<A.left-L.",
-    "x&&\"visible\"!=r.x||W&&\"visible\"!=r.x)return Y;e=ec(a);return e==Y?Y",
-    ":\"scroll\"}L=e.left>=A.left+A.width;A=e.top>=A.top+A.height;if(L&&\"hi",
-    "dden\"==r.x||A&&\"hidden\"==r.y)return Y;if(L&&\"visible\"!=r.x||A&&\"v",
-    "isible\"!=r.y){if(D&&(r=d(a),e.left>=g.scrollWidth-r.x||e.right>=g.scro",
-    "llHeight-r.y))return Y;e=ec(a);return e==Y?Y:\"scroll\"}}}return\"none",
-    "\"}\nfunction dc(a){var b=fc(a);if(b)return b.rect;if(C(a,\"HTML\"))ret",
-    "urn a=z(a),a=((a?a.parentWindow||a.defaultView:window)||window).documen",
-    "t,a=\"CSS1Compat\"==a.compatMode?a.documentElement:a.body,a=new Fa(a.cl",
-    "ientWidth,a.clientHeight),new V(0,0,a.width,a.height);try{var c=a.getBo",
-    "undingClientRect()}catch(d){return new V(0,0,0,0)}return new V(c.left,c",
-    ".top,c.right-c.left,c.bottom-c.top)}\nfunction fc(a){var b=C(a,\"MAP\")",
-    ";if(!b&&!C(a,\"AREA\"))return null;var c=b?a:C(a.parentNode,\"MAP\")?a.",
-    "parentNode:null,d=null,e=null;c&&c.name&&(d=U.u('/descendant::*[@usemap",
-    " = \"#'+c.name+'\"]',z(c)))&&(e=dc(d),b||\"default\"==a.shape.toLowerCa",
-    "se()||(a=jc(a),b=Math.min(Math.max(a.left,0),e.width),c=Math.min(Math.m",
-    "ax(a.top,0),e.height),e=new V(b+e.left,c+e.top,Math.min(a.width,e.width",
-    "-b),Math.min(a.height,e.height-c))));return{ba:d,rect:e||new V(0,0,0,0)",
-    "}}\nfunction jc(a){var b=a.shape.toLowerCase();a=a.coords.split(\",\");",
-    "if(\"rect\"==b&&4==a.length){var b=a[0],c=a[1];return new V(b,c,a[2]-b,",
-    "a[3]-c)}if(\"circle\"==b&&3==a.length)return b=a[2],new V(a[0]-b,a[1]-b",
-    ",2*b,2*b);if(\"poly\"==b&&2<a.length){for(var b=a[0],c=a[1],d=b,e=c,f=2",
-    ";f+1<a.length;f+=2)b=Math.min(b,a[f]),d=Math.max(d,a[f]),c=Math.min(c,a",
-    "[f+1]),e=Math.max(e,a[f+1]);return new V(b,c,d-b,e-c)}return new V(0,0,",
-    "0,0)}function ic(a){a=dc(a);return new Zb(a.top,a.left+a.width,a.top+a.",
-    "height,a.left)}\nfunction kc(a){return a.replace(/^[^\\S\\xa0]+|[^\\S",
-    "\\xa0]+$/g,\"\")}function lc(a){var b=[];$b?mc(a,b):nc(a,b);var c=b;a=c",
-    ".length;for(var b=Array(a),c=m(c)?c.split(\"\"):c,d=0;d<a;d++)d in c&&(",
-    "b[d]=kc.call(void 0,c[d]));return kc(b.join(\"\\n\")).replace(/\\xa0/g,",
-    "\" \")}\nfunction oc(a,b,c){if(C(a,\"BR\"))b.push(\"\");else{var d=C(a,",
-    "\"TD\"),e=X(a,\"display\"),f=!d&&!(0<=oa(pc,e)),g=l(a.previousElementSi",
-    "bling)?a.previousElementSibling:Ja(a.previousSibling),g=g?X(g,\"display",
-    "\"):\"\",k=X(a,\"float\")||X(a,\"cssFloat\")||X(a,\"styleFloat\");!f||",
-    "\"run-in\"==g&&\"none\"==k||/^[\\s\\xa0]*$/.test(b[b.length-1]||\"\")||",
-    "b.push(\"\");var u=hc(a),D=null,r=null;u&&(D=X(a,\"white-space\"),r=X(a",
-    ",\"text-transform\"));t(a.childNodes,function(a){c(a,b,u,D,r)});a=b[b.l",
-    "ength-1]||\"\";!d&&\"table-cell\"!=e||!a||la(a)||(b[b.length-\n1]+=\" ",
-    "\");f&&\"run-in\"!=e&&!/^[\\s\\xa0]*$/.test(a)&&b.push(\"\")}}function ",
-    "nc(a,b){oc(a,b,function(a,b,e,f,g){3==a.nodeType&&e?qc(a,b,f,g):C(a)&&n",
-    "c(a,b)})}var pc=\"inline inline-block inline-table none table-cell tabl",
-    "e-column table-column-group\".split(\" \");\nfunction qc(a,b,c,d){a=a.n",
-    "odeValue.replace(/[\\u200b\\u200e\\u200f]/g,\"\");a=a.replace(/(\\r\\n|",
-    "\\r|\\n)/g,\"\\n\");if(\"normal\"==c||\"nowrap\"==c)a=a.replace(/\\n/g,",
-    "\" \");a=\"pre\"==c||\"pre-wrap\"==c?a.replace(/[ \\f\\t\\v\\u2028\\u20",
-    "29]/g,\"\\u00a0\"):a.replace(/[\\ \\f\\t\\v\\u2028\\u2029]+/g,\" \");\"",
-    "capitalize\"==d?a=a.replace(/(^|\\s)(\\S)/g,function(a,b,c){return b+c.",
-    "toUpperCase()}):\"uppercase\"==d?a=a.toUpperCase():\"lowercase\"==d&&(a",
-    "=a.toLowerCase());c=b.pop()||\"\";la(c)&&0==a.lastIndexOf(\" \",0)&&(a=",
-    "a.substr(1));b.push(c+a)}\nfunction gc(a){var b=1,c=X(a,\"opacity\");c&",
-    "&(b=Number(c));(a=ac(a))&&(b*=gc(a));return b}\nfunction rc(a,b,c,d,e){",
-    "var f;if(3==a.nodeType&&c)qc(a,b,d,e);else if(C(a))if(C(a,\"CONTENT\")|",
-    "|C(a,\"SLOT\")){for(f=a;f.parentNode;)f=f.parentNode;f instanceof Shado",
-    "wRoot?(a=C(a,\"CONTENT\")?a.getDistributedNodes():a.assignedNodes(),t(a",
-    ",function(a){rc(a,b,c,d,e)})):mc(a,b)}else if(C(a,\"SHADOW\")){for(f=a;",
-    "f.parentNode;)f=f.parentNode;if(f instanceof ShadowRoot&&(a=f))for(a=a.",
-    "olderShadowRoot;a;)t(a.childNodes,function(a){rc(a,b,c,d,e)}),a=a.older",
-    "ShadowRoot}else mc(a,b)}\nfunction mc(a,b){a.shadowRoot&&t(a.shadowRoot",
-    ".childNodes,function(a){rc(a,b,!0,null,null)});oc(a,b,function(a,b,e,f,",
-    "g){var c=null;1==a.nodeType?c=a:3==a.nodeType&&(c=a);null!=c&&(null!=c.",
-    "assignedSlot||c.getDestinationInsertionPoints&&0<c.getDestinationInsert",
-    "ionPoints().length)||rc(a,b,e,f,g)})};var sc={K:function(a){return!(!a.",
-    "querySelectorAll||!a.querySelector)},u:function(a,b){if(!a)throw new v(",
-    "32,\"No class name specified\");a=ma(a);if(-1!==a.indexOf(\" \"))throw ",
-    "new v(32,\"Compound class names not permitted\");if(sc.K(b))try{return ",
-    "b.querySelector(\".\"+a.replace(/\\./g,\"\\\\.\"))||null}catch(c){throw",
-    " new v(32,\"An invalid or illegal class name was specified\");}a=B(y(b)",
-    ",\"*\",a,b);return a.length?a[0]:null},l:function(a,b){if(!a)throw new ",
-    "v(32,\"No class name specified\");a=ma(a);if(-1!==a.indexOf(\" \"))thro",
-    "w new v(32,\n\"Compound class names not permitted\");if(sc.K(b))try{ret",
-    "urn b.querySelectorAll(\".\"+a.replace(/\\./g,\"\\\\.\"))}catch(c){thro",
-    "w new v(32,\"An invalid or illegal class name was specified\");}return ",
-    "B(y(b),\"*\",a,b)}};var tc={u:function(a,b){p(b.querySelector);if(!a)th",
-    "row new v(32,\"No selector specified\");a=ma(a);try{var c=b.querySelect",
-    "or(a)}catch(d){throw new v(32,\"An invalid or illegal selector was spec",
-    "ified\");}return c&&1==c.nodeType?c:null},l:function(a,b){p(b.querySele",
-    "ctorAll);if(!a)throw new v(32,\"No selector specified\");a=ma(a);try{re",
-    "turn b.querySelectorAll(a)}catch(c){throw new v(32,\"An invalid or ille",
-    "gal selector was specified\");}}};var uc={K:function(a,b){return!(!a.qu",
-    "erySelectorAll||!a.querySelector)&&!/^\\d.*/.test(b)},u:function(a,b){v",
-    "ar c=y(b),d=m(a)?c.C.getElementById(a):a;return d?Pa(d,\"id\")==a&&b!=d",
-    "&&Ka(b,d)?d:ta(B(c,\"*\"),function(c){return Pa(c,\"id\")==a&&b!=c&&Ka(",
-    "b,c)}):null},l:function(a,b){if(!a)return[];if(uc.K(b,a))try{return b.q",
-    "uerySelectorAll(\"#\"+uc.na(a))}catch(c){return[]}b=B(y(b),\"*\",null,b",
-    ");return pa(b,function(b){return Pa(b,\"id\")==a})},na:function(a){retu",
-    "rn a.replace(/([\\s'\"\\\\#.:;,!?+<>=~*^$|%&@`{}\\-\\/\\[\\]\\(\\)])/g,",
-    "\n\"\\\\$1\")}};var Z={},vc={};Z.ja=function(a,b,c){try{var d=tc.l(\"a",
-    "\",b)}catch(e){d=B(y(b),\"A\",null,b)}return ta(d,function(b){b=lc(b);b",
-    "=b.replace(/^[\\s]+|[\\s]+$/g,\"\");return c&&-1!=b.indexOf(a)||b==a})}",
-    ";Z.ea=function(a,b,c){try{var d=tc.l(\"a\",b)}catch(e){d=B(y(b),\"A\",n",
-    "ull,b)}return pa(d,function(b){b=lc(b);b=b.replace(/^[\\s]+|[\\s]+$/g,",
-    "\"\");return c&&-1!=b.indexOf(a)||b==a})};Z.u=function(a,b){return Z.ja",
-    "(a,b,!1)};Z.l=function(a,b){return Z.ea(a,b,!1)};vc.u=function(a,b){ret",
-    "urn Z.ja(a,b,!0)};\nvc.l=function(a,b){return Z.ea(a,b,!0)};var wc={u:f",
-    "unction(a,b){if(\"\"===a)throw new v(32,'Unable to locate an element wi",
-    "th the tagName \"\"');return b.getElementsByTagName(a)[0]||null},l:func",
-    "tion(a,b){if(\"\"===a)throw new v(32,'Unable to locate an element with ",
-    "the tagName \"\"');return b.getElementsByTagName(a)}};var xc={className",
-    ":sc,\"class name\":sc,css:tc,\"css selector\":tc,id:uc,linkText:Z,\"lin",
-    "k text\":Z,name:{u:function(a,b){b=B(y(b),\"*\",null,b);return ta(b,fun",
-    "ction(b){return Pa(b,\"name\")==a})},l:function(a,b){b=B(y(b),\"*\",nul",
-    "l,b);return pa(b,function(b){return Pa(b,\"name\")==a})}},partialLinkTe",
-    "xt:vc,\"partial link text\":vc,tagName:wc,\"tag name\":wc,xpath:U};func",
-    "tion yc(a){for(var b in a)if(a.hasOwnProperty(b))return b;return null};",
-    "var zc=\"function\"===typeof ShadowRoot;ba(\"_\",function(a,b){var c;a:",
-    "{if(c=yc(a)){var d=xc[c];if(d&&p(d.u)){c=d.u(a[c],b||ja.document);break",
-    " a}}throw new v(61,\"Unsupported locator strategy: \"+c);}if(c)return c",
-    ";if(zc&&b){for(c=b;c.parentNode;)c=c.parentNode;if(c instanceof ShadowR",
-    "oot){a:{if((c=yc(a))&&(d=xc[c])&&p(d.l)){a=d.l(a[c],b||ja.document);bre",
-    "ak a}throw new v(61,\"Unsupported locator strategy: \"+c);}if(c=a[0])re",
-    "turn c}}return null});; return this._.apply(null,arguments);}.apply({na",
-    "vigator:typeof window!='undefined'?window.navigator:null,document:typeo",
-    "f window!='undefined'?window.document:null}, arguments);}",
+    "==X(a,\"display\"))return!1;a:{var c=a.parentNode;if(a.getDestinationIn",
+    "sertionPoints){var e=a.getDestinationInsertionPoints();if(0<e.length){a",
+    "=e[e.length-1];break a}}a=c&&c.shadowRoot&&void 0!==a.assignedSlot?a.as",
+    "signedSlot?a.assignedSlot.parentNode:null:c}return $b&&a instanceof Sha",
+    "dowRoot||a&&(9==a.nodeType||11==a.nodeType)?!0:!!a&&b(a)}return cc(a,!1",
+    ",b)}var Y=\"hidden\";\nfunction ec(a){function b(a){function b(a){retur",
+    "n a==g?!0:0==X(a,\"display\").lastIndexOf(\"inline\",0)||\"absolute\"==",
+    "c&&\"static\"==X(a,\"position\")?!1:!0}var c=X(a,\"position\");if(\"fix",
+    "ed\"==c)return D=!0,a==g?null:g;for(a=ac(a);a&&!b(a);)a=ac(a);return a}",
+    "function c(a){var b=a;if(\"visible\"==u)if(a==g&&k)b=k;else if(a==k)ret",
+    "urn{x:\"visible\",y:\"visible\"};b={x:X(b,\"overflow-x\"),y:X(b,\"overf",
+    "low-y\")};a==g&&(b.x=\"visible\"==b.x?\"auto\":b.x,b.y=\"visible\"==b.y",
+    "?\"auto\":b.y);return b}function d(a){if(a==g){var b=(new Ga(f)).C;\na=",
+    "b.scrollingElement?b.scrollingElement:b.body||b.documentElement;b=b.par",
+    "entWindow||b.defaultView;a=new x(b.pageXOffset||a.scrollLeft,b.pageYOff",
+    "set||a.scrollTop)}else a=new x(a.scrollLeft,a.scrollTop);return a}var e",
+    "=ic(a);var f=z(a),g=f.documentElement,k=f.body,u=X(g,\"overflow\"),D;fo",
+    "r(a=b(a);a;a=b(a)){var r=c(a);if(\"visible\"!=r.x||\"visible\"!=r.y){va",
+    "r A=dc(a);if(0==A.width||0==A.height)return Y;var L=e.right<A.left,W=e.",
+    "bottom<A.top;if(L&&\"hidden\"==r.x||W&&\"hidden\"==r.y)return Y;if(L&&",
+    "\"visible\"!=r.x||\nW&&\"visible\"!=r.y){L=d(a);W=e.bottom<A.top-L.y;if",
+    "(e.right<A.left-L.x&&\"visible\"!=r.x||W&&\"visible\"!=r.x)return Y;e=e",
+    "c(a);return e==Y?Y:\"scroll\"}L=e.left>=A.left+A.width;A=e.top>=A.top+A",
+    ".height;if(L&&\"hidden\"==r.x||A&&\"hidden\"==r.y)return Y;if(L&&\"visi",
+    "ble\"!=r.x||A&&\"visible\"!=r.y){if(D&&(r=d(a),e.left>=g.scrollWidth-r.",
+    "x||e.right>=g.scrollHeight-r.y))return Y;e=ec(a);return e==Y?Y:\"scroll",
+    "\"}}}return\"none\"}\nfunction dc(a){var b=fc(a);if(b)return b.rect;if(",
+    "C(a,\"HTML\"))return a=z(a),a=((a?a.parentWindow||a.defaultView:window)",
+    "||window).document,a=\"CSS1Compat\"==a.compatMode?a.documentElement:a.b",
+    "ody,a=new Fa(a.clientWidth,a.clientHeight),new V(0,0,a.width,a.height);",
+    "try{var c=a.getBoundingClientRect()}catch(d){return new V(0,0,0,0)}retu",
+    "rn new V(c.left,c.top,c.right-c.left,c.bottom-c.top)}\nfunction fc(a){v",
+    "ar b=C(a,\"MAP\");if(!b&&!C(a,\"AREA\"))return null;var c=b?a:C(a.paren",
+    "tNode,\"MAP\")?a.parentNode:null,d=null,e=null;c&&c.name&&(d=U.u('/desc",
+    "endant::*[@usemap = \"#'+c.name+'\"]',z(c)))&&(e=dc(d),b||\"default\"==",
+    "a.shape.toLowerCase()||(a=jc(a),b=Math.min(Math.max(a.left,0),e.width),",
+    "c=Math.min(Math.max(a.top,0),e.height),e=new V(b+e.left,c+e.top,Math.mi",
+    "n(a.width,e.width-b),Math.min(a.height,e.height-c))));return{ba:d,rect:",
+    "e||new V(0,0,0,0)}}\nfunction jc(a){var b=a.shape.toLowerCase();a=a.coo",
+    "rds.split(\",\");if(\"rect\"==b&&4==a.length){var b=a[0],c=a[1];return ",
+    "new V(b,c,a[2]-b,a[3]-c)}if(\"circle\"==b&&3==a.length)return b=a[2],ne",
+    "w V(a[0]-b,a[1]-b,2*b,2*b);if(\"poly\"==b&&2<a.length){for(var b=a[0],c",
+    "=a[1],d=b,e=c,f=2;f+1<a.length;f+=2)b=Math.min(b,a[f]),d=Math.max(d,a[f",
+    "]),c=Math.min(c,a[f+1]),e=Math.max(e,a[f+1]);return new V(b,c,d-b,e-c)}",
+    "return new V(0,0,0,0)}function ic(a){a=dc(a);return new Zb(a.top,a.left",
+    "+a.width,a.top+a.height,a.left)}\nfunction kc(a){return a.replace(/^[^",
+    "\\S\\xa0]+|[^\\S\\xa0]+$/g,\"\")}function lc(a){var b=[];$b?mc(a,b):nc(",
+    "a,b);var c=b;a=c.length;for(var b=Array(a),c=m(c)?c.split(\"\"):c,d=0;d",
+    "<a;d++)d in c&&(b[d]=kc.call(void 0,c[d]));return kc(b.join(\"\\n\")).r",
+    "eplace(/\\xa0/g,\" \")}\nfunction oc(a,b,c){if(C(a,\"BR\"))b.push(\"\")",
+    ";else{var d=C(a,\"TD\"),e=X(a,\"display\"),f=!d&&!(0<=oa(pc,e)),g=l(a.p",
+    "reviousElementSibling)?a.previousElementSibling:Ja(a.previousSibling),g",
+    "=g?X(g,\"display\"):\"\",k=X(a,\"float\")||X(a,\"cssFloat\")||X(a,\"sty",
+    "leFloat\");!f||\"run-in\"==g&&\"none\"==k||/^[\\s\\xa0]*$/.test(b[b.len",
+    "gth-1]||\"\")||b.push(\"\");var u=hc(a),D=null,r=null;u&&(D=X(a,\"white",
+    "-space\"),r=X(a,\"text-transform\"));t(a.childNodes,function(a){c(a,b,u",
+    ",D,r)});a=b[b.length-1]||\"\";!d&&\"table-cell\"!=e||!a||la(a)||(b[b.le",
+    "ngth-\n1]+=\" \");f&&\"run-in\"!=e&&!/^[\\s\\xa0]*$/.test(a)&&b.push(\"",
+    "\")}}function nc(a,b){oc(a,b,function(a,b,e,f,g){3==a.nodeType&&e?qc(a,",
+    "b,f,g):C(a)&&nc(a,b)})}var pc=\"inline inline-block inline-table none t",
+    "able-cell table-column table-column-group\".split(\" \");\nfunction qc(",
+    "a,b,c,d){a=a.nodeValue.replace(/[\\u200b\\u200e\\u200f]/g,\"\");a=a.rep",
+    "lace(/(\\r\\n|\\r|\\n)/g,\"\\n\");if(\"normal\"==c||\"nowrap\"==c)a=a.r",
+    "eplace(/\\n/g,\" \");a=\"pre\"==c||\"pre-wrap\"==c?a.replace(/[ \\f\\t",
+    "\\v\\u2028\\u2029]/g,\"\\u00a0\"):a.replace(/[\\ \\f\\t\\v\\u2028\\u202",
+    "9]+/g,\" \");\"capitalize\"==d?a=a.replace(/(^|\\s)(\\S)/g,function(a,b",
+    ",c){return b+c.toUpperCase()}):\"uppercase\"==d?a=a.toUpperCase():\"low",
+    "ercase\"==d&&(a=a.toLowerCase());c=b.pop()||\"\";la(c)&&0==a.lastIndexO",
+    "f(\" \",0)&&(a=a.substr(1));b.push(c+a)}\nfunction gc(a){var b=1,c=X(a,",
+    "\"opacity\");c&&(b=Number(c));(a=ac(a))&&(b*=gc(a));return b}\nfunction",
+    " rc(a,b,c,d,e){var f;if(3==a.nodeType&&c)qc(a,b,d,e);else if(C(a))if(C(",
+    "a,\"CONTENT\")||C(a,\"SLOT\")){for(f=a;f.parentNode;)f=f.parentNode;f i",
+    "nstanceof ShadowRoot?(a=C(a,\"CONTENT\")?a.getDistributedNodes():a.assi",
+    "gnedNodes(),t(a,function(a){rc(a,b,c,d,e)})):mc(a,b)}else if(C(a,\"SHAD",
+    "OW\")){for(f=a;f.parentNode;)f=f.parentNode;if(f instanceof ShadowRoot&",
+    "&(a=f))for(a=a.olderShadowRoot;a;)t(a.childNodes,function(a){rc(a,b,c,d",
+    ",e)}),a=a.olderShadowRoot}else mc(a,b)}\nfunction mc(a,b){a.shadowRoot&",
+    "&t(a.shadowRoot.childNodes,function(a){rc(a,b,!0,null,null)});oc(a,b,fu",
+    "nction(a,b,e,f,g){var c=null;1==a.nodeType?c=a:3==a.nodeType&&(c=a);nul",
+    "l!=c&&(null!=c.assignedSlot||c.getDestinationInsertionPoints&&0<c.getDe",
+    "stinationInsertionPoints().length)||rc(a,b,e,f,g)})};var sc={K:function",
+    "(a){return!(!a.querySelectorAll||!a.querySelector)},u:function(a,b){if(",
+    "!a)throw new v(32,\"No class name specified\");a=ma(a);if(-1!==a.indexO",
+    "f(\" \"))throw new v(32,\"Compound class names not permitted\");if(sc.K",
+    "(b))try{return b.querySelector(\".\"+a.replace(/\\./g,\"\\\\.\"))||null",
+    "}catch(c){throw new v(32,\"An invalid or illegal class name was specifi",
+    "ed\");}a=B(y(b),\"*\",a,b);return a.length?a[0]:null},l:function(a,b){i",
+    "f(!a)throw new v(32,\"No class name specified\");a=ma(a);if(-1!==a.inde",
+    "xOf(\" \"))throw new v(32,\n\"Compound class names not permitted\");if(",
+    "sc.K(b))try{return b.querySelectorAll(\".\"+a.replace(/\\./g,\"\\\\.\")",
+    ")}catch(c){throw new v(32,\"An invalid or illegal class name was specif",
+    "ied\");}return B(y(b),\"*\",a,b)}};var tc={u:function(a,b){p(b.querySel",
+    "ector);if(!a)throw new v(32,\"No selector specified\");a=ma(a);try{var ",
+    "c=b.querySelector(a)}catch(d){throw new v(32,\"An invalid or illegal se",
+    "lector was specified\");}return c&&1==c.nodeType?c:null},l:function(a,b",
+    "){p(b.querySelectorAll);if(!a)throw new v(32,\"No selector specified\")",
+    ";a=ma(a);try{return b.querySelectorAll(a)}catch(c){throw new v(32,\"An ",
+    "invalid or illegal selector was specified\");}}};var uc={K:function(a,b",
+    "){return!(!a.querySelectorAll||!a.querySelector)&&!/^\\d.*/.test(b)},u:",
+    "function(a,b){var c=y(b),d=m(a)?c.C.getElementById(a):a;return d?Pa(d,",
+    "\"id\")==a&&b!=d&&Ka(b,d)?d:ta(B(c,\"*\"),function(c){return Pa(c,\"id",
+    "\")==a&&b!=c&&Ka(b,c)}):null},l:function(a,b){if(!a)return[];if(uc.K(b,",
+    "a))try{return b.querySelectorAll(\"#\"+uc.na(a))}catch(c){return[]}b=B(",
+    "y(b),\"*\",null,b);return pa(b,function(b){return Pa(b,\"id\")==a})},na",
+    ":function(a){return a.replace(/([\\s'\"\\\\#.:;,!?+<>=~*^$|%&@`{}\\-\\/",
+    "\\[\\]\\(\\)])/g,\n\"\\\\$1\")}};var Z={},vc={};Z.ja=function(a,b,c){tr",
+    "y{var d=tc.l(\"a\",b)}catch(e){d=B(y(b),\"A\",null,b)}return ta(d,funct",
+    "ion(b){b=lc(b);b=b.replace(/^[\\s]+|[\\s]+$/g,\"\");return c&&-1!=b.ind",
+    "exOf(a)||b==a})};Z.ea=function(a,b,c){try{var d=tc.l(\"a\",b)}catch(e){",
+    "d=B(y(b),\"A\",null,b)}return pa(d,function(b){b=lc(b);b=b.replace(/^[",
+    "\\s]+|[\\s]+$/g,\"\");return c&&-1!=b.indexOf(a)||b==a})};Z.u=function(",
+    "a,b){return Z.ja(a,b,!1)};Z.l=function(a,b){return Z.ea(a,b,!1)};vc.u=f",
+    "unction(a,b){return Z.ja(a,b,!0)};\nvc.l=function(a,b){return Z.ea(a,b,",
+    "!0)};var wc={u:function(a,b){if(\"\"===a)throw new v(32,'Unable to loca",
+    "te an element with the tagName \"\"');return b.getElementsByTagName(a)[",
+    "0]||null},l:function(a,b){if(\"\"===a)throw new v(32,'Unable to locate ",
+    "an element with the tagName \"\"');return b.getElementsByTagName(a)}};v",
+    "ar xc={className:sc,\"class name\":sc,css:tc,\"css selector\":tc,id:uc,",
+    "linkText:Z,\"link text\":Z,name:{u:function(a,b){b=B(y(b),\"*\",null,b)",
+    ";return ta(b,function(b){return Pa(b,\"name\")==a})},l:function(a,b){b=",
+    "B(y(b),\"*\",null,b);return pa(b,function(b){return Pa(b,\"name\")==a})",
+    "}},partialLinkText:vc,\"partial link text\":vc,tagName:wc,\"tag name\":",
+    "wc,xpath:U};function yc(a){for(var b in a)if(a.hasOwnProperty(b))return",
+    " b;return null};var zc=\"function\"===typeof ShadowRoot;ba(\"_\",functi",
+    "on(a,b){var c;a:{if(c=yc(a)){var d=xc[c];if(d&&p(d.u)){c=d.u(a[c],b||ja",
+    ".document);break a}}throw new v(61,\"Unsupported locator strategy: \"+c",
+    ");}if(c)return c;if(zc&&b){for(c=b;c.parentNode;)c=c.parentNode;if(c in",
+    "stanceof ShadowRoot){a:{if((c=yc(a))&&(d=xc[c])&&p(d.l)){a=d.l(a[c],b||",
+    "ja.document);break a}throw new v(61,\"Unsupported locator strategy: \"+",
+    "c);}if(c=a[0])return c}}return null});; return this._.apply(null,argume",
+    "nts);}.apply({navigator:typeof window!='undefined'?window.navigator:nul",
+    "l,document:typeof window!='undefined'?window.document:null}, arguments)",
+    ";}",
     NULL
 };
 
@@ -7609,58 +7610,58 @@
     "pe.toLowerCase()||z(a,\"NOSCRIPT\"))return!1;f=Y(a,\"visibility\");retu",
     "rn\"collapse\"!=f&&\"hidden\"!=f&&c(a)&&(b||0!=Tb(a))&&d(a)?!e(a):!1}\n",
     "function Ub(a,b){function c(a){if(z(a)&&\"none\"==Y(a,\"display\"))retu",
-    "rn!1;var b;(b=a.parentNode)&&b.shadowRoot&&void 0!==a.assignedSlot?b=a.",
-    "assignedSlot?a.assignedSlot.parentNode:null:a.getDestinationInsertionPo",
-    "ints&&(a=a.getDestinationInsertionPoints(),0<a.length&&(b=a[a.length-1]",
-    "));return Mb&&b instanceof ShadowRoot||b&&(9==b.nodeType||11==b.nodeTyp",
-    "e)?!0:!!b&&c(b)}return Pb(a,!!b,c)}var Z=\"hidden\";\nfunction Rb(a){fu",
-    "nction b(a){function b(a){return a==g?!0:0==Y(a,\"display\").lastIndexO",
-    "f(\"inline\",0)||\"absolute\"==c&&\"static\"==Y(a,\"position\")?!1:!0}v",
-    "ar c=Y(a,\"position\");if(\"fixed\"==c)return D=!0,a==g?null:g;for(a=Nb",
-    "(a);a&&!b(a);)a=Nb(a);return a}function c(a){var b=a;if(\"visible\"==w)",
-    "if(a==g&&l)b=l;else if(a==l)return{x:\"visible\",y:\"visible\"};b={x:Y(",
-    "b,\"overflow-x\"),y:Y(b,\"overflow-y\")};a==g&&(b.x=\"visible\"==b.x?\"",
-    "auto\":b.x,b.y=\"visible\"==b.y?\"auto\":b.y);return b}function d(a){if",
-    "(a==g){var b=(new Ha(f)).H;\na=b.scrollingElement?b.scrollingElement:b.",
-    "body||b.documentElement;b=b.parentWindow||b.defaultView;a=new v(b.pageX",
-    "Offset||a.scrollLeft,b.pageYOffset||a.scrollTop)}else a=new v(a.scrollL",
-    "eft,a.scrollTop);return a}var e=Vb(a);var f=x(a),g=f.documentElement,l=",
-    "f.body,w=Y(g,\"overflow\"),D;for(a=b(a);a;a=b(a)){var q=c(a);if(\"visib",
-    "le\"!=q.x||\"visible\"!=q.y){var y=Qb(a);if(0==y.width||0==y.height)ret",
-    "urn Z;var H=e.right<y.left,S=e.bottom<y.top;if(H&&\"hidden\"==q.x||S&&",
-    "\"hidden\"==q.y)return Z;if(H&&\"visible\"!=q.x||\nS&&\"visible\"!=q.y)",
-    "{H=d(a);S=e.bottom<y.top-H.y;if(e.right<y.left-H.x&&\"visible\"!=q.x||S",
-    "&&\"visible\"!=q.x)return Z;e=Rb(a);return e==Z?Z:\"scroll\"}H=e.left>=",
-    "y.left+y.width;y=e.top>=y.top+y.height;if(H&&\"hidden\"==q.x||y&&\"hidd",
-    "en\"==q.y)return Z;if(H&&\"visible\"!=q.x||y&&\"visible\"!=q.y){if(D&&(",
-    "q=d(a),e.left>=g.scrollWidth-q.x||e.right>=g.scrollHeight-q.y))return Z",
-    ";e=Rb(a);return e==Z?Z:\"scroll\"}}}return\"none\"}\nfunction Qb(a){var",
-    " b=Sb(a);if(b)return b.rect;if(z(a,\"HTML\"))return a=x(a),a=((a?a.pare",
-    "ntWindow||a.defaultView:window)||window).document,a=\"CSS1Compat\"==a.c",
-    "ompatMode?a.documentElement:a.body,a=new za(a.clientWidth,a.clientHeigh",
-    "t),new X(0,0,a.width,a.height);try{var c=a.getBoundingClientRect()}catc",
-    "h(d){return new X(0,0,0,0)}return new X(c.left,c.top,c.right-c.left,c.b",
-    "ottom-c.top)}\nfunction Sb(a){var b=z(a,\"MAP\");if(!b&&!z(a,\"AREA\"))",
-    "return null;var c=b?a:z(a.parentNode,\"MAP\")?a.parentNode:null,d=null,",
-    "e=null;c&&c.name&&(d=W.pa('/descendant::*[@usemap = \"#'+c.name+'\"]',x",
-    "(c)))&&(e=Qb(d),b||\"default\"==a.shape.toLowerCase()||(a=Wb(a),b=Math.",
-    "min(Math.max(a.left,0),e.width),c=Math.min(Math.max(a.top,0),e.height),",
-    "e=new X(b+e.left,c+e.top,Math.min(a.width,e.width-b),Math.min(a.height,",
-    "e.height-c))));return{Z:d,rect:e||new X(0,0,0,0)}}\nfunction Wb(a){var ",
-    "b=a.shape.toLowerCase();a=a.coords.split(\",\");if(\"rect\"==b&&4==a.le",
-    "ngth){var b=a[0],c=a[1];return new X(b,c,a[2]-b,a[3]-c)}if(\"circle\"==",
-    "b&&3==a.length)return b=a[2],new X(a[0]-b,a[1]-b,2*b,2*b);if(\"poly\"==",
-    "b&&2<a.length){for(var b=a[0],c=a[1],d=b,e=c,f=2;f+1<a.length;f+=2)b=Ma",
-    "th.min(b,a[f]),d=Math.max(d,a[f]),c=Math.min(c,a[f+1]),e=Math.max(e,a[f",
-    "+1]);return new X(b,c,d-b,e-c)}return new X(0,0,0,0)}function Vb(a){a=Q",
-    "b(a);return new Lb(a.top,a.left+a.width,a.top+a.height,a.left)}\nfuncti",
-    "on Tb(a){var b=1,c=Y(a,\"opacity\");c&&(b=Number(c));(a=Nb(a))&&(b*=Tb(",
-    "a));return b};var Xb=\"function\"===typeof ShadowRoot;function Yb(a,b,c",
-    "){if(!Ub(a,c))return!1;if(Xb){for(;a.parentNode;)a=a.parentNode;if(a in",
-    "stanceof ShadowRoot)return Yb(a.host,b)}return!0};ba(\"_\",Yb);; return",
-    " this._.apply(null,arguments);}.apply({navigator:typeof window!='undefi",
-    "ned'?window.navigator:null,document:typeof window!='undefined'?window.d",
-    "ocument:null}, arguments);}",
+    "rn!1;a:{var b=a.parentNode;if(a.getDestinationInsertionPoints){var d=a.",
+    "getDestinationInsertionPoints();if(0<d.length){a=d[d.length-1];break a}",
+    "}a=b&&b.shadowRoot&&void 0!==a.assignedSlot?a.assignedSlot?a.assignedSl",
+    "ot.parentNode:null:b}return Mb&&a instanceof ShadowRoot||a&&(9==a.nodeT",
+    "ype||11==a.nodeType)?!0:!!a&&c(a)}return Pb(a,!!b,c)}var Z=\"hidden\";",
+    "\nfunction Rb(a){function b(a){function b(a){return a==g?!0:0==Y(a,\"di",
+    "splay\").lastIndexOf(\"inline\",0)||\"absolute\"==c&&\"static\"==Y(a,\"",
+    "position\")?!1:!0}var c=Y(a,\"position\");if(\"fixed\"==c)return D=!0,a",
+    "==g?null:g;for(a=Nb(a);a&&!b(a);)a=Nb(a);return a}function c(a){var b=a",
+    ";if(\"visible\"==w)if(a==g&&l)b=l;else if(a==l)return{x:\"visible\",y:",
+    "\"visible\"};b={x:Y(b,\"overflow-x\"),y:Y(b,\"overflow-y\")};a==g&&(b.x",
+    "=\"visible\"==b.x?\"auto\":b.x,b.y=\"visible\"==b.y?\"auto\":b.y);retur",
+    "n b}function d(a){if(a==g){var b=(new Ha(f)).H;\na=b.scrollingElement?b",
+    ".scrollingElement:b.body||b.documentElement;b=b.parentWindow||b.default",
+    "View;a=new v(b.pageXOffset||a.scrollLeft,b.pageYOffset||a.scrollTop)}el",
+    "se a=new v(a.scrollLeft,a.scrollTop);return a}var e=Vb(a);var f=x(a),g=",
+    "f.documentElement,l=f.body,w=Y(g,\"overflow\"),D;for(a=b(a);a;a=b(a)){v",
+    "ar q=c(a);if(\"visible\"!=q.x||\"visible\"!=q.y){var y=Qb(a);if(0==y.wi",
+    "dth||0==y.height)return Z;var H=e.right<y.left,S=e.bottom<y.top;if(H&&",
+    "\"hidden\"==q.x||S&&\"hidden\"==q.y)return Z;if(H&&\"visible\"!=q.x||\n",
+    "S&&\"visible\"!=q.y){H=d(a);S=e.bottom<y.top-H.y;if(e.right<y.left-H.x&",
+    "&\"visible\"!=q.x||S&&\"visible\"!=q.x)return Z;e=Rb(a);return e==Z?Z:",
+    "\"scroll\"}H=e.left>=y.left+y.width;y=e.top>=y.top+y.height;if(H&&\"hid",
+    "den\"==q.x||y&&\"hidden\"==q.y)return Z;if(H&&\"visible\"!=q.x||y&&\"vi",
+    "sible\"!=q.y){if(D&&(q=d(a),e.left>=g.scrollWidth-q.x||e.right>=g.scrol",
+    "lHeight-q.y))return Z;e=Rb(a);return e==Z?Z:\"scroll\"}}}return\"none\"",
+    "}\nfunction Qb(a){var b=Sb(a);if(b)return b.rect;if(z(a,\"HTML\"))retur",
+    "n a=x(a),a=((a?a.parentWindow||a.defaultView:window)||window).document,",
+    "a=\"CSS1Compat\"==a.compatMode?a.documentElement:a.body,a=new za(a.clie",
+    "ntWidth,a.clientHeight),new X(0,0,a.width,a.height);try{var c=a.getBoun",
+    "dingClientRect()}catch(d){return new X(0,0,0,0)}return new X(c.left,c.t",
+    "op,c.right-c.left,c.bottom-c.top)}\nfunction Sb(a){var b=z(a,\"MAP\");i",
+    "f(!b&&!z(a,\"AREA\"))return null;var c=b?a:z(a.parentNode,\"MAP\")?a.pa",
+    "rentNode:null,d=null,e=null;c&&c.name&&(d=W.pa('/descendant::*[@usemap ",
+    "= \"#'+c.name+'\"]',x(c)))&&(e=Qb(d),b||\"default\"==a.shape.toLowerCas",
+    "e()||(a=Wb(a),b=Math.min(Math.max(a.left,0),e.width),c=Math.min(Math.ma",
+    "x(a.top,0),e.height),e=new X(b+e.left,c+e.top,Math.min(a.width,e.width-",
+    "b),Math.min(a.height,e.height-c))));return{Z:d,rect:e||new X(0,0,0,0)}}",
+    "\nfunction Wb(a){var b=a.shape.toLowerCase();a=a.coords.split(\",\");if",
+    "(\"rect\"==b&&4==a.length){var b=a[0],c=a[1];return new X(b,c,a[2]-b,a[",
+    "3]-c)}if(\"circle\"==b&&3==a.length)return b=a[2],new X(a[0]-b,a[1]-b,2",
+    "*b,2*b);if(\"poly\"==b&&2<a.length){for(var b=a[0],c=a[1],d=b,e=c,f=2;f",
+    "+1<a.length;f+=2)b=Math.min(b,a[f]),d=Math.max(d,a[f]),c=Math.min(c,a[f",
+    "+1]),e=Math.max(e,a[f+1]);return new X(b,c,d-b,e-c)}return new X(0,0,0,",
+    "0)}function Vb(a){a=Qb(a);return new Lb(a.top,a.left+a.width,a.top+a.he",
+    "ight,a.left)}\nfunction Tb(a){var b=1,c=Y(a,\"opacity\");c&&(b=Number(c",
+    "));(a=Nb(a))&&(b*=Tb(a));return b};var Xb=\"function\"===typeof ShadowR",
+    "oot;function Yb(a,b,c){if(!Ub(a,c))return!1;if(Xb){for(;a.parentNode;)a",
+    "=a.parentNode;if(a instanceof ShadowRoot)return Yb(a.host,b)}return!0};",
+    "ba(\"_\",Yb);; return this._.apply(null,arguments);}.apply({navigator:t",
+    "ypeof window!='undefined'?window.navigator:null,document:typeof window!",
+    "='undefined'?window.document:null}, arguments);}",
     NULL
 };
 
@@ -8723,136 +8724,136 @@
     "type.toLowerCase()||y(a,\"NOSCRIPT\"))return!1;f=X(a,\"visibility\");re",
     "turn\"collapse\"!=f&&\"hidden\"!=f&&c(a)&&(b||0!=ic(a))&&d(a)?!e(a):!1}",
     "\nfunction jc(a){function b(a){if(y(a)&&\"none\"==X(a,\"display\"))retu",
-    "rn!1;var c;(c=a.parentNode)&&c.shadowRoot&&void 0!==a.assignedSlot?c=a.",
-    "assignedSlot?a.assignedSlot.parentNode:null:a.getDestinationInsertionPo",
-    "ints&&(a=a.getDestinationInsertionPoints(),0<a.length&&(c=a[a.length-1]",
-    "));return bc&&c instanceof ShadowRoot||c&&(9==c.nodeType||11==c.nodeTyp",
-    "e)?!0:!!c&&b(c)}return ec(a,!1,b)}var Y=\"hidden\";\nfunction gc(a){fun",
-    "ction b(a){function b(a){return a==h?!0:0==X(a,\"display\").lastIndexOf",
-    "(\"inline\",0)||\"absolute\"==c&&\"static\"==X(a,\"position\")?!1:!0}va",
-    "r c=X(a,\"position\");if(\"fixed\"==c)return C=!0,a==h?null:h;for(a=cc(",
-    "a);a&&!b(a);)a=cc(a);return a}function c(a){var b=a;if(\"visible\"==v)i",
-    "f(a==h&&m)b=m;else if(a==m)return{x:\"visible\",y:\"visible\"};b={x:X(b",
-    ",\"overflow-x\"),y:X(b,\"overflow-y\")};a==h&&(b.x=\"visible\"==b.x?\"a",
-    "uto\":b.x,b.y=\"visible\"==b.y?\"auto\":b.y);return b}function d(a){if(",
-    "a==h){var b=(new Wa(f)).M;\na=b.scrollingElement?b.scrollingElement:b.b",
-    "ody||b.documentElement;b=b.parentWindow||b.defaultView;a=new w(b.pageXO",
-    "ffset||a.scrollLeft,b.pageYOffset||a.scrollTop)}else a=new w(a.scrollLe",
-    "ft,a.scrollTop);return a}var e=kc(a);var f=x(a),h=f.documentElement,m=f",
-    ".body,v=X(h,\"overflow\"),C;for(a=b(a);a;a=b(a)){var t=c(a);if(\"visibl",
-    "e\"!=t.x||\"visible\"!=t.y){var A=fc(a);if(0==A.width||0==A.height)retu",
-    "rn Y;var L=e.right<A.left,T=e.bottom<A.top;if(L&&\"hidden\"==t.x||T&&\"",
-    "hidden\"==t.y)return Y;if(L&&\"visible\"!=t.x||\nT&&\"visible\"!=t.y){L",
-    "=d(a);T=e.bottom<A.top-L.y;if(e.right<A.left-L.x&&\"visible\"!=t.x||T&&",
-    "\"visible\"!=t.x)return Y;e=gc(a);return e==Y?Y:\"scroll\"}L=e.left>=A.",
-    "left+A.width;A=e.top>=A.top+A.height;if(L&&\"hidden\"==t.x||A&&\"hidden",
-    "\"==t.y)return Y;if(L&&\"visible\"!=t.x||A&&\"visible\"!=t.y){if(C&&(t=",
-    "d(a),e.left>=h.scrollWidth-t.x||e.right>=h.scrollHeight-t.y))return Y;e",
-    "=gc(a);return e==Y?Y:\"scroll\"}}}return\"none\"}\nfunction fc(a){var b",
-    "=hc(a);if(b)return b.rect;if(y(a,\"HTML\"))return a=x(a),a=((a?a.parent",
-    "Window||a.defaultView:window)||window).document,a=\"CSS1Compat\"==a.com",
-    "patMode?a.documentElement:a.body,a=new Na(a.clientWidth,a.clientHeight)",
-    ",new W(0,0,a.width,a.height);try{var c=a.getBoundingClientRect()}catch(",
-    "d){return new W(0,0,0,0)}return new W(c.left,c.top,c.right-c.left,c.bot",
-    "tom-c.top)}\nfunction hc(a){var b=y(a,\"MAP\");if(!b&&!y(a,\"AREA\"))re",
-    "turn null;var c=b?a:y(a.parentNode,\"MAP\")?a.parentNode:null,d=null,e=",
-    "null;c&&c.name&&(d=V.ua('/descendant::*[@usemap = \"#'+c.name+'\"]',x(c",
-    ")))&&(e=fc(d),b||\"default\"==a.shape.toLowerCase()||(a=lc(a),b=Math.mi",
-    "n(Math.max(a.left,0),e.width),c=Math.min(Math.max(a.top,0),e.height),e=",
-    "new W(b+e.left,c+e.top,Math.min(a.width,e.width-b),Math.min(a.height,e.",
-    "height-c))));return{da:d,rect:e||new W(0,0,0,0)}}\nfunction lc(a){var b",
-    "=a.shape.toLowerCase();a=a.coords.split(\",\");if(\"rect\"==b&&4==a.len",
-    "gth){var b=a[0],c=a[1];return new W(b,c,a[2]-b,a[3]-c)}if(\"circle\"==b",
-    "&&3==a.length)return b=a[2],new W(a[0]-b,a[1]-b,2*b,2*b);if(\"poly\"==b",
-    "&&2<a.length){for(var b=a[0],c=a[1],d=b,e=c,f=2;f+1<a.length;f+=2)b=Mat",
-    "h.min(b,a[f]),d=Math.max(d,a[f]),c=Math.min(c,a[f+1]),e=Math.max(e,a[f+",
-    "1]);return new W(b,c,d-b,e-c)}return new W(0,0,0,0)}function kc(a){a=fc",
-    "(a);return new ac(a.top,a.left+a.width,a.top+a.height,a.left)}\nfunctio",
-    "n mc(a){return a.replace(/^[^\\S\\xa0]+|[^\\S\\xa0]+$/g,\"\")}\nfunctio",
-    "n nc(a,b,c){if(y(a,\"BR\"))b.push(\"\");else{var d=y(a,\"TD\"),e=X(a,\"",
-    "display\"),f=!d&&!(0<=na(oc,e)),h=k(a.previousElementSibling)?a.previou",
-    "sElementSibling:Qa(a.previousSibling),h=h?X(h,\"display\"):\"\",m=X(a,",
-    "\"float\")||X(a,\"cssFloat\")||X(a,\"styleFloat\");!f||\"run-in\"==h&&",
-    "\"none\"==m||/^[\\s\\xa0]*$/.test(b[b.length-1]||\"\")||b.push(\"\");va",
-    "r v=jc(a),C=null,t=null;v&&(C=X(a,\"white-space\"),t=X(a,\"text-transfo",
-    "rm\"));q(a.childNodes,function(a){c(a,b,v,C,t)});a=b[b.length-1]||\"\";",
-    "!d&&\"table-cell\"!=e||!a||ja(a)||(b[b.length-\n1]+=\" \");f&&\"run-in",
-    "\"!=e&&!/^[\\s\\xa0]*$/.test(a)&&b.push(\"\")}}function pc(a,b){nc(a,b,",
-    "function(a,b,e,f,h){3==a.nodeType&&e?qc(a,b,f,h):y(a)&&pc(a,b)})}var oc",
-    "=\"inline inline-block inline-table none table-cell table-column table-",
-    "column-group\".split(\" \");\nfunction qc(a,b,c,d){a=a.nodeValue.replac",
-    "e(/[\\u200b\\u200e\\u200f]/g,\"\");a=a.replace(/(\\r\\n|\\r|\\n)/g,\"",
-    "\\n\");if(\"normal\"==c||\"nowrap\"==c)a=a.replace(/\\n/g,\" \");a=\"pr",
-    "e\"==c||\"pre-wrap\"==c?a.replace(/[ \\f\\t\\v\\u2028\\u2029]/g,\"\\u00",
-    "a0\"):a.replace(/[\\ \\f\\t\\v\\u2028\\u2029]+/g,\" \");\"capitalize\"=",
-    "=d?a=a.replace(/(^|\\s)(\\S)/g,function(a,b,c){return b+c.toUpperCase()",
-    "}):\"uppercase\"==d?a=a.toUpperCase():\"lowercase\"==d&&(a=a.toLowerCas",
-    "e());c=b.pop()||\"\";ja(c)&&0==a.lastIndexOf(\" \",0)&&(a=a.substr(1));",
-    "b.push(c+a)}\nfunction ic(a){var b=1,c=X(a,\"opacity\");c&&(b=Number(c)",
-    ");(a=cc(a))&&(b*=ic(a));return b}\nfunction rc(a,b,c,d,e){var f;if(3==a",
-    ".nodeType&&c)qc(a,b,d,e);else if(y(a))if(y(a,\"CONTENT\")||y(a,\"SLOT\"",
-    ")){for(f=a;f.parentNode;)f=f.parentNode;f instanceof ShadowRoot?(a=y(a,",
-    "\"CONTENT\")?a.getDistributedNodes():a.assignedNodes(),q(a,function(a){",
-    "rc(a,b,c,d,e)})):sc(a,b)}else if(y(a,\"SHADOW\")){for(f=a;f.parentNode;",
-    ")f=f.parentNode;if(f instanceof ShadowRoot&&(a=f))for(a=a.olderShadowRo",
-    "ot;a;)q(a.childNodes,function(a){rc(a,b,c,d,e)}),a=a.olderShadowRoot}el",
-    "se sc(a,b)}\nfunction sc(a,b){a.shadowRoot&&q(a.shadowRoot.childNodes,f",
-    "unction(a){rc(a,b,!0,null,null)});nc(a,b,function(a,b,e,f,h){var c=null",
-    ";1==a.nodeType?c=a:3==a.nodeType&&(c=a);null!=c&&(null!=c.assignedSlot|",
-    "|c.getDestinationInsertionPoints&&0<c.getDestinationInsertionPoints().l",
-    "ength)||rc(a,b,e,f,h)})};Ma();Ma();function tc(a,b){this.w={};this.g=[]",
-    ";this.F=0;var c=arguments.length;if(1<c){if(c%2)throw Error(\"Uneven nu",
-    "mber of arguments\");for(var d=0;d<c;d+=2)this.set(arguments[d],argumen",
-    "ts[d+1])}else a&&this.addAll(a)}function uc(a){vc(a);return a.g.concat(",
-    ")}g=tc.prototype;g.clear=function(){this.w={};this.F=this.g.length=0};g",
-    ".remove=function(a){return Object.prototype.hasOwnProperty.call(this.w,",
-    "a)?(delete this.w[a],this.F--,this.g.length>2*this.F&&vc(this),!0):!1};",
-    "\nfunction vc(a){var b,c;if(a.F!=a.g.length){for(b=c=0;c<a.g.length;){v",
-    "ar d=a.g[c];Object.prototype.hasOwnProperty.call(a.w,d)&&(a.g[b++]=d);c",
-    "++}a.g.length=b}if(a.F!=a.g.length){var e={};for(b=c=0;c<a.g.length;)d=",
-    "a.g[c],Object.prototype.hasOwnProperty.call(e,d)||(a.g[b++]=d,e[d]=1),c",
-    "++;a.g.length=b}}g.get=function(a,b){return Object.prototype.hasOwnProp",
-    "erty.call(this.w,a)?this.w[a]:b};g.set=function(a,b){Object.prototype.h",
-    "asOwnProperty.call(this.w,a)||(this.F++,this.g.push(a));this.w[a]=b};\n",
-    "g.addAll=function(a){if(a instanceof tc){var b=uc(a);vc(a);for(var c=[]",
-    ",d=0;d<a.g.length;d++)c.push(a.w[a.g[d]]);a=c}else{b=[];var d=0;for(e i",
-    "n a)b[d++]=e;d=[];var e=0;for(c in a)d[e++]=a[c];a=d}for(c=0;c<b.length",
-    ";c++)this.set(b[c],a[c])};g.forEach=function(a,b){for(var c=uc(this),d=",
-    "0;d<c.length;d++){var e=c[d],f=this.get(e);a.call(b,f,e,this)}};g.clone",
-    "=function(){return new tc(this)};var wc={};function Z(a,b,c){ea(a)&&(a=",
-    "a.b);a=new xc(a);!b||b in wc&&!c||(wc[b]={key:a,shift:!1},c&&(wc[c]={ke",
-    "y:a,shift:!0}));return a}function xc(a){this.code=a}Z(8);Z(9);Z(13);var",
-    " yc=Z(16),zc=Z(17),Ac=Z(18);Z(19);Z(20);Z(27);Z(32,\" \");Z(33);Z(34);Z",
-    "(35);Z(36);Z(37);Z(38);Z(39);Z(40);Z(44);Z(45);Z(46);Z(48,\"0\",\")\");",
-    "Z(49,\"1\",\"!\");Z(50,\"2\",\"@\");Z(51,\"3\",\"#\");Z(52,\"4\",\"$\")",
-    ";Z(53,\"5\",\"%\");Z(54,\"6\",\"^\");Z(55,\"7\",\"&\");Z(56,\"8\",\"*\"",
-    ");Z(57,\"9\",\"(\");Z(65,\"a\",\"A\");Z(66,\"b\",\"B\");Z(67,\"c\",\"C",
-    "\");Z(68,\"d\",\"D\");\nZ(69,\"e\",\"E\");Z(70,\"f\",\"F\");Z(71,\"g\",",
-    "\"G\");Z(72,\"h\",\"H\");Z(73,\"i\",\"I\");Z(74,\"j\",\"J\");Z(75,\"k\"",
-    ",\"K\");Z(76,\"l\",\"L\");Z(77,\"m\",\"M\");Z(78,\"n\",\"N\");Z(79,\"o",
-    "\",\"O\");Z(80,\"p\",\"P\");Z(81,\"q\",\"Q\");Z(82,\"r\",\"R\");Z(83,\"",
-    "s\",\"S\");Z(84,\"t\",\"T\");Z(85,\"u\",\"U\");Z(86,\"v\",\"V\");Z(87,",
-    "\"w\",\"W\");Z(88,\"x\",\"X\");Z(89,\"y\",\"Y\");Z(90,\"z\",\"Z\");var ",
-    "Bc=Z(Ia?{c:91,b:91}:Ha?{c:224,b:91}:{c:0,b:91});Z(Ia?{c:92,b:92}:Ha?{c:",
-    "224,b:93}:{c:0,b:92});Z(Ia?{c:93,b:93}:Ha?{c:0,b:0}:{c:93,b:null});Z({c",
-    ":96,b:96},\"0\");Z({c:97,b:97},\"1\");\nZ({c:98,b:98},\"2\");Z({c:99,b:",
-    "99},\"3\");Z({c:100,b:100},\"4\");Z({c:101,b:101},\"5\");Z({c:102,b:102",
-    "},\"6\");Z({c:103,b:103},\"7\");Z({c:104,b:104},\"8\");Z({c:105,b:105},",
-    "\"9\");Z({c:106,b:106},\"*\");Z({c:107,b:107},\"+\");Z({c:109,b:109},\"",
-    "-\");Z({c:110,b:110},\".\");Z({c:111,b:111},\"/\");Z(144);Z(112);Z(113)",
-    ";Z(114);Z(115);Z(116);Z(117);Z(118);Z(119);Z(120);Z(121);Z(122);Z(123);",
-    "Z({c:107,b:187},\"=\",\"+\");Z(108,\",\");Z({c:109,b:189},\"-\",\"_\");",
-    "Z(188,\",\",\"<\");Z(190,\".\",\">\");Z(191,\"/\",\"?\");Z(192,\"`\",\"",
-    "~\");Z(219,\"[\",\"{\");\nZ(220,\"\\\\\",\"|\");Z(221,\"]\",\"}\");Z({c",
-    ":59,b:186},\";\",\":\");Z(222,\"'\",'\"');var Cc=new tc;Cc.set(1,yc);Cc",
-    ".set(2,zc);Cc.set(4,Ac);Cc.set(8,Bc);(function(a){var b=new tc;q(uc(a),",
-    "function(c){b.set(a.get(c).code,c)});return b})(Cc);ba(\"_\",function(a",
-    "){var b=[];bc?sc(a,b):pc(a,b);var c=b;a=c.length;for(var b=Array(a),c=l",
-    "(c)?c.split(\"\"):c,d=0;d<a;d++)d in c&&(b[d]=mc.call(void 0,c[d]));ret",
-    "urn mc(b.join(\"\\n\")).replace(/\\xa0/g,\" \")});; return this._.apply",
-    "(null,arguments);}.apply({navigator:typeof window!='undefined'?window.n",
-    "avigator:null,document:typeof window!='undefined'?window.document:null}",
-    ", arguments);}",
+    "rn!1;a:{var c=a.parentNode;if(a.getDestinationInsertionPoints){var e=a.",
+    "getDestinationInsertionPoints();if(0<e.length){a=e[e.length-1];break a}",
+    "}a=c&&c.shadowRoot&&void 0!==a.assignedSlot?a.assignedSlot?a.assignedSl",
+    "ot.parentNode:null:c}return bc&&a instanceof ShadowRoot||a&&(9==a.nodeT",
+    "ype||11==a.nodeType)?!0:!!a&&b(a)}return ec(a,!1,b)}var Y=\"hidden\";\n",
+    "function gc(a){function b(a){function b(a){return a==h?!0:0==X(a,\"disp",
+    "lay\").lastIndexOf(\"inline\",0)||\"absolute\"==c&&\"static\"==X(a,\"po",
+    "sition\")?!1:!0}var c=X(a,\"position\");if(\"fixed\"==c)return C=!0,a==",
+    "h?null:h;for(a=cc(a);a&&!b(a);)a=cc(a);return a}function c(a){var b=a;i",
+    "f(\"visible\"==v)if(a==h&&m)b=m;else if(a==m)return{x:\"visible\",y:\"v",
+    "isible\"};b={x:X(b,\"overflow-x\"),y:X(b,\"overflow-y\")};a==h&&(b.x=\"",
+    "visible\"==b.x?\"auto\":b.x,b.y=\"visible\"==b.y?\"auto\":b.y);return b",
+    "}function d(a){if(a==h){var b=(new Wa(f)).M;\na=b.scrollingElement?b.sc",
+    "rollingElement:b.body||b.documentElement;b=b.parentWindow||b.defaultVie",
+    "w;a=new w(b.pageXOffset||a.scrollLeft,b.pageYOffset||a.scrollTop)}else ",
+    "a=new w(a.scrollLeft,a.scrollTop);return a}var e=kc(a);var f=x(a),h=f.d",
+    "ocumentElement,m=f.body,v=X(h,\"overflow\"),C;for(a=b(a);a;a=b(a)){var ",
+    "t=c(a);if(\"visible\"!=t.x||\"visible\"!=t.y){var A=fc(a);if(0==A.width",
+    "||0==A.height)return Y;var L=e.right<A.left,T=e.bottom<A.top;if(L&&\"hi",
+    "dden\"==t.x||T&&\"hidden\"==t.y)return Y;if(L&&\"visible\"!=t.x||\nT&&",
+    "\"visible\"!=t.y){L=d(a);T=e.bottom<A.top-L.y;if(e.right<A.left-L.x&&\"",
+    "visible\"!=t.x||T&&\"visible\"!=t.x)return Y;e=gc(a);return e==Y?Y:\"sc",
+    "roll\"}L=e.left>=A.left+A.width;A=e.top>=A.top+A.height;if(L&&\"hidden",
+    "\"==t.x||A&&\"hidden\"==t.y)return Y;if(L&&\"visible\"!=t.x||A&&\"visib",
+    "le\"!=t.y){if(C&&(t=d(a),e.left>=h.scrollWidth-t.x||e.right>=h.scrollHe",
+    "ight-t.y))return Y;e=gc(a);return e==Y?Y:\"scroll\"}}}return\"none\"}\n",
+    "function fc(a){var b=hc(a);if(b)return b.rect;if(y(a,\"HTML\"))return a",
+    "=x(a),a=((a?a.parentWindow||a.defaultView:window)||window).document,a=",
+    "\"CSS1Compat\"==a.compatMode?a.documentElement:a.body,a=new Na(a.client",
+    "Width,a.clientHeight),new W(0,0,a.width,a.height);try{var c=a.getBoundi",
+    "ngClientRect()}catch(d){return new W(0,0,0,0)}return new W(c.left,c.top",
+    ",c.right-c.left,c.bottom-c.top)}\nfunction hc(a){var b=y(a,\"MAP\");if(",
+    "!b&&!y(a,\"AREA\"))return null;var c=b?a:y(a.parentNode,\"MAP\")?a.pare",
+    "ntNode:null,d=null,e=null;c&&c.name&&(d=V.ua('/descendant::*[@usemap = ",
+    "\"#'+c.name+'\"]',x(c)))&&(e=fc(d),b||\"default\"==a.shape.toLowerCase(",
+    ")||(a=lc(a),b=Math.min(Math.max(a.left,0),e.width),c=Math.min(Math.max(",
+    "a.top,0),e.height),e=new W(b+e.left,c+e.top,Math.min(a.width,e.width-b)",
+    ",Math.min(a.height,e.height-c))));return{da:d,rect:e||new W(0,0,0,0)}}",
+    "\nfunction lc(a){var b=a.shape.toLowerCase();a=a.coords.split(\",\");if",
+    "(\"rect\"==b&&4==a.length){var b=a[0],c=a[1];return new W(b,c,a[2]-b,a[",
+    "3]-c)}if(\"circle\"==b&&3==a.length)return b=a[2],new W(a[0]-b,a[1]-b,2",
+    "*b,2*b);if(\"poly\"==b&&2<a.length){for(var b=a[0],c=a[1],d=b,e=c,f=2;f",
+    "+1<a.length;f+=2)b=Math.min(b,a[f]),d=Math.max(d,a[f]),c=Math.min(c,a[f",
+    "+1]),e=Math.max(e,a[f+1]);return new W(b,c,d-b,e-c)}return new W(0,0,0,",
+    "0)}function kc(a){a=fc(a);return new ac(a.top,a.left+a.width,a.top+a.he",
+    "ight,a.left)}\nfunction mc(a){return a.replace(/^[^\\S\\xa0]+|[^\\S\\xa",
+    "0]+$/g,\"\")}\nfunction nc(a,b,c){if(y(a,\"BR\"))b.push(\"\");else{var ",
+    "d=y(a,\"TD\"),e=X(a,\"display\"),f=!d&&!(0<=na(oc,e)),h=k(a.previousEle",
+    "mentSibling)?a.previousElementSibling:Qa(a.previousSibling),h=h?X(h,\"d",
+    "isplay\"):\"\",m=X(a,\"float\")||X(a,\"cssFloat\")||X(a,\"styleFloat\")",
+    ";!f||\"run-in\"==h&&\"none\"==m||/^[\\s\\xa0]*$/.test(b[b.length-1]||\"",
+    "\")||b.push(\"\");var v=jc(a),C=null,t=null;v&&(C=X(a,\"white-space\"),",
+    "t=X(a,\"text-transform\"));q(a.childNodes,function(a){c(a,b,v,C,t)});a=",
+    "b[b.length-1]||\"\";!d&&\"table-cell\"!=e||!a||ja(a)||(b[b.length-\n1]+",
+    "=\" \");f&&\"run-in\"!=e&&!/^[\\s\\xa0]*$/.test(a)&&b.push(\"\")}}funct",
+    "ion pc(a,b){nc(a,b,function(a,b,e,f,h){3==a.nodeType&&e?qc(a,b,f,h):y(a",
+    ")&&pc(a,b)})}var oc=\"inline inline-block inline-table none table-cell ",
+    "table-column table-column-group\".split(\" \");\nfunction qc(a,b,c,d){a",
+    "=a.nodeValue.replace(/[\\u200b\\u200e\\u200f]/g,\"\");a=a.replace(/(\\r",
+    "\\n|\\r|\\n)/g,\"\\n\");if(\"normal\"==c||\"nowrap\"==c)a=a.replace(/",
+    "\\n/g,\" \");a=\"pre\"==c||\"pre-wrap\"==c?a.replace(/[ \\f\\t\\v\\u202",
+    "8\\u2029]/g,\"\\u00a0\"):a.replace(/[\\ \\f\\t\\v\\u2028\\u2029]+/g,\" ",
+    "\");\"capitalize\"==d?a=a.replace(/(^|\\s)(\\S)/g,function(a,b,c){retur",
+    "n b+c.toUpperCase()}):\"uppercase\"==d?a=a.toUpperCase():\"lowercase\"=",
+    "=d&&(a=a.toLowerCase());c=b.pop()||\"\";ja(c)&&0==a.lastIndexOf(\" \",0",
+    ")&&(a=a.substr(1));b.push(c+a)}\nfunction ic(a){var b=1,c=X(a,\"opacity",
+    "\");c&&(b=Number(c));(a=cc(a))&&(b*=ic(a));return b}\nfunction rc(a,b,c",
+    ",d,e){var f;if(3==a.nodeType&&c)qc(a,b,d,e);else if(y(a))if(y(a,\"CONTE",
+    "NT\")||y(a,\"SLOT\")){for(f=a;f.parentNode;)f=f.parentNode;f instanceof",
+    " ShadowRoot?(a=y(a,\"CONTENT\")?a.getDistributedNodes():a.assignedNodes",
+    "(),q(a,function(a){rc(a,b,c,d,e)})):sc(a,b)}else if(y(a,\"SHADOW\")){fo",
+    "r(f=a;f.parentNode;)f=f.parentNode;if(f instanceof ShadowRoot&&(a=f))fo",
+    "r(a=a.olderShadowRoot;a;)q(a.childNodes,function(a){rc(a,b,c,d,e)}),a=a",
+    ".olderShadowRoot}else sc(a,b)}\nfunction sc(a,b){a.shadowRoot&&q(a.shad",
+    "owRoot.childNodes,function(a){rc(a,b,!0,null,null)});nc(a,b,function(a,",
+    "b,e,f,h){var c=null;1==a.nodeType?c=a:3==a.nodeType&&(c=a);null!=c&&(nu",
+    "ll!=c.assignedSlot||c.getDestinationInsertionPoints&&0<c.getDestination",
+    "InsertionPoints().length)||rc(a,b,e,f,h)})};Ma();Ma();function tc(a,b){",
+    "this.w={};this.g=[];this.F=0;var c=arguments.length;if(1<c){if(c%2)thro",
+    "w Error(\"Uneven number of arguments\");for(var d=0;d<c;d+=2)this.set(a",
+    "rguments[d],arguments[d+1])}else a&&this.addAll(a)}function uc(a){vc(a)",
+    ";return a.g.concat()}g=tc.prototype;g.clear=function(){this.w={};this.F",
+    "=this.g.length=0};g.remove=function(a){return Object.prototype.hasOwnPr",
+    "operty.call(this.w,a)?(delete this.w[a],this.F--,this.g.length>2*this.F",
+    "&&vc(this),!0):!1};\nfunction vc(a){var b,c;if(a.F!=a.g.length){for(b=c",
+    "=0;c<a.g.length;){var d=a.g[c];Object.prototype.hasOwnProperty.call(a.w",
+    ",d)&&(a.g[b++]=d);c++}a.g.length=b}if(a.F!=a.g.length){var e={};for(b=c",
+    "=0;c<a.g.length;)d=a.g[c],Object.prototype.hasOwnProperty.call(e,d)||(a",
+    ".g[b++]=d,e[d]=1),c++;a.g.length=b}}g.get=function(a,b){return Object.p",
+    "rototype.hasOwnProperty.call(this.w,a)?this.w[a]:b};g.set=function(a,b)",
+    "{Object.prototype.hasOwnProperty.call(this.w,a)||(this.F++,this.g.push(",
+    "a));this.w[a]=b};\ng.addAll=function(a){if(a instanceof tc){var b=uc(a)",
+    ";vc(a);for(var c=[],d=0;d<a.g.length;d++)c.push(a.w[a.g[d]]);a=c}else{b",
+    "=[];var d=0;for(e in a)b[d++]=e;d=[];var e=0;for(c in a)d[e++]=a[c];a=d",
+    "}for(c=0;c<b.length;c++)this.set(b[c],a[c])};g.forEach=function(a,b){fo",
+    "r(var c=uc(this),d=0;d<c.length;d++){var e=c[d],f=this.get(e);a.call(b,",
+    "f,e,this)}};g.clone=function(){return new tc(this)};var wc={};function ",
+    "Z(a,b,c){ea(a)&&(a=a.b);a=new xc(a);!b||b in wc&&!c||(wc[b]={key:a,shif",
+    "t:!1},c&&(wc[c]={key:a,shift:!0}));return a}function xc(a){this.code=a}",
+    "Z(8);Z(9);Z(13);var yc=Z(16),zc=Z(17),Ac=Z(18);Z(19);Z(20);Z(27);Z(32,",
+    "\" \");Z(33);Z(34);Z(35);Z(36);Z(37);Z(38);Z(39);Z(40);Z(44);Z(45);Z(46",
+    ");Z(48,\"0\",\")\");Z(49,\"1\",\"!\");Z(50,\"2\",\"@\");Z(51,\"3\",\"#",
+    "\");Z(52,\"4\",\"$\");Z(53,\"5\",\"%\");Z(54,\"6\",\"^\");Z(55,\"7\",\"",
+    "&\");Z(56,\"8\",\"*\");Z(57,\"9\",\"(\");Z(65,\"a\",\"A\");Z(66,\"b\",",
+    "\"B\");Z(67,\"c\",\"C\");Z(68,\"d\",\"D\");\nZ(69,\"e\",\"E\");Z(70,\"f",
+    "\",\"F\");Z(71,\"g\",\"G\");Z(72,\"h\",\"H\");Z(73,\"i\",\"I\");Z(74,\"",
+    "j\",\"J\");Z(75,\"k\",\"K\");Z(76,\"l\",\"L\");Z(77,\"m\",\"M\");Z(78,",
+    "\"n\",\"N\");Z(79,\"o\",\"O\");Z(80,\"p\",\"P\");Z(81,\"q\",\"Q\");Z(82",
+    ",\"r\",\"R\");Z(83,\"s\",\"S\");Z(84,\"t\",\"T\");Z(85,\"u\",\"U\");Z(8",
+    "6,\"v\",\"V\");Z(87,\"w\",\"W\");Z(88,\"x\",\"X\");Z(89,\"y\",\"Y\");Z(",
+    "90,\"z\",\"Z\");var Bc=Z(Ia?{c:91,b:91}:Ha?{c:224,b:91}:{c:0,b:91});Z(I",
+    "a?{c:92,b:92}:Ha?{c:224,b:93}:{c:0,b:92});Z(Ia?{c:93,b:93}:Ha?{c:0,b:0}",
+    ":{c:93,b:null});Z({c:96,b:96},\"0\");Z({c:97,b:97},\"1\");\nZ({c:98,b:9",
+    "8},\"2\");Z({c:99,b:99},\"3\");Z({c:100,b:100},\"4\");Z({c:101,b:101},",
+    "\"5\");Z({c:102,b:102},\"6\");Z({c:103,b:103},\"7\");Z({c:104,b:104},\"",
+    "8\");Z({c:105,b:105},\"9\");Z({c:106,b:106},\"*\");Z({c:107,b:107},\"+",
+    "\");Z({c:109,b:109},\"-\");Z({c:110,b:110},\".\");Z({c:111,b:111},\"/\"",
+    ");Z(144);Z(112);Z(113);Z(114);Z(115);Z(116);Z(117);Z(118);Z(119);Z(120)",
+    ";Z(121);Z(122);Z(123);Z({c:107,b:187},\"=\",\"+\");Z(108,\",\");Z({c:10",
+    "9,b:189},\"-\",\"_\");Z(188,\",\",\"<\");Z(190,\".\",\">\");Z(191,\"/\"",
+    ",\"?\");Z(192,\"`\",\"~\");Z(219,\"[\",\"{\");\nZ(220,\"\\\\\",\"|\");Z",
+    "(221,\"]\",\"}\");Z({c:59,b:186},\";\",\":\");Z(222,\"'\",'\"');var Cc=",
+    "new tc;Cc.set(1,yc);Cc.set(2,zc);Cc.set(4,Ac);Cc.set(8,Bc);(function(a)",
+    "{var b=new tc;q(uc(a),function(c){b.set(a.get(c).code,c)});return b})(C",
+    "c);ba(\"_\",function(a){var b=[];bc?sc(a,b):pc(a,b);var c=b;a=c.length;",
+    "for(var b=Array(a),c=l(c)?c.split(\"\"):c,d=0;d<a;d++)d in c&&(b[d]=mc.",
+    "call(void 0,c[d]));return mc(b.join(\"\\n\")).replace(/\\xa0/g,\" \")})",
+    ";; return this._.apply(null,arguments);}.apply({navigator:typeof window",
+    "!='undefined'?window.navigator:null,document:typeof window!='undefined'",
+    "?window.document:null}, arguments);}",
     NULL
 };
 
diff --git a/third_party/webdriver/patch.diff b/third_party/webdriver/patch.diff
index 657f6253..90863e2 100644
--- a/third_party/webdriver/patch.diff
+++ b/third_party/webdriver/patch.diff
@@ -1,5 +1,5 @@
 diff --git a/javascript/atoms/dom.js b/javascript/atoms/dom.js
-index 78b78e1038..f1d0b424b0 100644
+index 9bd669a05d..569de66f58 100644
 --- a/javascript/atoms/dom.js
 +++ b/javascript/atoms/dom.js
 @@ -587,14 +587,8 @@ bot.dom.isShown = function(elem, opt_ignoreOpacity) {
@@ -28,6 +28,34 @@
    }
  
    return bot.dom.isShown_(elem, !!opt_ignoreOpacity, displayed);
+@@ -1262,13 +1256,6 @@ bot.dom.getOpacityNonIE_ = function(elem) {
+ bot.dom.getParentNodeInComposedDom = function(node) {
+   var /**@type {Node}*/ parent = node.parentNode;
+ 
+-  // Shadow DOM v1
+-  if (parent && parent.shadowRoot && node.assignedSlot !== undefined) {
+-    // Can be null on purpose, meaning it has no parent as
+-    // it hasn't yet been slotted
+-    return node.assignedSlot ? node.assignedSlot.parentNode : null;
+-  }
+-
+   // Shadow DOM V0 (deprecated)
+   if (node.getDestinationInsertionPoints) {
+     var destinations = node.getDestinationInsertionPoints();
+@@ -1277,6 +1264,13 @@ bot.dom.getParentNodeInComposedDom = function(node) {
+     }
+   }
+ 
++  // Shadow DOM v1
++  if (parent && parent.shadowRoot && node.assignedSlot !== undefined) {
++    // Can be null on purpose, meaning it has no parent as
++    // it hasn't yet been slotted
++    return node.assignedSlot ? node.assignedSlot.parentNode : null;
++  }
++
+   return parent;
+ };
+ 
 diff --git a/javascript/atoms/mouse.js b/javascript/atoms/mouse.js
 index 737ed50f62..1bc9e858f5 100644
 --- a/javascript/atoms/mouse.js
diff --git a/tools/android/OWNERS b/tools/android/OWNERS
index 49d9078..869a4d9 100644
--- a/tools/android/OWNERS
+++ b/tools/android/OWNERS
@@ -1,4 +1,6 @@
+agrieve@chromium.org
 digit@chromium.org
 jbudorick@chromium.org
 michaelbai@chromium.org
+wnwen@chromium.org
 yfriedman@chromium.org
diff --git a/tools/chrome_proxy/webdriver/bypass.py b/tools/chrome_proxy/webdriver/bypass.py
index 474ec72..4dcd245 100644
--- a/tools/chrome_proxy/webdriver/bypass.py
+++ b/tools/chrome_proxy/webdriver/bypass.py
@@ -6,6 +6,7 @@
 from common import TestDriver
 from common import IntegrationTest
 from decorators import ChromeVersionEqualOrAfterM
+from decorators import ChromeVersionBeforeM
 
 
 class Bypass(IntegrationTest):
@@ -147,6 +148,7 @@
   # Verify that when Chrome receives a 4xx response through a Data Reduction
   # Proxy that doesn't set a proper via header, Chrome bypasses all proxies and
   # retries the request over direct.
+  @ChromeVersionBeforeM(67)
   def testMissingViaHeader4xxBypass(self):
     with TestDriver() as test_driver:
       test_driver.AddChromeArg('--enable-spdy-proxy-auth')
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 4d5ef410..06b61d91 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -21740,6 +21740,26 @@
   </summary>
 </histogram>
 
+<histogram name="DirectWrite.Fonts.Proxy.LookupTableBuildTime" units="ms"
+    expires_after="M75">
+  <owner>drott@chromium.org</owner>
+  <summary>
+    Time it takes to build the font unique name lookup table. Recorded at the
+    initial build of this table, after which it is kept for the lifetime of the
+    browser process.
+  </summary>
+</histogram>
+
+<histogram name="DirectWrite.Fonts.Proxy.LookupTableSize" units="KB"
+    expires_after="M75">
+  <owner>drott@chromium.org</owner>
+  <summary>
+    Size of the font unique name lookup table in kilobytes. Recorded at the
+    initial build of this table, after which it is kept for the lifetime of the
+    browser process.
+  </summary>
+</histogram>
+
 <histogram name="DirectWrite.Fonts.Proxy.MessageFilterError"
     enum="DirectWriteMessageFilterError">
   <owner>kulshin@chromium.org</owner>
@@ -27531,6 +27551,18 @@
   </summary>
 </histogram>
 
+<histogram name="Event.DragDrop.AcceptDragUpdate" enum="Boolean">
+  <owner>dcheng@chromium.org</owner>
+  <owner>sadrul@chromium.org</owner>
+  <summary>
+    Reports whether chrome accepts or rejects a drag and drop operation.
+
+    During a drag and drop operation, there are many 'drag update' events that
+    happen for each mouse-move event. For each such drag-update event, chrome
+    reports whether it is able to accept the drop event or not.
+  </summary>
+</histogram>
+
 <histogram name="Event.DragDrop.Cancel" enum="DragDropEventSource">
   <owner>mfomitchev@chromium.org</owner>
   <summary>
@@ -70648,6 +70680,9 @@
 
 <histogram name="NQE.Accuracy.DownstreamThroughputKbps.EstimatedObservedDiff"
     units="kbps">
+  <obsolete>
+    Obsoleted in Jan 2019
+  </obsolete>
   <owner>tbansal@chromium.org</owner>
   <owner>bengr@chromium.org</owner>
   <summary>
@@ -70662,6 +70697,9 @@
 
 <histogram name="NQE.Accuracy.EffectiveConnectionType.EstimatedObservedDiff"
     units="Effective connection type">
+  <obsolete>
+    Obsoleted in Jan 2019
+  </obsolete>
   <owner>tbansal@chromium.org</owner>
   <owner>bengr@chromium.org</owner>
   <summary>
@@ -70674,6 +70712,9 @@
 </histogram>
 
 <histogram name="NQE.Accuracy.HttpRTT.EstimatedObservedDiff" units="ms">
+  <obsolete>
+    Obsoleted in Jan 2019
+  </obsolete>
   <owner>tbansal@chromium.org</owner>
   <owner>bengr@chromium.org</owner>
   <summary>
@@ -70685,6 +70726,9 @@
 </histogram>
 
 <histogram name="NQE.Accuracy.TransportRTT.EstimatedObservedDiff" units="ms">
+  <obsolete>
+    Obsoleted in Jan 2019
+  </obsolete>
   <owner>tbansal@chromium.org</owner>
   <owner>bengr@chromium.org</owner>
   <summary>
@@ -87530,6 +87574,9 @@
 
 <histogram name="Previews.Triggered.EffectiveConnectionType"
     enum="NQEEffectiveConnectionType">
+  <obsolete>
+    Replaced by Previews.Triggered.EffectiveConnectionType2 as of 01/2019.
+  </obsolete>
   <owner>dougarnett@chromium.org</owner>
   <summary>
     Records the effective connection type of a navigation that triggers a
@@ -87539,6 +87586,16 @@
   </summary>
 </histogram>
 
+<histogram name="Previews.Triggered.EffectiveConnectionType2"
+    enum="NQEEffectiveConnectionType">
+  <owner>dougarnett@chromium.org</owner>
+  <summary>
+    Records the effective connection type of a navigation that triggers a
+    preview. This is captured at commit time but uses the effective connection
+    type from the beginning of the navigation.
+  </summary>
+</histogram>
+
 <histogram name="PrinterService.PrinterServiceEvent"
     enum="PrinterServiceEventType">
   <owner>vitalybuka@chromium.org</owner>
@@ -94355,6 +94412,9 @@
 </histogram>
 
 <histogram name="SafeBrowsing.V4GetPrefixMatches.TimeUs" units="microseconds">
+  <obsolete>
+    Deprecated 01/2019 due to lack of use (Histogram Eraser).
+  </obsolete>
   <owner>csharrison@chromium.org</owner>
   <owner>vakh@chromium.org</owner>
   <summary>
@@ -138628,6 +138688,7 @@
   <affected-histogram name="Previews.OptOut.UserOptedOut"/>
   <affected-histogram name="Previews.PageEndReason"/>
   <affected-histogram name="Previews.Triggered.EffectiveConnectionType"/>
+  <affected-histogram name="Previews.Triggered.EffectiveConnectionType2"/>
 </histogram_suffixes>
 
 <histogram_suffixes name="ProcessMemoryAllocator2" separator=".">
diff --git a/ui/message_center/views/notification_view_md.cc b/ui/message_center/views/notification_view_md.cc
index a886af71..9f186c4 100644
--- a/ui/message_center/views/notification_view_md.cc
+++ b/ui/message_center/views/notification_view_md.cc
@@ -17,6 +17,7 @@
 #include "ui/events/gesture_detection/gesture_provider_config_helper.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/color_palette.h"
+#include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/image/image_skia_operations.h"
 #include "ui/gfx/paint_vector_icon.h"
@@ -37,6 +38,7 @@
 #include "ui/strings/grit/ui_strings.h"
 #include "ui/views/animation/flood_fill_ink_drop_ripple.h"
 #include "ui/views/animation/ink_drop_highlight.h"
+#include "ui/views/animation/ink_drop_mask.h"
 #include "ui/views/background.h"
 #include "ui/views/border.h"
 #include "ui/views/controls/button/image_button.h"
@@ -605,6 +607,13 @@
   }
 }
 
+void NotificationViewMD::OnBoundsChanged(const gfx::Rect& previous_bounds) {
+  if (ink_drop_layer_)
+    ink_drop_layer_->SetBounds(gfx::Rect(size()));
+  if (ink_drop_mask_)
+    ink_drop_mask_->layer()->SetBounds(gfx::Rect(size()));
+}
+
 void NotificationViewMD::OnFocus() {
   MessageView::OnFocus();
   ScrollRectToVisible(GetLocalBounds());
@@ -1239,6 +1248,8 @@
   action_buttons_row_->SetBackground(views::CreateBackgroundFromPainter(
       std::make_unique<NotificationBackgroundPainter>(
           0, bottom_radius, kActionsRowBackgroundColor)));
+  top_radius_ = top_radius;
+  bottom_radius_ = bottom_radius;
 }
 
 NotificationControlButtonsView* NotificationViewMD::GetControlButtonsView()
@@ -1306,6 +1317,7 @@
 }
 
 void NotificationViewMD::RemoveBackgroundAnimation() {
+  SetInkDropMode(InkDropMode::OFF);
   AnimateInkDrop(views::InkDropState::HIDDEN, nullptr);
 }
 
@@ -1320,7 +1332,8 @@
   settings_done_button_->SetPaintToLayer();
   settings_done_button_->layer()->SetFillsBoundsOpaquely(false);
   ink_drop_container_->AddInkDropLayer(ink_drop_layer);
-  InstallInkDropMask(ink_drop_layer);
+  ink_drop_layer_ = ink_drop_layer;
+  InstallNotificationInkDropMask();
 }
 
 void NotificationViewMD::RemoveInkDropLayer(ui::Layer* ink_drop_layer) {
@@ -1328,18 +1341,38 @@
   block_all_button_->DestroyLayer();
   dont_block_button_->DestroyLayer();
   settings_done_button_->DestroyLayer();
-  ResetInkDropMask();
+  ink_drop_mask_.reset();
   ink_drop_container_->RemoveInkDropLayer(ink_drop_layer);
   GetInkDrop()->RemoveObserver(this);
+  ink_drop_layer_ = nullptr;
 }
 
 std::unique_ptr<views::InkDropRipple> NotificationViewMD::CreateInkDropRipple()
     const {
   return std::make_unique<views::FloodFillInkDropRipple>(
-      ink_drop_container_->size(), GetInkDropCenterBasedOnLastEvent(),
+      GetPreferredSize(), GetInkDropCenterBasedOnLastEvent(),
       GetInkDropBaseColor(), ink_drop_visible_opacity());
 }
 
+void NotificationViewMD::InstallNotificationInkDropMask() {
+  SkPath path;
+  SkScalar radii[8] = {top_radius_,    top_radius_,    top_radius_,
+                       top_radius_,    bottom_radius_, bottom_radius_,
+                       bottom_radius_, bottom_radius_};
+  gfx::Rect rect(GetPreferredSize());
+  path.addRoundRect(gfx::RectToSkRect(rect), radii);
+  ink_drop_mask_ = std::make_unique<views::PathInkDropMask>(size(), path);
+  ink_drop_layer_->SetMaskLayer(ink_drop_mask_->layer());
+}
+
+std::unique_ptr<views::InkDropMask> NotificationViewMD::CreateInkDropMask()
+    const {
+  // We don't use this as we need access to the |ink_drop_mask_|.
+  // See crbug.com/915222.
+  NOTREACHED();
+  return nullptr;
+}
+
 SkColor NotificationViewMD::GetInkDropBaseColor() const {
   // Background of inline settings area.
   return SkColorSetRGB(0xEE, 0xEE, 0xEE);
diff --git a/ui/message_center/views/notification_view_md.h b/ui/message_center/views/notification_view_md.h
index 84671e19..be4d065 100644
--- a/ui/message_center/views/notification_view_md.h
+++ b/ui/message_center/views/notification_view_md.h
@@ -173,6 +173,7 @@
 
   // Overridden from views::View:
   void Layout() override;
+  void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
   void OnFocus() override;
   bool OnMousePressed(const ui::MouseEvent& event) override;
   bool OnMouseDragged(const ui::MouseEvent& event) override;
@@ -184,6 +185,7 @@
   void AddInkDropLayer(ui::Layer* ink_drop_layer) override;
   void RemoveInkDropLayer(ui::Layer* ink_drop_layer) override;
   std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override;
+  std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override;
   SkColor GetInkDropBaseColor() const override;
 
   // Overridden from MessageView:
@@ -248,6 +250,9 @@
   void UpdateViewForExpandedState(bool expanded);
   void ToggleInlineSettings(const ui::Event& event);
 
+  // Initializes |ink_drop_mask_| and sets the mask on |ink_drop_layer_|.
+  void InstallNotificationInkDropMask();
+
   views::InkDropContainerView* const ink_drop_container_;
 
   // View containing close and settings buttons
@@ -269,6 +274,15 @@
   // Describes whether the view should display a hand pointer or not.
   bool clickable_;
 
+  // Corner radii for the InkDropMask.
+  int top_radius_ = 0;
+  int bottom_radius_ = 0;
+
+  // The InkDrop layer and InkDropMask used to update their bounds on
+  // OnBoundsChanged(). See crbug.com/915222.
+  ui::Layer* ink_drop_layer_ = nullptr;
+  std::unique_ptr<views::InkDropMask> ink_drop_mask_;
+
   // Container views directly attached to this view.
   NotificationHeaderView* header_row_ = nullptr;
   views::View* content_row_ = nullptr;
diff --git a/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc b/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc
index f0da4f8..e562b63 100644
--- a/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc
+++ b/ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.cc
@@ -1168,6 +1168,8 @@
   DragTranslate(screen_point, &data, &drop_target_event, &delegate);
   if (delegate)
     drag_operation = delegate->OnDragUpdated(*drop_target_event);
+  UMA_HISTOGRAM_BOOLEAN("Event.DragDrop.AcceptDragUpdate",
+                        drag_operation != ui::DragDropTypes::DRAG_NONE);
 
   // Sends an XdndStatus message back to the source_window. l[2,3]
   // theoretically represent an area in the window where the current action is
diff --git a/ui/views/widget/desktop_aura/desktop_drop_target_win.cc b/ui/views/widget/desktop_aura/desktop_drop_target_win.cc
index 094a0b0..d4c4cba 100644
--- a/ui/views/widget/desktop_aura/desktop_drop_target_win.cc
+++ b/ui/views/widget/desktop_aura/desktop_drop_target_win.cc
@@ -78,6 +78,9 @@
   Translate(data_object, key_state, position, effect, &data, &event, &delegate);
   if (delegate)
     drag_operation = delegate->OnDragUpdated(*event);
+
+  UMA_HISTOGRAM_BOOLEAN("Event.DragDrop.AcceptDragUpdate",
+                        drag_operation != ui::DragDropTypes::DRAG_NONE);
   return ui::DragDropTypes::DragOperationToDropEffect(drag_operation);
 }
 
diff --git a/ui/views_bridge_mac/bridged_content_view.mm b/ui/views_bridge_mac/bridged_content_view.mm
index 520eb83..d5a2b4e 100644
--- a/ui/views_bridge_mac/bridged_content_view.mm
+++ b/ui/views_bridge_mac/bridged_content_view.mm
@@ -9,6 +9,7 @@
 #import "base/mac/mac_util.h"
 #import "base/mac/scoped_nsobject.h"
 #import "base/mac/sdk_forward_declarations.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/strings/sys_string_conversions.h"
 #include "skia/ext/skia_utils_mac.h"
 #import "ui/base/cocoa/appkit_utils.h"
@@ -639,7 +640,11 @@
 
 - (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender {
   views_bridge_mac::DragDropClient* client = [self dragDropClient];
-  return client ? client->DragUpdate(sender) : ui::DragDropTypes::DRAG_NONE;
+  const auto drag_operation =
+      client ? client->DragUpdate(sender) : ui::DragDropTypes::DRAG_NONE;
+  UMA_HISTOGRAM_BOOLEAN("Event.DragDrop.AcceptDragUpdate",
+                        drag_operation != ui::DragDropTypes::DRAG_NONE);
+  return drag_operation;
 }
 
 - (void)draggingExited:(id<NSDraggingInfo>)sender {