diff --git a/DEPS b/DEPS
index 34b1fbf..064b036 100644
--- a/DEPS
+++ b/DEPS
@@ -129,11 +129,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': 'aba7a5c93b91ee49c8a281daf19e8715978b7d81',
+  'skia_revision': '731eaa372a59ad3951ef2d461771b86e9e66c74e',
   # 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': 'a3c1051c26e72b7b86bd93d580e4a39ebdcbecd2',
+  'v8_revision': 'ce2242080787636827dd629ed5ee4e11a4368b9e',
   # 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.
@@ -145,7 +145,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': '4ba1911b2d7f526695ffed525faa9c903cd6737b',
+  'swiftshader_revision': '3bb94905928d271476a7fb2c6a14912f2de94d9f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -805,7 +805,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'd5f1da86cc3a55856e1d259b941c2c7f967e12cf',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'de64cb214d81c5af372b16e1f51c415f851358f6',
       'condition': 'checkout_linux',
   },
 
@@ -820,12 +820,12 @@
 
   # For Linux and Chromium OS.
   'src/third_party/cros_system_api': {
-      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '8ba4296f282ce24783d2c4259851907d9b9c1739',
+      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '4ebef283ecc4b2a94d68f4b4e1584cdb288a38db',
       'condition': 'checkout_linux',
   },
 
   'src/third_party/custom_tabs_client/src': {
-      'url': Var('chromium_git') + '/custom-tabs-client.git' + '@' + '26f06b877be8654c3f51928ec713a283d5ce3a88',
+      'url': Var('chromium_git') + '/custom-tabs-client.git' + '@' + 'b0d6c6e86d8046fa62135cebb7bc59d9feac9f89',
       'condition': 'checkout_android',
   },
 
@@ -1172,7 +1172,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '766ef6cc7749a612c271720bf04f545d0e8a57da',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '094a5527955836c210acb17ebffa744233963159',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
@@ -1384,7 +1384,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@cdd88f554acbe96eea5126535fe546c88e5f3ab1',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@40c6e15502942f8074065e6174ff40d8889bd439',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/ash/accessibility/accessibility_controller.cc b/ash/accessibility/accessibility_controller.cc
index 294c6f47..fec3117 100644
--- a/ash/accessibility/accessibility_controller.cc
+++ b/ash/accessibility/accessibility_controller.cc
@@ -755,11 +755,6 @@
   accessibility_highlight_controller_->SetCaretBounds(bounds_in_screen);
 }
 
-void AccessibilityController::SetAccessibilityPanelAlwaysVisible(
-    bool always_visible) {
-  GetLayoutManager()->SetAlwaysVisible(always_visible);
-}
-
 void AccessibilityController::SetAccessibilityPanelBounds(
     const gfx::Rect& bounds,
     mojom::AccessibilityPanelState state) {
diff --git a/ash/accessibility/accessibility_controller.h b/ash/accessibility/accessibility_controller.h
index 640fc34..004305d 100644
--- a/ash/accessibility/accessibility_controller.h
+++ b/ash/accessibility/accessibility_controller.h
@@ -172,7 +172,6 @@
   void BrailleDisplayStateChanged(bool connected) override;
   void SetFocusHighlightRect(const gfx::Rect& bounds_in_screen) override;
   void SetCaretBounds(const gfx::Rect& bounds_in_screen) override;
-  void SetAccessibilityPanelAlwaysVisible(bool always_visible) override;
   void SetAccessibilityPanelBounds(
       const gfx::Rect& bounds,
       mojom::AccessibilityPanelState state) override;
diff --git a/ash/accessibility/accessibility_panel_layout_manager.cc b/ash/accessibility/accessibility_panel_layout_manager.cc
index 4c1af0e7..3761c2c 100644
--- a/ash/accessibility/accessibility_panel_layout_manager.cc
+++ b/ash/accessibility/accessibility_panel_layout_manager.cc
@@ -26,11 +26,6 @@
   display::Screen::GetScreen()->RemoveObserver(this);
 }
 
-void AccessibilityPanelLayoutManager::SetAlwaysVisible(bool always_visible) {
-  always_visible_ = always_visible;
-  UpdateWindowBounds();
-}
-
 void AccessibilityPanelLayoutManager::SetPanelBounds(
     const gfx::Rect& bounds,
     mojom::AccessibilityPanelState state) {
@@ -103,12 +98,6 @@
   RootWindowController* root_controller =
       RootWindowController::ForWindow(root_window);
 
-  aura::Window* current = panel_window_;
-  while (current->parent()) {
-    current->parent()->StackChildAtTop(current);
-    current = current->parent();
-  }
-
   gfx::Rect bounds = panel_bounds_;
 
   // The panel can make itself fill the screen (including covering the shelf).
@@ -119,13 +108,6 @@
     bounds.set_width(root_window->bounds().width());
   }
 
-  // If a fullscreen browser window is open, give the panel a height of 0
-  // unless it's active or always_visible_ is true.
-  if (!always_visible_ && root_controller->GetWindowForFullscreenMode() &&
-      !::wm::IsActiveWindow(panel_window_)) {
-    bounds.set_height(0);
-  }
-
   // Make sure the accessibility panel is always below the Docked Magnifier
   // viewport so it shows up and gets magnified.
   int magnifier_height =
diff --git a/ash/accessibility/accessibility_panel_layout_manager.h b/ash/accessibility/accessibility_panel_layout_manager.h
index 70c90c2a..cd170f9 100644
--- a/ash/accessibility/accessibility_panel_layout_manager.h
+++ b/ash/accessibility/accessibility_panel_layout_manager.h
@@ -38,7 +38,6 @@
   ~AccessibilityPanelLayoutManager() override;
 
   // Controls the panel's visibility and location.
-  void SetAlwaysVisible(bool always_visible);
   void SetPanelBounds(const gfx::Rect& bounds,
                       mojom::AccessibilityPanelState state);
 
@@ -82,9 +81,6 @@
   // Window bounds when not in fullscreen
   gfx::Rect panel_bounds_ = gfx::Rect(0, 0, 0, 0);
 
-  // Determines whether panel is hidden when browser is in fullscreen.
-  bool always_visible_ = false;
-
   // Determines how the panel_bounds_ are used when displaying the panel.
   mojom::AccessibilityPanelState panel_state_ =
       mojom::AccessibilityPanelState::BOUNDED;
diff --git a/ash/autoclick/autoclick_unittest.cc b/ash/autoclick/autoclick_unittest.cc
index 3912d0f6..d245f1c 100644
--- a/ash/autoclick/autoclick_unittest.cc
+++ b/ash/autoclick/autoclick_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "ash/accessibility/accessibility_controller.h"
 #include "ash/autoclick/autoclick_controller.h"
+#include "ash/shelf/shelf.h"
 #include "ash/shell.h"
 #include "ash/system/accessibility/autoclick_menu_bubble_controller.h"
 #include "ash/system/accessibility/autoclick_menu_view.h"
@@ -749,4 +750,33 @@
   Shell::Get()->accessibility_controller()->SetAutoclickEnabled(false);
 }
 
+// The autoclick tray shouldn't stop the shelf from auto-hiding.
+TEST_F(AutoclickTest, ShelfAutohidesWithAutoclickBubble) {
+  Shell::Get()->accessibility_controller()->SetAutoclickEnabled(false);
+  Shelf* shelf = GetPrimaryShelf();
+
+  // Create a visible window so auto-hide behavior is enforced.
+  views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
+  params.bounds = gfx::Rect(0, 0, 200, 200);
+  params.context = CurrentContext();
+  views::Widget* widget = new views::Widget;
+  widget->Init(params);
+  widget->Show();
+
+  // Turn on auto-hide for the shelf.
+  shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
+  EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
+  EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState());
+
+  // Enable autoclick. The shelf should remain invisible.
+  Shell::Get()->accessibility_controller()->SetAutoclickEnabled(true);
+  AutoclickMenuView* menu = GetAutoclickMenuView();
+  ASSERT_TRUE(menu);
+  EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
+  EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState());
+
+  // Reset state.
+  Shell::Get()->accessibility_controller()->SetAutoclickEnabled(false);
+}
+
 }  // namespace ash
diff --git a/ash/public/interfaces/accessibility_controller.mojom b/ash/public/interfaces/accessibility_controller.mojom
index 222ba80..6de0721 100644
--- a/ash/public/interfaces/accessibility_controller.mojom
+++ b/ash/public/interfaces/accessibility_controller.mojom
@@ -53,10 +53,6 @@
   // Setting off-screen or empty bounds suppresses the highlight.
   SetCaretBounds(gfx.mojom.Rect bounds_in_screen);
 
-  // Sets whether the accessibility panel should always be visible, regardless
-  // of whether the window is fullscreen.
-  SetAccessibilityPanelAlwaysVisible(bool always_visible);
-
   // Sets the bounds for the accessibility panel. Overrides current
   // configuration (i.e. fullscreen, full-width).
   SetAccessibilityPanelBounds(gfx.mojom.Rect bounds,
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc
index 4f183af3..772063c 100644
--- a/ash/root_window_controller.cc
+++ b/ash/root_window_controller.cc
@@ -989,16 +989,6 @@
   settings_bubble_container->SetProperty(::wm::kUsesScreenCoordinatesKey, true);
   settings_bubble_container->SetProperty(kLockedToRootKey, true);
 
-  aura::Window* accessibility_panel_container = CreateContainer(
-      kShellWindowId_AccessibilityPanelContainer, "AccessibilityPanelContainer",
-      lock_screen_related_containers);
-  ::wm::SetChildWindowVisibilityChangesAnimated(accessibility_panel_container);
-  accessibility_panel_container->SetProperty(::wm::kUsesScreenCoordinatesKey,
-                                             true);
-  accessibility_panel_container->SetProperty(kLockedToRootKey, true);
-  accessibility_panel_container->SetLayoutManager(
-      new AccessibilityPanelLayoutManager());
-
   aura::Window* virtual_keyboard_parent_container = CreateContainer(
       kShellWindowId_ImeWindowParentContainer, "ImeWindowParentContainer",
       lock_screen_related_containers);
@@ -1031,6 +1021,16 @@
   autoclick_container->SetProperty(::wm::kUsesScreenCoordinatesKey, true);
   wm::SetSnapsChildrenToPhysicalPixelBoundary(autoclick_container);
 
+  aura::Window* accessibility_panel_container = CreateContainer(
+      kShellWindowId_AccessibilityPanelContainer, "AccessibilityPanelContainer",
+      lock_screen_related_containers);
+  ::wm::SetChildWindowVisibilityChangesAnimated(accessibility_panel_container);
+  accessibility_panel_container->SetProperty(::wm::kUsesScreenCoordinatesKey,
+                                             true);
+  accessibility_panel_container->SetProperty(kLockedToRootKey, true);
+  accessibility_panel_container->SetLayoutManager(
+      new AccessibilityPanelLayoutManager());
+
   aura::Window* drag_drop_container = CreateContainer(
       kShellWindowId_DragImageAndTooltipContainer,
       "DragImageAndTooltipContainer", lock_screen_related_containers);
diff --git a/ash/system/accessibility/autoclick_menu_view.cc b/ash/system/accessibility/autoclick_menu_view.cc
index de4b218..02064ca 100644
--- a/ash/system/accessibility/autoclick_menu_view.cc
+++ b/ash/system/accessibility/autoclick_menu_view.cc
@@ -122,6 +122,10 @@
 
 AutoclickMenuBubbleView::~AutoclickMenuBubbleView() {}
 
+bool AutoclickMenuBubbleView::IsAnchoredToStatusArea() const {
+  return false;
+}
+
 void AutoclickMenuBubbleView::MoveToPosition(const gfx::Rect& rect) {
   // TODO(katie): Animate to the new position.
   SetAnchorRect(rect);
diff --git a/ash/system/accessibility/autoclick_menu_view.h b/ash/system/accessibility/autoclick_menu_view.h
index d89c8ac..789ddec 100644
--- a/ash/system/accessibility/autoclick_menu_view.h
+++ b/ash/system/accessibility/autoclick_menu_view.h
@@ -20,6 +20,9 @@
   AutoclickMenuBubbleView(TrayBubbleView::InitParams init_params);
   ~AutoclickMenuBubbleView() override;
 
+  // TrayBubbleView:
+  bool IsAnchoredToStatusArea() const override;
+
   void MoveToPosition(const gfx::Rect& rect);
 
  private:
diff --git a/ash/system/tray/tray_bubble_view.cc b/ash/system/tray/tray_bubble_view.cc
index 93776c8..4f7a66f 100644
--- a/ash/system/tray/tray_bubble_view.cc
+++ b/ash/system/tray/tray_bubble_view.cc
@@ -271,7 +271,8 @@
   GetWidget()->Show();
   UpdateBubble();
 
-  ++g_current_tray_bubble_showing_count_;
+  if (IsAnchoredToStatusArea())
+    ++g_current_tray_bubble_showing_count_;
 
   // If TrayBubbleView cannot be activated and is shown by clicking on the
   // corresponding tray view, register pre target event handler to reroute key
@@ -338,6 +339,10 @@
   SetArrow(GetArrowAlignment(alignment));
 }
 
+bool TrayBubbleView::IsAnchoredToStatusArea() const {
+  return true;
+}
+
 int TrayBubbleView::GetDialogButtons() const {
   return ui::DIALOG_BUTTON_NONE;
 }
@@ -370,7 +375,10 @@
   reroute_event_handler_.reset();
 
   BubbleDialogDelegateView::OnWidgetClosing(widget);
-  --g_current_tray_bubble_showing_count_;
+
+  if (IsAnchoredToStatusArea()) {
+    --g_current_tray_bubble_showing_count_;
+  }
   DCHECK_GE(g_current_tray_bubble_showing_count_, 0)
       << "Closing " << widget->GetName();
 }
diff --git a/ash/system/tray/tray_bubble_view.h b/ash/system/tray/tray_bubble_view.h
index 78de7f0a..9bc03a9 100644
--- a/ash/system/tray/tray_bubble_view.h
+++ b/ash/system/tray/tray_bubble_view.h
@@ -155,6 +155,11 @@
   // Change anchor alignment mode when anchoring either the rect or view.
   void ChangeAnchorAlignment(AnchorAlignment alignment);
 
+  // Returns true if the bubble is an anchored status area bubble. Override
+  // this function for a bubble which is not anchored directly to the status
+  // area.
+  virtual bool IsAnchoredToStatusArea() const;
+
   Delegate* delegate() { return delegate_; }
 
   void set_gesture_dragging(bool dragging) { is_gesture_dragging_ = dragging; }
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
index ae42663..842355a2 100644
--- a/base/metrics/histogram.cc
+++ b/base/metrics/histogram.cc
@@ -263,6 +263,8 @@
                                          TimeDelta maximum,
                                          uint32_t bucket_count,
                                          int32_t flags) {
+  DCHECK_LT(minimum.InMilliseconds(), std::numeric_limits<Sample>::max());
+  DCHECK_LT(maximum.InMilliseconds(), std::numeric_limits<Sample>::max());
   return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()),
                     static_cast<Sample>(maximum.InMilliseconds()), bucket_count,
                     flags);
@@ -273,6 +275,8 @@
                                                      TimeDelta maximum,
                                                      uint32_t bucket_count,
                                                      int32_t flags) {
+  DCHECK_LT(minimum.InMicroseconds(), std::numeric_limits<Sample>::max());
+  DCHECK_LT(maximum.InMicroseconds(), std::numeric_limits<Sample>::max());
   return FactoryGet(name, static_cast<Sample>(minimum.InMicroseconds()),
                     static_cast<Sample>(maximum.InMicroseconds()), bucket_count,
                     flags);
@@ -900,6 +904,8 @@
                                                TimeDelta maximum,
                                                uint32_t bucket_count,
                                                int32_t flags) {
+  DCHECK_LT(minimum.InMilliseconds(), std::numeric_limits<Sample>::max());
+  DCHECK_LT(maximum.InMilliseconds(), std::numeric_limits<Sample>::max());
   return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()),
                     static_cast<Sample>(maximum.InMilliseconds()), bucket_count,
                     flags);
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index aaa72eb..c4393ff 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8916875429194723312
\ No newline at end of file
+8916765319702380096
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 5baed26..5a0d165 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-8916873457256596624
\ No newline at end of file
+8916772086441183392
\ No newline at end of file
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index 59c4845..687ab1b 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -883,11 +883,9 @@
   if (inner_viewport_scroll_delta.IsZero() && info.page_scale_delta == 1.f &&
       info.elastic_overscroll_delta.IsZero() && !info.top_controls_delta &&
       !info.browser_controls_constraint_changed &&
-      !info.scroll_gesture_did_end &&
-      info.is_pinch_gesture_active == is_pinch_gesture_active_from_impl_) {
+      !info.scroll_gesture_did_end) {
     return;
   }
-  is_pinch_gesture_active_from_impl_ = info.is_pinch_gesture_active;
 
   // Preemptively apply the scroll offset and scale delta here before sending
   // it to the client.  If the client comes back and sets it to the same
@@ -1328,16 +1326,11 @@
       this, [](Layer* layer) { layer->SetNeedsDisplay(); });
 }
 
-void LayerTreeHost::SetExternalPageScaleFactor(
-    float page_scale_factor,
-    bool is_external_pinch_gesture_active) {
-  if (external_page_scale_factor_ == page_scale_factor &&
-      is_external_pinch_gesture_active_ == is_external_pinch_gesture_active) {
+void LayerTreeHost::SetExternalPageScaleFactor(float page_scale_factor) {
+  if (external_page_scale_factor_ == page_scale_factor)
     return;
-  }
 
   external_page_scale_factor_ = page_scale_factor;
-  is_external_pinch_gesture_active_ = is_external_pinch_gesture_active;
   SetNeedsCommit();
 }
 
@@ -1658,7 +1651,6 @@
   host_impl->SetHasGpuRasterizationTrigger(has_gpu_rasterization_trigger_);
   host_impl->SetContentHasSlowPaths(content_has_slow_paths_);
   host_impl->SetContentHasNonAAPaint(content_has_non_aa_paint_);
-  host_impl->set_pinch_gesture_active(is_external_pinch_gesture_active_);
   RecordGpuRasterizationHistogram(host_impl);
 
   host_impl->SetDebugState(debug_state_);
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index cd2c6e69..85c520d 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -471,11 +471,7 @@
   // 'external_page_scale_factor', a value that affects raster scale in the
   // same way that page_scale_factor does, but doesn't affect any geometry
   // calculations.
-  void SetExternalPageScaleFactor(float page_scale_factor,
-                                  bool is_external_pinch_gesture_active);
-  bool is_external_pinch_gesture_active_for_testing() {
-    return is_external_pinch_gesture_active_;
-  }
+  void SetExternalPageScaleFactor(float page_scale_factor);
 
   // Requests that we force send RenderFrameMetadata with the next frame.
   void RequestForceSendMetadata() { force_send_metadata_request_ = true; }
@@ -809,9 +805,6 @@
   float min_page_scale_factor_ = 1.f;
   float max_page_scale_factor_ = 1.f;
   float external_page_scale_factor_ = 1.f;
-  bool is_external_pinch_gesture_active_ = false;
-  // Used to track the out-bound state for ApplyViewportChanges.
-  bool is_pinch_gesture_active_from_impl_ = false;
 
   int raster_color_space_id_ = -1;
   gfx::ColorSpace raster_color_space_;
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index c2d3791e..8e76053 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -591,15 +591,6 @@
   }
 
   bool pinch_gesture_active() const { return pinch_gesture_active_; }
-  // Used to set the pinch gesture active state when the pinch gesture is
-  // handled on another layer tree. In a page with OOPIFs, only the main
-  // frame's layer tree directly handles pinch events. But layer trees for
-  // sub-frames need to know when pinch gestures are active so they can
-  // throttle the re-rastering. This function allows setting this flag on
-  // OOPIF layer trees using information sent (initially) from the main-frame.
-  void set_pinch_gesture_active(bool external_pinch_gesture_active) {
-    pinch_gesture_active_ = external_pinch_gesture_active;
-  }
 
   void SetTreePriority(TreePriority priority);
   TreePriority GetTreePriority() const;
@@ -1015,15 +1006,6 @@
   bool did_scroll_x_for_scroll_gesture_;
   bool did_scroll_y_for_scroll_gesture_;
 
-  // This value is used to allow the compositor to throttle re-rastering during
-  // pinch gestures, when the page scale factor may be changing frequently. It
-  // is set in one of two ways:
-  // i) In a layer tree serving the root of the frame/compositor tree, it is
-  // directly set during processing of GesturePinch events on the impl thread
-  // (only the root layer tree has access to these).
-  // ii) In a layer tree serving a sub-frame in the frame/compositor tree, it
-  // is set from the main thread during the commit process, using information
-  // sent from the root layer tree via IPC messaging.
   bool pinch_gesture_active_ = false;
   bool pinch_gesture_end_should_clear_scrolling_node_ = false;
 
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni
index b005fbe..a71fdbb 100644
--- a/chrome/android/chrome_test_java_sources.gni
+++ b/chrome/android/chrome_test_java_sources.gni
@@ -356,13 +356,6 @@
   "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServiceWorkerPaymentAppTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressAndOptionTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressChangeTest.java",
-  "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowPromiseDigitalGoodsTest.java",
-  "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowPromiseInvalidDetailsTest.java",
-  "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowPromiseRejectTest.java",
-  "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowPromiseSingleOptionShippingTest.java",
-  "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowPromiseSingleOptionShippingWithUpdateTest.java",
-  "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowPromiseUnsupportedTest.java",
-  "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowPromiseUSOnlyShippingTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowTwiceTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTabTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestRule.java",
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantClient.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantClient.java
index 15dbe6a..537919df 100644
--- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantClient.java
+++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantClient.java
@@ -83,9 +83,10 @@
     /**
      * Launches Autofill Assistant on the current web contents, expecting autostart.
      */
-    public void start(String initialUrl, Map<String, String> parameters, Bundle intentExtras) {
+    public void start(String initialUrl, Map<String, String> parameters,
+            @Nullable String experimentIds, Bundle intentExtras) {
         checkNativeClientIsAliveOrThrow();
-        nativeStart(mNativeClientAndroid, initialUrl,
+        nativeStart(mNativeClientAndroid, initialUrl, experimentIds == null ? "" : experimentIds,
                 parameters.keySet().toArray(new String[parameters.size()]),
                 parameters.values().toArray(new String[parameters.size()]));
         chooseAccountAsync(parameters.get(PARAMETER_USER_EMAIL), intentExtras);
@@ -251,7 +252,7 @@
     private static native AutofillAssistantClient nativeFromWebContents(WebContents webContents);
     private native void nativeShowOnboarding(long nativeClientAndroid, Object onAccept);
     private native void nativeStart(long nativeClientAndroid, String initialUrl,
-            String[] parameterNames, String[] parameterValues);
+            String experimentIds, 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/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java
index 0a3470da..98602cc 100644
--- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java
+++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java
@@ -47,6 +47,9 @@
     /** Pending intent sent by first-party apps. */
     private static final String PENDING_INTENT_NAME = INTENT_SPECIAL_PREFIX + "PENDING_INTENT";
 
+    /** Intent extra name for csv list of experiment ids. */
+    private static final String EXPERIMENT_IDS_NAME = INTENT_SPECIAL_PREFIX + "EXPERIMENT_IDS";
+
     /** Package names of trusted first-party apps, from the pending intent. */
     private static final String[] TRUSTED_CALLER_PACKAGES = {
             "com.google.android.googlequicksearchbox", // GSA
@@ -88,13 +91,20 @@
     }
 
     private static void startNow(ChromeActivity activity, Tab tab) {
-        Map<String, String> parameters = extractParameters(activity.getInitialIntent().getExtras());
+        Bundle bundleExtras = activity.getInitialIntent().getExtras();
+        Map<String, String> parameters = extractParameters(bundleExtras);
         parameters.remove(PARAMETER_ENABLED);
         String initialUrl = activity.getInitialIntent().getDataString();
 
         AutofillAssistantClient client =
                 AutofillAssistantClient.fromWebContents(tab.getWebContents());
-        client.start(initialUrl, parameters, activity.getInitialIntent().getExtras());
+
+        String experimentIds = null;
+        if (bundleExtras != null) {
+            experimentIds = IntentUtils.safeGetString(bundleExtras, EXPERIMENT_IDS_NAME);
+        }
+        client.start(
+                initialUrl, parameters, experimentIds, activity.getInitialIntent().getExtras());
     }
 
     private static void getTab(ChromeActivity activity, Callback<Tab> callback) {
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index bf56f45..07aa8ed9 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -1137,7 +1137,7 @@
             <intent-filter>
               <action android:name="android.support.customtabs.action.CustomTabsService" />
               <category android:name="androidx.browser.trusted.category.TrustedWebActivities"/>
-              <category android:name="android.support.customtabs.category.TrustedWebActivitySplashScreensV1"/>
+              <category android:name="androidx.browser.trusted.category.TrustedWebActivitySplashScreensV1"/>
             </intent-filter>
         </service>
         <service android:name="android.support.customtabs.PostMessageService" />
diff --git a/chrome/android/java/monochrome_public_apk.AndroidManifest.expected b/chrome/android/java/monochrome_public_apk.AndroidManifest.expected
index e872549..3f8bc380 100644
--- a/chrome/android/java/monochrome_public_apk.AndroidManifest.expected
+++ b/chrome/android/java/monochrome_public_apk.AndroidManifest.expected
@@ -1954,9 +1954,9 @@
         tools:ignore="ExportedService">
       <intent-filter>
         <action android:name="android.support.customtabs.action.CustomTabsService"/>
-        <category
-            android:name="android.support.customtabs.category.TrustedWebActivitySplashScreensV1"/>
         <category android:name="androidx.browser.trusted.category.TrustedWebActivities"/>
+        <category
+            android:name="androidx.browser.trusted.category.TrustedWebActivitySplashScreensV1"/>
       </intent-filter>
     </service>
     <service
diff --git a/chrome/android/java/res/values/ids.xml b/chrome/android/java/res/values/ids.xml
index b658a52..e7ee576 100644
--- a/chrome/android/java/res/values/ids.xml
+++ b/chrome/android/java/res/values/ids.xml
@@ -67,8 +67,6 @@
     <item type="id" name="payments_add_option_button" />
     <item type="id" name="payments_edit_cancel_button" />
     <item type="id" name="payments_edit_checkbox" />
-    <item type="id" name="payments_description_label" />
-    <item type="id" name="payments_warning_label" />
 
     <!-- Password update prompt -->
     <item type="id" name="password_infobar_accounts_spinner" />
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/splashscreen/SplashScreenController.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/splashscreen/SplashScreenController.java
index 559c3b1..8eb71dfe 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/splashscreen/SplashScreenController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/splashscreen/SplashScreenController.java
@@ -10,11 +10,14 @@
 import android.content.Intent;
 import android.graphics.Bitmap;
 import android.graphics.Color;
+import android.graphics.Matrix;
 import android.os.Bundle;
 import android.support.annotation.Nullable;
 import android.support.customtabs.TrustedWebUtils;
+import android.support.customtabs.TrustedWebUtils.SplashScreenParamKey;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewPropertyAnimator;
 import android.widget.ImageView;
 
 import org.chromium.base.Log;
@@ -24,9 +27,11 @@
 import org.chromium.chrome.browser.customtabs.TabObserverRegistrar;
 import org.chromium.chrome.browser.customtabs.TranslucentCustomTabActivity;
 import org.chromium.chrome.browser.init.ActivityLifecycleDispatcher;
+import org.chromium.chrome.browser.lifecycle.Destroyable;
 import org.chromium.chrome.browser.lifecycle.InflationObserver;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.util.ColorUtils;
 import org.chromium.chrome.browser.util.IntentUtils;
 
 import java.lang.reflect.Method;
@@ -55,7 +60,7 @@
  * - It also immediately removes the translucency via a reflective call to
  * {@link Activity#convertFromTranslucent}. This is important for performance, otherwise the windows
  * under Chrome will continue being drawn (e.g. launcher with wallpaper). Without removing
- * traslucency, we also see visual glitches when closing TWA and sending it to background (example:
+ * translucency, we also see visual glitches when closing TWA and sending it to background (example:
  * https://crbug.com/856544#c30).
  * - It waits for the page to load, and removes the splash image once first paint (or a failure)
  * occurs.
@@ -64,7 +69,7 @@
  * gc-ed when it finishes its job (to that end, it removes all observers it has set).
  * If these lifecycle assumptions change, consider whether @ActivityScope needs to be added.
  */
-public class SplashScreenController implements InflationObserver {
+public class SplashScreenController implements InflationObserver, Destroyable {
 
     private static final String TAG = "TwaSplashScreens";
 
@@ -78,6 +83,9 @@
     @Nullable
     private ImageView mSplashView;
 
+    @Nullable
+    private ViewPropertyAnimator mFadeOutAnimator;
+
     @Inject
     public SplashScreenController(TabObserverRegistrar tabObserverRegistrar,
             Activity activity,
@@ -120,21 +128,46 @@
             mLifecycleDispatcher.unregister(this);
             return;
         }
-        Bundle params = mIntentDataProvider.getIntent().getBundleExtra(
-                TrustedWebUtils.EXTRA_SPLASH_SCREEN_PARAMS);
-        int backgroundColor = params.getInt(TrustedWebUtils.SplashScreenParamKey.BACKGROUND_COLOR,
-                Color.WHITE);
-
         mSplashView = new ImageView(mActivity);
         mSplashView.setLayoutParams(new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
         mSplashView.setImageBitmap(bitmap);
-        mSplashView.setBackgroundColor(backgroundColor);
-        mSplashView.setScaleType(ImageView.ScaleType.FIT_CENTER);
+        applyCustomizationsToSplashScreenView(mSplashView);
         // At this point the actual layout is not yet inflated. When it is, it replaces the
         // splash screen, but we put it back on top in onPostInflationStartup.
         mActivity.setContentView(mSplashView);
     }
 
+    private void applyCustomizationsToSplashScreenView(ImageView imageView) {
+        Bundle params = getSplashScreenParamsFromIntent();
+
+        int backgroundColor = IntentUtils.safeGetInt(params, SplashScreenParamKey.BACKGROUND_COLOR,
+                Color.WHITE);
+        imageView.setBackgroundColor(ColorUtils.getOpaqueColor(backgroundColor));
+
+        int scaleTypeOrdinal = IntentUtils.safeGetInt(params, SplashScreenParamKey.SCALE_TYPE, -1);
+        ImageView.ScaleType[] scaleTypes = ImageView.ScaleType.values();
+        ImageView.ScaleType scaleType;
+        if (scaleTypeOrdinal < 0 || scaleTypeOrdinal >= scaleTypes.length) {
+            scaleType = ImageView.ScaleType.CENTER;
+        } else {
+            scaleType = scaleTypes[scaleTypeOrdinal];
+        }
+        imageView.setScaleType(scaleType);
+
+        if (scaleType != ImageView.ScaleType.MATRIX) return;
+        float[] matrixValues = IntentUtils.safeGetFloatArray(params,
+                SplashScreenParamKey.IMAGE_TRANSFORMATION_MATRIX);
+        if (matrixValues == null || matrixValues.length != 9) return;
+        Matrix matrix = new Matrix();
+        matrix.setValues(matrixValues);
+        imageView.setImageMatrix(matrix);
+    }
+
+    private Bundle getSplashScreenParamsFromIntent() {
+        return mIntentDataProvider.getIntent().getBundleExtra(
+                TrustedWebUtils.EXTRA_SPLASH_SCREEN_PARAMS);
+    }
+
     @Override
     public void onPostInflationStartup() {
         if (mSplashView == null) {
@@ -180,7 +213,8 @@
             private void onPageReady(Tab tab) {
                 tab.removeObserver(this); // TODO(pshmakov): make TabObserverRegistrar do this.
                 mTabObserverRegistrar.unregisterTabObserver(this);
-                removeSplashScreen();
+                mCompositorViewHolder.get().getCompositorView().surfaceRedrawNeededAsync(
+                        SplashScreenController.this::removeSplashScreen);
             }
         });
     }
@@ -195,12 +229,33 @@
         mSplashView = null;
 
         mActivity.findViewById(R.id.coordinator).setVisibility(View.VISIBLE);
-        mCompositorViewHolder.get().getCompositorView().surfaceRedrawNeededAsync(
-                () -> getRootView().removeView(splashView));
 
+        int fadeOutDuration = IntentUtils.safeGetInt(getSplashScreenParamsFromIntent(),
+                SplashScreenParamKey.FADE_OUT_DURATION_MS, 0);
+        if (fadeOutDuration == 0) {
+            onSplashScreenFadeOutComplete(splashView);
+        } else {
+            mFadeOutAnimator = splashView.animate()
+                    .alpha(0)
+                    .setDuration(fadeOutDuration)
+                    .withEndAction(() -> onSplashScreenFadeOutComplete(splashView));
+            mFadeOutAnimator.start();
+        }
+    }
+
+    private void onSplashScreenFadeOutComplete(View splashView) {
+        getRootView().removeView(splashView);
+        mFadeOutAnimator = null;
         mLifecycleDispatcher.unregister(this);  // Unregister to get gc-ed
     }
 
+    @Override
+    public void destroy() {
+        if (mFadeOutAnimator != null) {
+            mFadeOutAnimator.cancel();
+        }
+    }
+
     /**
      * Returns true if the intent corresponds to a TWA with a splash screen.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestFactory.java
index 40f7c76..a9e64c68 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestFactory.java
@@ -38,7 +38,7 @@
         }
 
         @Override
-        public void show(boolean isUserGesture, boolean waitForUpdatedDetails) {
+        public void show(boolean isUserGesture) {
             if (mClient != null) {
                 mClient.onError(PaymentErrorReason.USER_CANCEL);
                 mClient.close();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
index 5547717..d4b6a4b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
@@ -109,13 +109,6 @@
      */
     public interface PaymentRequestServiceObserverForTest {
         /**
-         * Called after an instance of PaymentRequestImpl has been created.
-         *
-         * @param paymentRequest The newly created instance of PaymentRequestImpl.
-         */
-        void onPaymentRequestCreated(PaymentRequestImpl paymentRequest);
-
-        /**
          * Called when an abort request was denied.
          */
         void onPaymentRequestServiceUnableToAbort();
@@ -309,7 +302,6 @@
     private boolean mHideServerAutofillInstruments;
     private ContactEditor mContactEditor;
     private boolean mHasRecordedAbortReason;
-    private boolean mWaitForUpdatedDetails;
     private Map<String, CurrencyFormatter> mCurrencyFormatterMap;
     private TabModelSelector mObservedTabModelSelector;
     private TabModel mObservedTabModel;
@@ -383,8 +375,6 @@
 
         mJourneyLogger = new JourneyLogger(mIsIncognito, mWebContents);
         mCurrencyFormatterMap = new HashMap<>();
-
-        if (sObserverForTest != null) sObserverForTest.onPaymentRequestCreated(this);
     }
 
     /**
@@ -482,19 +472,7 @@
         }
         mJourneyLogger.setRequestedPaymentMethodTypes(mMerchantSupportsAutofillPaymentInstruments,
                 requestedMethodGoogle, requestedMethodOther);
-        calculateWhetherShouldSkipShowingPaymentRequestUi(
-                false /* skipUiForNonUrlPaymentMethodIdentifiersForTest */);
-    }
 
-    /**
-     * Calculate whether the browser payment sheet should be skipped directly into the payment app.
-     *
-     * @param skipUiForNonUrlPaymentMethodIdentifiersForTest Whether non-URL payment method
-     *                                                       identifiers should skip UI. Used only
-     *                                                       in tests.
-     */
-    private void calculateWhetherShouldSkipShowingPaymentRequestUi(
-            boolean skipUiForNonUrlPaymentMethodIdentifiersForTest) {
         // If there is a single payment method and the merchant has not requested any other
         // information, we can safely go directly to the payment app instead of showing
         // Payment Request UI.
@@ -507,8 +485,7 @@
                 // This excludes AutofillPaymentApp as its UI is rendered inline in
                 // the payment request UI, thus can't be skipped.
                 && mMethodData.keySet().iterator().next() != null
-                && (mMethodData.keySet().iterator().next().startsWith(UrlConstants.HTTPS_URL_PREFIX)
-                        || skipUiForNonUrlPaymentMethodIdentifiersForTest);
+                && mMethodData.keySet().iterator().next().startsWith(UrlConstants.HTTPS_URL_PREFIX);
     }
 
     /** @return Whether the UI was built. */
@@ -549,7 +526,7 @@
                     false /* includeNameInLabel */);
         }
 
-        if (mRequestShipping && !mWaitForUpdatedDetails) {
+        if (mRequestShipping) {
             createShippingSection(activity, Collections.unmodifiableList(profiles));
         }
 
@@ -645,7 +622,7 @@
      * Called by the merchant website to show the payment request to the user.
      */
     @Override
-    public void show(boolean isUserGesture, boolean waitForUpdatedDetails) {
+    public void show(boolean isUserGesture) {
         if (mClient == null) return;
 
         if (mUI != null) {
@@ -680,8 +657,6 @@
         }
 
         mIsUserGestureShow = isUserGesture;
-        mWaitForUpdatedDetails = waitForUpdatedDetails;
-
         if (!mShouldSkipShowingPaymentRequestUi) {
             if (!buildUI(chromeActivity)) return;
             mUI.show();
@@ -694,7 +669,7 @@
         // If we are skipping showing the Payment Request UI, we should call into the
         // PaymentApp immediately after we determine the instruments are ready and UI is shown.
         if (mShouldSkipShowingPaymentRequestUi && isFinishedQueryingPaymentApps()
-                && mIsCurrentPaymentRequestShowing && !mWaitForUpdatedDetails) {
+                && mIsCurrentPaymentRequestShowing) {
             assert !mPaymentMethodsSection.isEmpty();
 
             PaymentInstrument selectedInstrument =
@@ -863,11 +838,6 @@
     public void updateWith(PaymentDetails details) {
         if (mClient == null) return;
 
-        if (mWaitForUpdatedDetails) {
-            initializeWithUpdatedDetails(details);
-            return;
-        }
-
         if (mUI == null) {
             mJourneyLogger.setAborted(AbortReason.INVALID_DATA_FROM_RENDERER);
             disconnectFromClientWithDebugMessage(
@@ -875,14 +845,6 @@
             return;
         }
 
-        if (!mRequestShipping) {
-            mJourneyLogger.setAborted(AbortReason.INVALID_DATA_FROM_RENDERER);
-            disconnectFromClientWithDebugMessage(
-                    "PaymentRequestUpdateEvent.updateWith() called without passing a promise into "
-                    + "PaymentRequest.show() and without requestShipping:true");
-            return;
-        }
-
         if (!parseAndValidateDetailsOrDisconnectFromClient(details)) return;
 
         if (mInvokedPaymentInstrument != null) {
@@ -910,49 +872,6 @@
         enableUserInterfaceAfterPaymentRequestUpdateEvent();
     }
 
-    private void initializeWithUpdatedDetails(PaymentDetails details) {
-        assert mWaitForUpdatedDetails;
-
-        ChromeActivity chromeActivity = ChromeActivity.fromWebContents(mWebContents);
-        if (chromeActivity == null) {
-            mJourneyLogger.setNotShown(NotShownReason.OTHER);
-            disconnectFromClientWithDebugMessage("Unable to find Chrome activity");
-            return;
-        }
-
-        if (!parseAndValidateDetailsOrDisconnectFromClient(details)) return;
-
-        if (details.total == null) {
-            mJourneyLogger.setNotShown(NotShownReason.OTHER);
-            disconnectFromClientWithDebugMessage(
-                    "PaymentRequestUpdateEvent.updateWith() called without a total amount when "
-                    + "resolving the promise passed into PaymentRequest.show()");
-            return;
-        }
-
-        if (!TextUtils.isEmpty(details.error)) {
-            mJourneyLogger.setNotShown(NotShownReason.OTHER);
-            disconnectFromClientWithDebugMessage(
-                    "PaymentRequestUpdateEvent.updateWith() called with an error when resolving "
-                    + "the promise passed into PaymentRequest.show()");
-            return;
-        }
-
-        if (mRequestShipping) {
-            createShippingSection(chromeActivity,
-                    Collections.unmodifiableList(
-                            PersonalDataManager.getInstance().getProfilesToSuggest(
-                                    false /* includeNameInLabel */)));
-        }
-
-        if (!mShouldSkipShowingPaymentRequestUi) {
-            enableUserInterfaceAfterPaymentRequestUpdateEvent();
-        }
-
-        mWaitForUpdatedDetails = false;
-        triggerPaymentAppUiSkipIfApplicable(chromeActivity);
-    }
-
     /**
      * Called when the merchant received a new shipping address, shipping option, or payment method
      * info, but did not update the payment details in response.
@@ -977,13 +896,11 @@
     }
 
     private void enableUserInterfaceAfterPaymentRequestUpdateEvent() {
-        if (mPaymentInformationCallback != null && mPaymentMethodsSection != null) {
+        if (mPaymentInformationCallback != null) {
             providePaymentInformation();
         } else {
             mUI.updateOrderSummarySection(mUiShoppingCart);
-            if (mRequestShipping) {
-                mUI.updateSection(PaymentRequestUI.DataType.SHIPPING_OPTIONS, mUiShippingOptions);
-            }
+            mUI.updateSection(PaymentRequestUI.DataType.SHIPPING_OPTIONS, mUiShippingOptions);
         }
     }
 
@@ -1207,7 +1124,7 @@
     public void getDefaultPaymentInformation(Callback<PaymentInformation> callback) {
         mPaymentInformationCallback = callback;
 
-        if (mPaymentMethodsSection == null || mWaitForUpdatedDetails) return;
+        if (mPaymentMethodsSection == null) return;
 
         mHandler.post(() -> {
             if (mUI != null) providePaymentInformation();
@@ -1967,9 +1884,7 @@
         updateInstrumentModifiedTotals();
 
         // UI has requested the full list of payment instruments. Provide it now.
-        if (mPaymentInformationCallback != null && !mWaitForUpdatedDetails) {
-            providePaymentInformation();
-        }
+        if (mPaymentInformationCallback != null) providePaymentInformation();
 
         SettingsAutofillAndPaymentsObserver.getInstance().registerObserver(this);
 
@@ -2208,12 +2123,6 @@
         sIsLocalCanMakePaymentQueryQuotaEnforcedForTest = true;
     }
 
-    @VisibleForTesting
-    /* package */ void setSkipUIForNonURLPaymentMethodIdentifiersForTest() {
-        calculateWhetherShouldSkipShowingPaymentRequestUi(
-                true /* skipUiForNonUrlPaymentMethodIdentifiersForTest */);
-    }
-
     /**
      * Compares two payment instruments by frecency.
      * Return negative value if a has strictly lower frecency score than b.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestSection.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestSection.java
index 77b0ab18..2a39ce30 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestSection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestSection.java
@@ -991,13 +991,11 @@
 
                     ApiCompatibilityUtils.setTextAppearance(
                             labelView, R.style.TextAppearance_BlackBody);
-                    labelView.setId(R.id.payments_description_label);
                 } else if (mRowType == OPTION_ROW_TYPE_WARNING) {
                     // Warnings use three columns.
                     columnSpan = 3;
                     ApiCompatibilityUtils.setTextAppearance(
                             labelView, R.style.TextAppearance_PaymentsUiSectionWarningText);
-                    labelView.setId(R.id.payments_warning_label);
                 }
 
                 // The label spans two columns if no option or edit icon, or spans three columns if
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfAndroidBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfAndroidBridge.java
index 82718150..4f02c98 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfAndroidBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfAndroidBridge.java
@@ -110,12 +110,11 @@
      * Return whether the feature is available for the current user Profile and
      * the current WebContents.
      *
-     * @param profile Profile of the user.
      * @param WebContents The current WebContents.
      * @return Whether the feature is available.
      */
-    public static boolean isFeatureAvailable(Profile profile, WebContents webContents) {
-        return SendTabToSelfAndroidBridgeJni.get().isFeatureAvailable(profile, webContents);
+    public static boolean isFeatureAvailable(WebContents webContents) {
+        return SendTabToSelfAndroidBridgeJni.get().isFeatureAvailable(webContents);
     }
 
     @NativeMethods
@@ -133,6 +132,6 @@
 
         SendTabToSelfEntry getEntryByGUID(Profile profile, String guid);
 
-        boolean isFeatureAvailable(Profile profile, WebContents webContents);
+        boolean isFeatureAvailable(WebContents webContents);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfShareActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfShareActivity.java
index fcbd8d61..33062b4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfShareActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfShareActivity.java
@@ -34,7 +34,6 @@
     }
 
     public static boolean featureIsAvailable(Tab currentTab) {
-        return SendTabToSelfAndroidBridge.isFeatureAvailable(
-                currentTab.getProfile(), currentTab.getWebContents());
+        return SendTabToSelfAndroidBridge.isFeatureAvailable(currentTab.getWebContents());
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/util/IntentUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/util/IntentUtils.java
index 73d71fec..e9fcb1e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/util/IntentUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/util/IntentUtils.java
@@ -144,6 +144,19 @@
     }
 
     /**
+     * Just like {@link Bundle#getFloatArray(String)} but doesn't throw exceptions.
+     */
+    public static float[] safeGetFloatArray(Bundle bundle, String name) {
+        try {
+            return bundle.getFloatArray(name);
+        } catch (Throwable t) {
+            // Catches un-parceling exceptions.
+            Log.e(TAG, "getFloatArray failed on bundle " + bundle);
+            return null;
+        }
+    }
+
+    /**
      * Just like {@link Intent#getLongExtra(String, long)} but doesn't throw exceptions.
      */
     public static long safeGetLongExtra(Intent intent, String name, long defaultValue) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowPromiseDigitalGoodsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowPromiseDigitalGoodsTest.java
deleted file mode 100644
index 7029a80..0000000
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowPromiseDigitalGoodsTest.java
+++ /dev/null
@@ -1,111 +0,0 @@
-// 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.
-
-package org.chromium.chrome.browser.payments;
-
-import android.support.test.filters.MediumTest;
-
-import org.junit.Assert;
-import org.junit.ClassRule;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.Feature;
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeSwitches;
-import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
-import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
-
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeoutException;
-
-/**
- * A payment integration test for the show promise with digital goods.
- */
-@RunWith(ChromeJUnit4ClassRunner.class)
-@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
-public class PaymentRequestShowPromiseDigitalGoodsTest implements MainActivityStartCallback {
-    // Disable animations to reduce flakiness.
-    @ClassRule
-    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
-
-    @Rule
-    public PaymentRequestTestRule mRule =
-            new PaymentRequestTestRule("show_promise/digital_goods.html", this);
-
-    @Override
-    public void onMainActivityStarted()
-            throws InterruptedException, ExecutionException, TimeoutException {}
-
-    @Test
-    @MediumTest
-    @Feature({"Payments"})
-    public void testDigitalGoodsFastApp()
-            throws InterruptedException, ExecutionException, TimeoutException {
-        mRule.installPaymentApp("basic-card", PaymentRequestTestRule.HAVE_INSTRUMENTS,
-                PaymentRequestTestRule.IMMEDIATE_RESPONSE);
-        mRule.openPage();
-        mRule.executeJavaScriptAndWaitForResult("create();");
-        mRule.triggerUIAndWait(mRule.getReadyToPay());
-
-        Assert.assertEquals("USD $1.00", mRule.getOrderSummaryTotal());
-
-        mRule.clickAndWait(R.id.button_primary, mRule.getDismissed());
-
-        mRule.expectResultContains(new String[] {"\"total\":\"1.00\""});
-    }
-
-    @Test
-    @MediumTest
-    @Feature({"Payments"})
-    public void testDigitalGoodsSlowApp()
-            throws InterruptedException, ExecutionException, TimeoutException {
-        mRule.installPaymentApp("basic-card", PaymentRequestTestRule.HAVE_INSTRUMENTS,
-                PaymentRequestTestRule.DELAYED_RESPONSE, PaymentRequestTestRule.DELAYED_CREATION);
-        mRule.openPage();
-        mRule.executeJavaScriptAndWaitForResult("create();");
-        mRule.triggerUIAndWait(mRule.getReadyToPay());
-
-        Assert.assertEquals("USD $1.00", mRule.getOrderSummaryTotal());
-
-        mRule.clickAndWait(R.id.button_primary, mRule.getDismissed());
-
-        mRule.expectResultContains(new String[] {"\"total\":\"1.00\""});
-    }
-
-    @Test
-    @MediumTest
-    @Feature({"Payments"})
-    public void testSkipUIFastApp()
-            throws InterruptedException, ExecutionException, TimeoutException {
-        mRule.installPaymentApp("basic-card", PaymentRequestTestRule.HAVE_INSTRUMENTS,
-                PaymentRequestTestRule.IMMEDIATE_RESPONSE);
-        mRule.openPage();
-        mRule.executeJavaScriptAndWaitForResult("create();");
-        mRule.enableSkipUIForBasicCard();
-
-        mRule.openPageAndClickNodeAndWait("buy", mRule.getDismissed());
-
-        mRule.expectResultContains(new String[] {"\"total\":\"1.00\""});
-    }
-
-    @Test
-    @MediumTest
-    @Feature({"Payments"})
-    public void testSkipUISlowApp()
-            throws InterruptedException, ExecutionException, TimeoutException {
-        mRule.installPaymentApp("basic-card", PaymentRequestTestRule.HAVE_INSTRUMENTS,
-                PaymentRequestTestRule.DELAYED_RESPONSE, PaymentRequestTestRule.DELAYED_CREATION);
-        mRule.openPage();
-        mRule.executeJavaScriptAndWaitForResult("create();");
-        mRule.enableSkipUIForBasicCard();
-
-        mRule.openPageAndClickNodeAndWait("buy", mRule.getDismissed());
-
-        mRule.expectResultContains(new String[] {"\"total\":\"1.00\""});
-    }
-}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowPromiseInvalidDetailsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowPromiseInvalidDetailsTest.java
deleted file mode 100644
index 8276c2cd..0000000
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowPromiseInvalidDetailsTest.java
+++ /dev/null
@@ -1,49 +0,0 @@
-// 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.
-
-package org.chromium.chrome.browser.payments;
-
-import android.support.test.filters.MediumTest;
-
-import org.junit.ClassRule;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.Feature;
-import org.chromium.chrome.browser.ChromeSwitches;
-import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
-import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
-
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeoutException;
-
-/**
- * A payment integration test for the show promise that resolves with invalid details.
- */
-@RunWith(ChromeJUnit4ClassRunner.class)
-@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
-public class PaymentRequestShowPromiseInvalidDetailsTest implements MainActivityStartCallback {
-    // Disable animations to reduce flakiness.
-    @ClassRule
-    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
-
-    @Rule
-    public PaymentRequestTestRule mRule =
-            new PaymentRequestTestRule("show_promise/invalid_details.html", this);
-
-    @Override
-    public void onMainActivityStarted()
-            throws InterruptedException, ExecutionException, TimeoutException {}
-
-    @Test
-    @MediumTest
-    @Feature({"Payments"})
-    public void testReject() throws InterruptedException, ExecutionException, TimeoutException {
-        mRule.openPageAndClickNodeAndWait("buy", mRule.getDismissed());
-        mRule.expectResultContains(new String[] {"Total amount value should be non-negative"});
-    }
-}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowPromiseRejectTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowPromiseRejectTest.java
deleted file mode 100644
index 14c3932..0000000
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowPromiseRejectTest.java
+++ /dev/null
@@ -1,51 +0,0 @@
-// 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.
-
-package org.chromium.chrome.browser.payments;
-
-import android.support.test.filters.MediumTest;
-
-import org.junit.ClassRule;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.Feature;
-import org.chromium.chrome.browser.ChromeSwitches;
-import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
-import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
-
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeoutException;
-
-/**
- * A payment integration test for the show promise that is rejected.
- */
-@RunWith(ChromeJUnit4ClassRunner.class)
-@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
-public class PaymentRequestShowPromiseRejectTest implements MainActivityStartCallback {
-    // Disable animations to reduce flakiness.
-    @ClassRule
-    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
-
-    @Rule
-    public PaymentRequestTestRule mRule =
-            new PaymentRequestTestRule("show_promise/reject.html", this);
-
-    @Override
-    public void onMainActivityStarted()
-            throws InterruptedException, ExecutionException, TimeoutException {}
-
-    @Test
-    @MediumTest
-    @Feature({"Payments"})
-    public void testReject() throws InterruptedException, ExecutionException, TimeoutException {
-        mRule.installPaymentApp("basic-card", PaymentRequestTestRule.HAVE_INSTRUMENTS,
-                PaymentRequestTestRule.IMMEDIATE_RESPONSE);
-        mRule.openPageAndClickNodeAndWait("buy", mRule.getDismissed());
-        mRule.expectResultContains(new String[] {"AbortError"});
-    }
-}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowPromiseSingleOptionShippingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowPromiseSingleOptionShippingTest.java
deleted file mode 100644
index 0cb7fea..0000000
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowPromiseSingleOptionShippingTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-// 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.
-
-package org.chromium.chrome.browser.payments;
-
-import android.support.test.filters.MediumTest;
-
-import org.junit.Assert;
-import org.junit.ClassRule;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.Feature;
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeSwitches;
-import org.chromium.chrome.browser.autofill.AutofillTestHelper;
-import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
-import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
-import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
-
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeoutException;
-
-/**
- * A payment integration test for the show promise with a single pre-selected shipping option and no
- * shipping address change handler.
- */
-@RunWith(ChromeJUnit4ClassRunner.class)
-@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
-public class PaymentRequestShowPromiseSingleOptionShippingTest
-        implements MainActivityStartCallback {
-    // Disable animations to reduce flakiness.
-    @ClassRule
-    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
-
-    @Rule
-    public PaymentRequestTestRule mRule =
-            new PaymentRequestTestRule("show_promise/single_option_shipping.html", this);
-
-    @Override
-    public void onMainActivityStarted()
-            throws InterruptedException, ExecutionException, TimeoutException {
-        AutofillTestHelper autofillTestHelper = new AutofillTestHelper();
-        autofillTestHelper.setProfile(new AutofillProfile("", "https://example.com", true,
-                "Jon Doe", "Google", "340 Main St", "California", "Los Angeles", "", "90291", "",
-                "US", "555-222-2222", "", "en-US"));
-        autofillTestHelper.setProfile(new AutofillProfile("", "https://example.com", true,
-                "Jane Smith", "Google", "340 Main St", "California", "Los Angeles", "", "90291", "",
-                "US", "555-111-1111", "", "en-US"));
-    }
-
-    @Test
-    @MediumTest
-    @Feature({"Payments"})
-    public void testFastApp() throws InterruptedException, ExecutionException, TimeoutException {
-        mRule.installPaymentApp("basic-card", PaymentRequestTestRule.HAVE_INSTRUMENTS,
-                PaymentRequestTestRule.IMMEDIATE_RESPONSE);
-        mRule.triggerUIAndWait(mRule.getReadyToPay());
-        Assert.assertEquals("USD $1.00", mRule.getOrderSummaryTotal());
-        Assert.assertEquals("$0.00", mRule.getShippingOptionCostSummaryOnBottomSheet());
-        mRule.clickInShippingAddressAndWait(R.id.payments_section, mRule.getReadyForInput());
-        mRule.clickOnShippingAddressSuggestionOptionAndWait(1, mRule.getReadyForInput());
-        mRule.clickAndWait(R.id.button_primary, mRule.getDismissed());
-        mRule.expectResultContains(new String[] {"\"total\":\"1.00\""});
-    }
-
-    @Test
-    @MediumTest
-    @Feature({"Payments"})
-    public void testSlowApp() throws InterruptedException, ExecutionException, TimeoutException {
-        mRule.installPaymentApp("basic-card", PaymentRequestTestRule.HAVE_INSTRUMENTS,
-                PaymentRequestTestRule.DELAYED_RESPONSE, PaymentRequestTestRule.DELAYED_CREATION);
-        mRule.triggerUIAndWait(mRule.getReadyToPay());
-        Assert.assertEquals("USD $1.00", mRule.getOrderSummaryTotal());
-        Assert.assertEquals("$0.00", mRule.getShippingOptionCostSummaryOnBottomSheet());
-        mRule.clickInShippingAddressAndWait(R.id.payments_section, mRule.getReadyForInput());
-        mRule.clickOnShippingAddressSuggestionOptionAndWait(1, mRule.getReadyForInput());
-        mRule.clickAndWait(R.id.button_primary, mRule.getDismissed());
-        mRule.expectResultContains(new String[] {"\"total\":\"1.00\""});
-    }
-}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowPromiseSingleOptionShippingWithUpdateTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowPromiseSingleOptionShippingWithUpdateTest.java
deleted file mode 100644
index 3b8cedf..0000000
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowPromiseSingleOptionShippingWithUpdateTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-// 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.
-
-package org.chromium.chrome.browser.payments;
-
-import android.support.test.filters.MediumTest;
-
-import org.junit.Assert;
-import org.junit.ClassRule;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.Feature;
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeSwitches;
-import org.chromium.chrome.browser.autofill.AutofillTestHelper;
-import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
-import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
-import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
-
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeoutException;
-
-/**
- * A payment integration test for the show promise with a single pre-selected shipping option and a
- * shipping address change handler.
- */
-@RunWith(ChromeJUnit4ClassRunner.class)
-@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
-public class PaymentRequestShowPromiseSingleOptionShippingWithUpdateTest
-        implements MainActivityStartCallback {
-    // Disable animations to reduce flakiness.
-    @ClassRule
-    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
-
-    @Rule
-    public PaymentRequestTestRule mRule = new PaymentRequestTestRule(
-            "show_promise/single_option_shipping_with_update.html", this);
-
-    @Override
-    public void onMainActivityStarted()
-            throws InterruptedException, ExecutionException, TimeoutException {
-        AutofillTestHelper autofillTestHelper = new AutofillTestHelper();
-        autofillTestHelper.setProfile(new AutofillProfile("", "https://example.com", true,
-                "Jon Doe", "Google", "340 Main St", "California", "Los Angeles", "", "90291", "",
-                "US", "555-222-2222", "", "en-US"));
-        autofillTestHelper.setProfile(new AutofillProfile("", "https://example.com", true,
-                "Jane Smith", "Google", "340 Main St", "California", "Los Angeles", "", "90291", "",
-                "US", "555-111-1111", "", "en-US"));
-    }
-
-    @Test
-    @MediumTest
-    @Feature({"Payments"})
-    public void testFastApp() throws InterruptedException, ExecutionException, TimeoutException {
-        mRule.installPaymentApp("basic-card", PaymentRequestTestRule.HAVE_INSTRUMENTS,
-                PaymentRequestTestRule.IMMEDIATE_RESPONSE);
-        mRule.triggerUIAndWait(mRule.getReadyToPay());
-        Assert.assertEquals("USD $1.00", mRule.getOrderSummaryTotal());
-        Assert.assertEquals("$0.00", mRule.getShippingOptionCostSummaryOnBottomSheet());
-        mRule.clickInShippingAddressAndWait(R.id.payments_section, mRule.getReadyForInput());
-        mRule.clickOnShippingAddressSuggestionOptionAndWait(1, mRule.getReadyForInput());
-        mRule.clickAndWait(R.id.button_primary, mRule.getDismissed());
-        mRule.expectResultContains(new String[] {"\"total\":\"1.00\""});
-    }
-
-    @Test
-    @MediumTest
-    @Feature({"Payments"})
-    public void testSlowApp() throws InterruptedException, ExecutionException, TimeoutException {
-        mRule.installPaymentApp("basic-card", PaymentRequestTestRule.HAVE_INSTRUMENTS,
-                PaymentRequestTestRule.DELAYED_RESPONSE, PaymentRequestTestRule.DELAYED_CREATION);
-        mRule.triggerUIAndWait(mRule.getReadyToPay());
-        Assert.assertEquals("USD $1.00", mRule.getOrderSummaryTotal());
-        Assert.assertEquals("$0.00", mRule.getShippingOptionCostSummaryOnBottomSheet());
-        mRule.clickInShippingAddressAndWait(R.id.payments_section, mRule.getReadyForInput());
-        mRule.clickOnShippingAddressSuggestionOptionAndWait(1, mRule.getReadyForInput());
-        mRule.clickAndWait(R.id.button_primary, mRule.getDismissed());
-        mRule.expectResultContains(new String[] {"\"total\":\"1.00\""});
-    }
-}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowPromiseUSOnlyShippingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowPromiseUSOnlyShippingTest.java
deleted file mode 100644
index a2cb36d..0000000
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowPromiseUSOnlyShippingTest.java
+++ /dev/null
@@ -1,122 +0,0 @@
-// 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.
-
-package org.chromium.chrome.browser.payments;
-
-import android.support.test.filters.MediumTest;
-
-import org.junit.Assert;
-import org.junit.ClassRule;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.Feature;
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeSwitches;
-import org.chromium.chrome.browser.autofill.AutofillTestHelper;
-import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
-import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
-import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
-
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeoutException;
-
-/**
- * A payment integration test for the show promise with restricted shipping rules.
- */
-@RunWith(ChromeJUnit4ClassRunner.class)
-@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
-public class PaymentRequestShowPromiseUSOnlyShippingTest implements MainActivityStartCallback {
-    // Disable animations to reduce flakiness.
-    @ClassRule
-    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
-
-    @Rule
-    public PaymentRequestTestRule mRule =
-            new PaymentRequestTestRule("show_promise/us_only_shipping.html", this);
-
-    @Override
-    public void onMainActivityStarted()
-            throws InterruptedException, ExecutionException, TimeoutException {}
-
-    @Test
-    @MediumTest
-    @Feature({"Payments"})
-    public void testCannotShipWithFastApp()
-            throws InterruptedException, ExecutionException, TimeoutException {
-        mRule.installPaymentApp("basic-card", PaymentRequestTestRule.HAVE_INSTRUMENTS,
-                PaymentRequestTestRule.IMMEDIATE_RESPONSE);
-        runCannotShipTest();
-    }
-
-    @Test
-    @MediumTest
-    @Feature({"Payments"})
-    public void testCannotShipWithSlowApp()
-            throws InterruptedException, ExecutionException, TimeoutException {
-        mRule.installPaymentApp("basic-card", PaymentRequestTestRule.HAVE_INSTRUMENTS,
-                PaymentRequestTestRule.DELAYED_RESPONSE, PaymentRequestTestRule.DELAYED_CREATION);
-        runCannotShipTest();
-    }
-
-    private void runCannotShipTest()
-            throws InterruptedException, ExecutionException, TimeoutException {
-        AutofillTestHelper autofillTestHelper = new AutofillTestHelper();
-        autofillTestHelper.setProfile(new AutofillProfile("", "https://example.com", true,
-                "Jon Doe", "Google", "51 Breithaupt St", "ON", "Kitchener", "", "N2H 5G5", "", "CA",
-                "555-222-2222", "", "en-CA"));
-        mRule.triggerUIAndWait(mRule.getReadyForInput());
-        Assert.assertEquals("USD $1.00", mRule.getOrderSummaryTotal());
-        mRule.clickInShippingAddressAndWait(R.id.payments_section, mRule.getReadyForInput());
-        Assert.assertEquals("To see shipping methods and requirements, select an address",
-                mRule.getShippingAddressDescriptionLabel());
-        Assert.assertEquals(null, mRule.getShippingAddressWarningLabel());
-        mRule.clickOnShippingAddressSuggestionOptionAndWait(0, mRule.getReadyForInput());
-        Assert.assertEquals(null, mRule.getShippingAddressDescriptionLabel());
-        Assert.assertEquals("Cannot ship outside of US.", mRule.getShippingAddressWarningLabel());
-        mRule.clickAndWait(R.id.button_secondary, mRule.getDismissed());
-    }
-
-    @Test
-    @MediumTest
-    @Feature({"Payments"})
-    public void testCanShipWithFastApp()
-            throws InterruptedException, ExecutionException, TimeoutException {
-        mRule.installPaymentApp("basic-card", PaymentRequestTestRule.HAVE_INSTRUMENTS,
-                PaymentRequestTestRule.IMMEDIATE_RESPONSE);
-        runCanShipTest();
-    }
-
-    @Test
-    @MediumTest
-    @Feature({"Payments"})
-    public void testCanShipWithSlowApp()
-            throws InterruptedException, ExecutionException, TimeoutException {
-        mRule.installPaymentApp("basic-card", PaymentRequestTestRule.HAVE_INSTRUMENTS,
-                PaymentRequestTestRule.DELAYED_RESPONSE, PaymentRequestTestRule.DELAYED_CREATION);
-        runCanShipTest();
-    }
-
-    private void runCanShipTest()
-            throws InterruptedException, ExecutionException, TimeoutException {
-        AutofillTestHelper autofillTestHelper = new AutofillTestHelper();
-        autofillTestHelper.setProfile(new AutofillProfile("", "https://example.com", true,
-                "Jane Smith", "Google", "340 Main St", "California", "Los Angeles", "", "90291", "",
-                "US", "555-111-1111", "", "en-US"));
-        mRule.triggerUIAndWait(mRule.getReadyForInput());
-        Assert.assertEquals("USD $1.00", mRule.getOrderSummaryTotal());
-        mRule.clickInShippingAddressAndWait(R.id.payments_section, mRule.getReadyForInput());
-        Assert.assertEquals("To see shipping methods and requirements, select an address",
-                mRule.getShippingAddressDescriptionLabel());
-        Assert.assertEquals(null, mRule.getShippingAddressWarningLabel());
-        mRule.clickOnShippingAddressSuggestionOptionAndWait(0, mRule.getReadyToPay());
-        Assert.assertEquals(null, mRule.getShippingAddressDescriptionLabel());
-        Assert.assertEquals(null, mRule.getShippingAddressWarningLabel());
-        mRule.clickAndWait(R.id.button_primary, mRule.getDismissed());
-        mRule.expectResultContains(new String[] {"\"total\":\"1.00\""});
-    }
-}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowPromiseUnsupportedTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowPromiseUnsupportedTest.java
deleted file mode 100644
index 4e34e1c..0000000
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowPromiseUnsupportedTest.java
+++ /dev/null
@@ -1,50 +0,0 @@
-// 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.
-
-package org.chromium.chrome.browser.payments;
-
-import android.support.test.filters.MediumTest;
-
-import org.junit.ClassRule;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.Feature;
-import org.chromium.chrome.browser.ChromeSwitches;
-import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
-import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.chrome.test.ui.DisableAnimationsTestRule;
-
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeoutException;
-
-/**
- * A payment integration test for the show promise with an unsupported payment method.
- */
-@RunWith(ChromeJUnit4ClassRunner.class)
-@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
-public class PaymentRequestShowPromiseUnsupportedTest implements MainActivityStartCallback {
-    // Disable animations to reduce flakiness.
-    @ClassRule
-    public static DisableAnimationsTestRule sNoAnimationsRule = new DisableAnimationsTestRule();
-
-    @Rule
-    public PaymentRequestTestRule mRule =
-            new PaymentRequestTestRule("show_promise/unsupported.html", this);
-
-    @Override
-    public void onMainActivityStarted()
-            throws InterruptedException, ExecutionException, TimeoutException {}
-
-    @Test
-    @MediumTest
-    @Feature({"Payments"})
-    public void testReject() throws InterruptedException, ExecutionException, TimeoutException {
-        mRule.openPageAndClickNodeAndWait("buy", mRule.getDismissed());
-        mRule.expectResultContains(
-                new String[] {"NotSupportedError: The payment method \"foo\" is not supported"});
-    }
-}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestRule.java
index c6329db..42ca009 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestRule.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestRule.java
@@ -12,7 +12,6 @@
 import android.widget.CheckBox;
 import android.widget.EditText;
 import android.widget.Spinner;
-import android.widget.TextView;
 
 import org.junit.Assert;
 import org.junit.runner.Description;
@@ -118,7 +117,6 @@
     final CallbackHelper mHasEnrolledInstrumentQueryResponded;
     final CallbackHelper mExpirationMonthChange;
     final CallbackHelper mPaymentResponseReady;
-    PaymentRequestImpl mPaymentRequest;
     PaymentRequestUI mUI;
 
     private final AtomicReference<WebContents> mWebContentsRef;
@@ -165,7 +163,7 @@
         startMainActivityWithURL(mTestFilePath);
     }
 
-    protected void openPage() throws InterruptedException, ExecutionException, TimeoutException {
+    private void openPage() throws InterruptedException, ExecutionException, TimeoutException {
         onMainActivityStarted();
         ThreadUtils.runOnUiThreadBlocking(() -> {
             mWebContentsRef.set(getActivity().getCurrentWebContents());
@@ -279,11 +277,6 @@
         helper.waitForCallback(callCount);
     }
 
-    protected String executeJavaScriptAndWaitForResult(String script)
-            throws InterruptedException, TimeoutException {
-        return JavaScriptUtils.executeJavaScriptAndWaitForResult(mWebContentsRef.get(), script);
-    }
-
     /** Clicks on an HTML node. */
     protected void clickNodeAndWait(String nodeId, CallbackHelper helper)
             throws InterruptedException, TimeoutException {
@@ -501,24 +494,6 @@
                 .toString());
     }
 
-    protected String getShippingAddressWarningLabel() throws ExecutionException {
-        return ThreadUtils.runOnUiThreadBlocking(() -> {
-            View view = mUI.getShippingAddressSectionForTest().findViewById(
-                    R.id.payments_warning_label);
-            return view != null && view instanceof TextView ? ((TextView) view).getText().toString()
-                                                            : null;
-        });
-    }
-
-    protected String getShippingAddressDescriptionLabel() throws ExecutionException {
-        return ThreadUtils.runOnUiThreadBlocking(() -> {
-            View view = mUI.getShippingAddressSectionForTest().findViewById(
-                    R.id.payments_description_label);
-            return view != null && view instanceof TextView ? ((TextView) view).getText().toString()
-                                                            : null;
-        });
-    }
-
     /** Returns the focused view in the card editor view. */
     protected View getCardEditorFocusedView() {
         return mUI.getCardEditorDialog().getCurrentFocus();
@@ -792,8 +767,8 @@
                     }
                     for (int i = 0; i < contents.length; i++) {
                         if (!result.contains(contents[i])) {
-                            updateFailureReason(String.format(
-                                    "Result '" + result + "' should contain '%s'", contents[i]));
+                            updateFailureReason(
+                                    String.format("Result should contain '%s'", contents[i]));
                             return false;
                         }
                     }
@@ -889,12 +864,6 @@
                                    .findViewById(R.id.autofill_card_unmask_prompt));
     }
 
-    /** Allows to skip UI into paymenthandler for"basic-card". */
-    protected void enableSkipUIForBasicCard() {
-        ThreadUtils.runOnUiThreadBlocking(
-                () -> mPaymentRequest.setSkipUIForNonURLPaymentMethodIdentifiersForTest());
-    }
-
     @Override
     public void onPaymentRequestReadyForInput(PaymentRequestUI ui) {
         ThreadUtils.assertOnUiThread();
@@ -944,12 +913,6 @@
     }
 
     @Override
-    public void onPaymentRequestCreated(PaymentRequestImpl paymentRequest) {
-        ThreadUtils.assertOnUiThread();
-        mPaymentRequest = paymentRequest;
-    }
-
-    @Override
     public void onPaymentRequestServiceUnableToAbort() {
         ThreadUtils.assertOnUiThread();
         mUnableToAbort.notifyCalled();
@@ -1174,8 +1137,7 @@
                 Map<String, PaymentMethodData> methodData, PaymentItem total,
                 List<PaymentItem> displayItems, Map<String, PaymentDetailsModifier> modifiers,
                 InstrumentDetailsCallback detailsCallback) {
-            detailsCallback.onInstrumentDetailsReady(mDefaultMethodName,
-                    "{\"transaction\": 1337, \"total\": \"" + total.amount.value + "\"}");
+            detailsCallback.onInstrumentDetailsReady(mDefaultMethodName, "{\"transaction\": 1337}");
         }
 
         @Override
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfAndroidBridgeTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfAndroidBridgeTest.java
index fc3eb71..1a40702 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfAndroidBridgeTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfAndroidBridgeTest.java
@@ -133,9 +133,9 @@
     @SmallTest
     public void testIsFeatureAvailable() {
         boolean expected = true;
-        when(mNativeMock.isFeatureAvailable(eq(mProfile), eq(mWebContents))).thenReturn(expected);
+        when(mNativeMock.isFeatureAvailable(eq(mWebContents))).thenReturn(expected);
 
-        boolean actual = SendTabToSelfAndroidBridge.isFeatureAvailable(mProfile, mWebContents);
+        boolean actual = SendTabToSelfAndroidBridge.isFeatureAvailable(mWebContents);
         Assert.assertEquals(expected, actual);
     }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfShareActivityTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfShareActivityTest.java
index 3a0472a3..1894a26 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfShareActivityTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfShareActivityTest.java
@@ -76,9 +76,8 @@
     @SmallTest
     public void testIsFeatureAvailable() {
         boolean expected = true;
-        when(mTab.getProfile()).thenReturn(mProfile);
         when(mTab.getWebContents()).thenReturn(mWebContents);
-        when(mNativeMock.isFeatureAvailable(eq(mProfile), eq(mWebContents))).thenReturn(expected);
+        when(mNativeMock.isFeatureAvailable(eq(mWebContents))).thenReturn(expected);
 
         boolean actual = SendTabToSelfShareActivity.featureIsAvailable(mTab);
         Assert.assertEquals(expected, actual);
diff --git a/chrome/app/chrome_command_ids.h b/chrome/app/chrome_command_ids.h
index 1b21958..b96c8bb 100644
--- a/chrome/app/chrome_command_ids.h
+++ b/chrome/app/chrome_command_ids.h
@@ -93,6 +93,7 @@
 #define IDC_MIGRATE_LOCAL_CREDIT_CARD_FOR_PAGE 35014
 #define IDC_SEND_TAB_TO_SELF            35015
 #define IDC_FOCUS_THIS_TAB              35016
+#define IDC_CONTENT_LINK_SEND_TAB_TO_SELF 35017
 
 // Clipboard commands
 #define IDC_CUT                         36000
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index af62d48..1d60c07 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -6273,11 +6273,17 @@
         <message name="IDS_CONTEXT_MENU_SEND_TAB_TO_SELF" desc="The label of item for share this tab to other devices in different context menus.">
           Send to your devices
         </message>
+        <message name="IDS_LINK_MENU_SEND_TAB_TO_SELF" desc="The label of item for share this tab to other devices in content area link right click menu.">
+          Send link to your devices
+        </message>
       </if>
       <if expr="use_titlecase">
         <message name="IDS_CONTEXT_MENU_SEND_TAB_TO_SELF" desc="In Title Case: The label of item for share this tab to other devices in different context menus.">
           Send to Your Devices
         </message>
+        <message name="IDS_LINK_MENU_SEND_TAB_TO_SELF" desc="In Title Case: The label of item for share this tab to other devices in content area link right click menu.">
+          Send Link to Your Devices
+        </message>
       </if>
 
 
diff --git a/chrome/app/generated_resources_grd/IDS_LINK_MENU_SEND_TAB_TO_SELF.png.sha1 b/chrome/app/generated_resources_grd/IDS_LINK_MENU_SEND_TAB_TO_SELF.png.sha1
new file mode 100644
index 0000000..1cedebc
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_LINK_MENU_SEND_TAB_TO_SELF.png.sha1
@@ -0,0 +1 @@
+f0db35e017cf5ac9341ff80d414b70f8ec4cb674
\ No newline at end of file
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 69793ca..7aa9dae 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1457,10 +1457,6 @@
      flag_descriptions::kShowAutofillSignaturesName,
      flag_descriptions::kShowAutofillSignaturesDescription, kOsAll,
      SINGLE_VALUE_TYPE(autofill::switches::kShowAutofillSignatures)},
-    {"AffiliationBasedMatching",
-     flag_descriptions::kAffiliationBasedMatchingName,
-     flag_descriptions::kAffiliationBasedMatchingDescription, kOsAll,
-     FEATURE_VALUE_TYPE(password_manager::features::kAffiliationBasedMatching)},
     {"wallet-service-use-sandbox",
      flag_descriptions::kWalletServiceUseSandboxName,
      flag_descriptions::kWalletServiceUseSandboxDescription,
@@ -2318,6 +2314,10 @@
     {"arc-boot-completed-broadcast", flag_descriptions::kArcBootCompleted,
      flag_descriptions::kArcBootCompletedDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(arc::kBootCompletedBroadcastFeature)},
+    {"arc-custom-tabs-experiment",
+     flag_descriptions::kArcCustomTabsExperimentName,
+     flag_descriptions::kArcCustomTabsExperimentDescription, kOsCrOS,
+     FEATURE_VALUE_TYPE(arc::kCustomTabsExperimentFeature)},
     {"arc-documents-provider", flag_descriptions::kArcDocumentsProviderName,
      flag_descriptions::kArcDocumentsProviderDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(arc::kEnableDocumentsProviderInFilesAppFeature)},
diff --git a/chrome/browser/android/autofill_assistant/client_android.cc b/chrome/browser/android/autofill_assistant/client_android.cc
index 06f15c8..f15e122d 100644
--- a/chrome/browser/android/autofill_assistant/client_android.cc
+++ b/chrome/browser/android/autofill_assistant/client_android.cc
@@ -118,13 +118,17 @@
 void ClientAndroid::Start(JNIEnv* env,
                           const JavaParamRef<jobject>& jcaller,
                           const JavaParamRef<jstring>& jinitial_url,
+                          const JavaParamRef<jstring>& jexperiment_ids,
                           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);
+  controller_->Start(initial_url, std::make_unique<TriggerContext>(
+                                      std::move(parameters),
+                                      base::android::ConvertJavaStringToUTF8(
+                                          env, jexperiment_ids)));
 }
 
 void ClientAndroid::DestroyUI(
diff --git a/chrome/browser/android/autofill_assistant/client_android.h b/chrome/browser/android/autofill_assistant/client_android.h
index 649ad7bd..f7c492a 100644
--- a/chrome/browser/android/autofill_assistant/client_android.h
+++ b/chrome/browser/android/autofill_assistant/client_android.h
@@ -46,6 +46,7 @@
   void Start(JNIEnv* env,
              const base::android::JavaParamRef<jobject>& jcaller,
              const base::android::JavaParamRef<jstring>& jinitial_url,
+             const base::android::JavaParamRef<jstring>& jexperiment_ids,
              const base::android::JavaParamRef<jobjectArray>& parameterNames,
              const base::android::JavaParamRef<jobjectArray>& parameterValues);
   void DestroyUI(JNIEnv* env,
diff --git a/chrome/browser/android/send_tab_to_self/send_tab_to_self_android_bridge.cc b/chrome/browser/android/send_tab_to_self/send_tab_to_self_android_bridge.cc
index 34ceec097..9a06016 100644
--- a/chrome/browser/android/send_tab_to_self/send_tab_to_self_android_bridge.cc
+++ b/chrome/browser/android/send_tab_to_self/send_tab_to_self_android_bridge.cc
@@ -167,17 +167,14 @@
   }
 }
 
-// Returns whether the feature is available for the specified |profile| and
-// |web_contents|.
+// Returns whether the feature is available for the specified |web_contents|.
 static jboolean JNI_SendTabToSelfAndroidBridge_IsFeatureAvailable(
     JNIEnv* env,
-    const JavaParamRef<jobject>& j_profile,
     const JavaParamRef<jobject>& j_web_contents) {
-  Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
   content::WebContents* web_contents =
       content::WebContents::FromJavaWebContents(j_web_contents);
 
-  return ShouldOfferFeature(profile, web_contents);
+  return ShouldOfferFeature(web_contents);
 }
 
 }  // namespace send_tab_to_self
diff --git a/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl_unittest.cc b/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl_unittest.cc
index 105e26b..329eb2f 100644
--- a/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl_unittest.cc
+++ b/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl_unittest.cc
@@ -234,6 +234,7 @@
     fake_cookie_manager_->InvokePendingDeleteCookiesCallback(
         app_url, "cros_migrated_to" /* expected_cookie_name */,
         true /* success */);
+    base::RunLoop().RunUntilIdle();
 
     // If the PWA was not already installed at the URL, SetUpApp() should
     // install it.
@@ -287,6 +288,7 @@
         app_url, install_url, migrated_to_app_url,
         base::BindOnce(&AndroidSmsAppSetupControllerImplTest::OnRemoveAppResult,
                        base::Unretained(this), run_loop.QuitClosure()));
+    base::RunLoop().RunUntilIdle();
 
     // If the PWA was already installed at the URL, RemoveApp() should uninstall
     // the it.
@@ -304,6 +306,7 @@
       fake_cookie_manager_->InvokePendingDeleteCookiesCallback(
           app_url, "default_to_persist" /* expected_cookie_name */,
           true /* success */);
+      base::RunLoop().RunUntilIdle();
     }
 
     if (num_expected_app_uninstalls) {
diff --git a/chrome/browser/chromeos/arc/arc_service_launcher.cc b/chrome/browser/chromeos/arc/arc_service_launcher.cc
index 5d02a4707..6255b645 100644
--- a/chrome/browser/chromeos/arc/arc_service_launcher.cc
+++ b/chrome/browser/chromeos/arc/arc_service_launcher.cc
@@ -45,6 +45,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/arc/arc_usb_host_permission_manager.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
+#include "chrome/common/channel_info.h"
 #include "components/arc/app_permissions/arc_app_permissions_bridge.h"
 #include "components/arc/appfuse/arc_appfuse_bridge.h"
 #include "components/arc/arc_service_manager.h"
@@ -88,7 +89,8 @@
           std::make_unique<ArcSessionRunner>(
               base::BindRepeating(ArcSession::Create,
                                   arc_service_manager_->arc_bridge_service(),
-                                  &default_scale_factor_retriever_)))) {
+                                  &default_scale_factor_retriever_,
+                                  chrome::GetChannel())))) {
   DCHECK(g_arc_service_launcher == nullptr);
   g_arc_service_launcher = this;
 
@@ -224,7 +226,7 @@
   arc_session_manager_ = std::make_unique<ArcSessionManager>(
       std::make_unique<ArcSessionRunner>(base::BindRepeating(
           ArcSession::Create, arc_service_manager_->arc_bridge_service(),
-          &default_scale_factor_retriever_)));
+          &default_scale_factor_retriever_, chrome::GetChannel())));
 }
 
 }  // namespace arc
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
index fad5b49cb..07e22cf5 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/chromeos/file_manager/file_manager_string_util.h"
 #include "chrome/browser/chromeos/file_manager/open_with_browser.h"
 #include "chrome/browser/chromeos/login/demo_mode/demo_session.h"
+#include "chrome/browser/chromeos/plugin_vm/plugin_vm_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/grit/generated_resources.h"
 #include "chromeos/constants/chromeos_features.h"
@@ -55,6 +56,11 @@
   dict->SetBoolean(
       "MY_FILES_VOLUME_ENABLED",
       base::FeatureList::IsEnabled(chromeos::features::kMyFilesVolume));
+  dict->SetBoolean("PLUGIN_VM_ENABLED",
+                   plugin_vm::IsPluginVmAllowedForProfile(
+                       Profile::FromBrowserContext(browser_context())) &&
+                       plugin_vm::IsPluginVmConfigured(
+                           Profile::FromBrowserContext(browser_context())));
   dict->SetString("UI_LOCALE", extension_l10n_util::CurrentLocaleOrDefault());
 
   return RespondNow(OneArgument(std::move(dict)));
diff --git a/chrome/browser/chromeos/file_manager/file_manager_string_util.cc b/chrome/browser/chromeos/file_manager/file_manager_string_util.cc
index 5b16632..c60f4467 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_string_util.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_string_util.cc
@@ -514,6 +514,10 @@
              IDS_FILE_BROWSER_FOLDER_SHARED_WITH_CROSTINI);
   SET_STRING("FOLDER_SHARED_WITH_CROSTINI_PLURAL",
              IDS_FILE_BROWSER_FOLDER_SHARED_WITH_CROSTINI_PLURAL);
+  SET_STRING("FOLDER_SHARED_WITH_PLUGIN_VM",
+             IDS_FILE_BROWSER_FOLDER_SHARED_WITH_PLUGIN_VM);
+  SET_STRING("FOLDER_SHARED_WITH_PLUGIN_VM_PLURAL",
+             IDS_FILE_BROWSER_FOLDER_SHARED_WITH_PLUGIN_VM_PLURAL);
   SET_STRING("FORMATTING_FINISHED_FAILURE_MESSAGE",
              IDS_FORMATTING_FINISHED_FAILURE_MESSAGE);
   SET_STRING("FORMATTING_FINISHED_SUCCESS_MESSAGE",
@@ -723,6 +727,10 @@
              IDS_FILE_BROWSER_SHARE_WITH_LINUX_BUTTON_LABEL);
   SET_STRING("MANAGE_LINUX_SHARING_BUTTON_LABEL",
              IDS_FILE_BROWSER_MANAGE_LINUX_SHARING_BUTTON_LABEL);
+  SET_STRING("SHARE_WITH_PLUGIN_VM_BUTTON_LABEL",
+             IDS_FILE_BROWSER_SHARE_WITH_PLUGIN_VM_BUTTON_LABEL);
+  SET_STRING("MANAGE_PLUGIN_VM_SHARING_BUTTON_LABEL",
+             IDS_FILE_BROWSER_MANAGE_PLUGIN_VM_SHARING_BUTTON_LABEL);
   SET_STRING("CHANGE_TO_LISTVIEW_BUTTON_LABEL",
              IDS_FILE_BROWSER_CHANGE_TO_LISTVIEW_BUTTON_LABEL);
   SET_STRING("CHANGE_TO_THUMBNAILVIEW_BUTTON_LABEL",
diff --git a/chrome/browser/chromeos/file_manager/file_manager_uitest.cc b/chrome/browser/chromeos/file_manager/file_manager_uitest.cc
index 09d8e2b..9476a97 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_uitest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_uitest.cc
@@ -87,6 +87,10 @@
   RunTest("menu");
 }
 
+IN_PROC_BROWSER_TEST_F(FileManagerUITest, PluginVmShare) {
+  RunTest("pluginVmShare");
+}
+
 IN_PROC_BROWSER_TEST_F(FileManagerUITest, ProgressCenter) {
   RunTest("progressCenter");
 }
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index cbc127ce..c04bfc8 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -29,11 +29,6 @@
 
 [
   {
-    "name": "AffiliationBasedMatching",
-    // "owners": [ "your-team" ],
-    "expiry_milestone": 76
-  },
-  {
     "name": "BundledConnectionHelp",
     "owners": [ "carlosil" ],
     "expiry_milestone": 76
@@ -109,6 +104,11 @@
     "expiry_milestone": 76
   },
   {
+    "name": "arc-custom-tabs-experiment",
+    "owners": [ "hashimoto" ],
+    "expiry_milestone": 76
+  },
+  {
     "name": "arc-documents-provider",
     "owners": [ "fukino" ],
     "expiry_milestone": 76
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 13ef88f4..41771ef4 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -18,12 +18,6 @@
 const char kAcceleratedVideoDecodeDescription[] =
     "Hardware-accelerated video decode where available.";
 
-const char kAffiliationBasedMatchingName[] =
-    "Affiliation based matching in password manager";
-const char kAffiliationBasedMatchingDescription[] =
-    "Allow credentials stored for Android applications to be filled into "
-    "corresponding websites.";
-
 const char kAllowInsecureLocalhostName[] =
     "Allow invalid certificates for resources loaded from localhost.";
 const char kAllowInsecureLocalhostDescription[] =
@@ -2960,6 +2954,12 @@
 const char kArcCupsApiDescription[] =
     "Enables support of libcups APIs from ARC";
 
+const char kArcCustomTabsExperimentName[] =
+    "Enable Custom Tabs experiment for ARC";
+const char kArcCustomTabsExperimentDescription[] =
+    "Allow Android apps to use Custom Tabs."
+    "This feature only works on the Canary and Dev channels.";
+
 const char kArcDocumentsProviderName[] = "ARC DocumentsProvider integration";
 const char kArcDocumentsProviderDescription[] =
     "Enables DocumentsProvider integration in Chrome OS Files app.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index b33d9be..10dde3a 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -45,9 +45,6 @@
 extern const char kAcceleratedVideoDecodeName[];
 extern const char kAcceleratedVideoDecodeDescription[];
 
-extern const char kAffiliationBasedMatchingName[];
-extern const char kAffiliationBasedMatchingDescription[];
-
 extern const char kAllowInsecureLocalhostName[];
 extern const char kAllowInsecureLocalhostDescription[];
 
@@ -1777,6 +1774,9 @@
 extern const char kArcCupsApiName[];
 extern const char kArcCupsApiDescription[];
 
+extern const char kArcCustomTabsExperimentName[];
+extern const char kArcCustomTabsExperimentDescription[];
+
 extern const char kArcDocumentsProviderName[];
 extern const char kArcDocumentsProviderDescription[];
 
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 796c1821..31e72753 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -1016,4 +1016,9 @@
   profile_prefs->ClearPref(kDismissedAssetDownloadSuggestions);
   profile_prefs->ClearPref(kDismissedOfflinePageDownloadSuggestions);
 #endif  // defined(OS_ANDROID)
+
+#if defined(OS_CHROMEOS)
+  // Added 4/2019.
+  syncer::ClearObsoleteSyncSpareBootstrapToken(profile_prefs);
+#endif  // defined(OS_CHROMEOS)
 }
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
index f9bb5a8..03a71f88 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -357,10 +357,11 @@
     {100, -1, IDC_CONTENT_CONTEXT_ACCESSIBILITY_LABELS_TOGGLE_ONCE},
     {101, -1, IDC_CONTENT_CONTEXT_ACCESSIBILITY_LABELS},
     {102, -1, IDC_SEND_TAB_TO_SELF},
+    {103, -1, IDC_CONTENT_LINK_SEND_TAB_TO_SELF},
     // Add new items here and use |enum_id| from the next line.
     // Also, add new items to RenderViewContextMenuItem enum in
     // tools/metrics/histograms/enums.xml.
-    {103, -1, 0},  // Must be the last. Increment |enum_id| when new IDC
+    {104, -1, 0},  // Must be the last. Increment |enum_id| when new IDC
                    // was added.
 };
 
@@ -1159,6 +1160,18 @@
       }
     }
 #endif  // !defined(OS_CHROMEOS)
+
+    if (browser && send_tab_to_self::ShouldOfferFeatureForLink(
+                       browser->tab_strip_model()->GetActiveWebContents(),
+                       params_.link_url)) {
+      send_tab_to_self::RecordSendTabToSelfClickResult(
+          send_tab_to_self::kLinkMenu, SendTabToSelfClickResult::kShowItem);
+      menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
+      menu_model_.AddItemWithStringIdAndIcon(IDC_CONTENT_LINK_SEND_TAB_TO_SELF,
+                                             IDS_LINK_MENU_SEND_TAB_TO_SELF,
+                                             *send_tab_to_self::GetImageSkia());
+    }
+
     menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVELINKAS,
                                     IDS_CONTENT_CONTEXT_SAVELINKAS);
@@ -1355,7 +1368,6 @@
 
   if (GetBrowser() &&
       send_tab_to_self::ShouldOfferFeature(
-          GetBrowser()->profile(),
           GetBrowser()->tab_strip_model()->GetActiveWebContents())) {
     send_tab_to_self::RecordSendTabToSelfClickResult(
         send_tab_to_self::kContentMenu, SendTabToSelfClickResult::kShowItem);
@@ -1821,6 +1833,11 @@
     case IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS:
     case IDC_SEND_TAB_TO_SELF:
       return true;
+
+    case IDC_CONTENT_LINK_SEND_TAB_TO_SELF:
+      return send_tab_to_self::IsContentRequirementsMet(
+          params_.link_url, GetBrowser()->profile());
+
     case IDC_CHECK_SPELLING_WHILE_TYPING:
       return prefs->GetBoolean(spellcheck::prefs::kSpellCheckEnable);
 
@@ -2036,7 +2053,14 @@
     case IDC_SEND_TAB_TO_SELF:
       send_tab_to_self::RecordSendTabToSelfClickResult(
           send_tab_to_self::kContentMenu, SendTabToSelfClickResult::kClickItem);
-      send_tab_to_self::CreateNewEntry(embedder_web_contents_, GetProfile());
+      send_tab_to_self::CreateNewEntry(embedder_web_contents_);
+      break;
+
+    case IDC_CONTENT_LINK_SEND_TAB_TO_SELF:
+      send_tab_to_self::RecordSendTabToSelfClickResult(
+          send_tab_to_self::kLinkMenu, SendTabToSelfClickResult::kClickItem);
+      send_tab_to_self::CreateNewEntry(embedder_web_contents_,
+                                       params_.link_url);
       break;
 
     case IDC_RELOAD:
diff --git a/chrome/browser/resource_coordinator/tab_metrics_logger_unittest.cc b/chrome/browser/resource_coordinator/tab_metrics_logger_unittest.cc
index b4b2d0a..c2395c38 100644
--- a/chrome/browser/resource_coordinator/tab_metrics_logger_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_metrics_logger_unittest.cc
@@ -154,14 +154,15 @@
   }
 };
 
-// Tests has_form_entry.
-// TODO(crbug.com/949288): The test is flaky on ChromeOS.
+// TODO(crbug.com/949288, crbug.com/950244): All tests are flaky on ChromeOS
 #if defined(OS_CHROMEOS)
-#define MAYBE_GetHasFormEntry DISABLED_GetHasFormEntry
+#define MAYBE_(test) DISABLED_##test
 #else
-#define MAYBE_GetHasFormEntry GetHasFormEntry
+#define MAYBE_(test) test
 #endif
-TEST_F(TabMetricsLoggerTest, MAYBE_GetHasFormEntry) {
+
+// Tests has_form_entry.
+TEST_F(TabMetricsLoggerTest, MAYBE_(GetHasFormEntry)) {
   EXPECT_FALSE(CurrentTabFeatures().has_form_entry);
   content::PageImportanceSignals signal;
   signal.had_form_interaction = true;
@@ -170,14 +171,14 @@
 }
 
 // Tests is_pinned.
-TEST_F(TabMetricsLoggerTest, GetPinState) {
+TEST_F(TabMetricsLoggerTest, MAYBE_(GetPinState)) {
   EXPECT_FALSE(CurrentTabFeatures().is_pinned);
   tab_strip_model_->SetTabPinned(0, true);
   EXPECT_TRUE(CurrentTabFeatures().is_pinned);
 }
 
 // Tests navigation_entry_count.
-TEST_F(TabMetricsLoggerTest, GetNavigationEntryCount) {
+TEST_F(TabMetricsLoggerTest, MAYBE_(GetNavigationEntryCount)) {
   EXPECT_EQ(CurrentTabFeatures().navigation_entry_count, 1);
   tab_activity_simulator_.Navigate(web_contents_, GURL(kExampleUrl),
                                    pg_metrics_.page_transition);
@@ -188,7 +189,7 @@
 }
 
 // Tests site_engagement_score.
-TEST_F(TabMetricsLoggerTest, GetSiteEngagementScore) {
+TEST_F(TabMetricsLoggerTest, MAYBE_(GetSiteEngagementScore)) {
   EXPECT_EQ(CurrentTabFeatures().site_engagement_score, 0);
   SiteEngagementService::Get(profile())->ResetBaseScoreForURL(
       GURL(kChromiumUrl), 91);
@@ -196,20 +197,20 @@
 }
 
 // Tests was_recently_audible.
-TEST_F(TabMetricsLoggerTest, GetAudibleState) {
+TEST_F(TabMetricsLoggerTest, MAYBE_(GetAudibleState)) {
   EXPECT_FALSE(CurrentTabFeatures().was_recently_audible);
   web_contents_tester_->SetIsCurrentlyAudible(true);
   EXPECT_TRUE(CurrentTabFeatures().was_recently_audible);
 }
 
 // Tests host.
-TEST_F(TabMetricsLoggerTest, GetHost) {
+TEST_F(TabMetricsLoggerTest, MAYBE_(GetHost)) {
   EXPECT_EQ(CurrentTabFeatures().host, kChromiumDomain);
 }
 
 // Tests creating a flat TabFeatures structure for logging a tab and its
 // TabMetrics state.
-TEST_F(TabMetricsLoggerTest, GetTabFeatures) {
+TEST_F(TabMetricsLoggerTest, MAYBE_(GetTabFeatures)) {
   TabActivitySimulator tab_activity_simulator;
   Browser::CreateParams params(profile(), true);
   std::unique_ptr<Browser> browser =
diff --git a/chrome/browser/resources/chromeos/drive_internals.html b/chrome/browser/resources/chromeos/drive_internals.html
index 4e28354..92ced649 100644
--- a/chrome/browser/resources/chromeos/drive_internals.html
+++ b/chrome/browser/resources/chromeos/drive_internals.html
@@ -115,6 +115,9 @@
 
     <section id="service-log-section" hidden>
       <h2>Service Log</h2>
+      <ul>
+        <li><a id="other-logs">Other Logs</a>
+      </ul>
       <ul id="service-log">
       </ul>
     </section>
diff --git a/chrome/browser/resources/chromeos/drive_internals.js b/chrome/browser/resources/chromeos/drive_internals.js
index 4113763..6d6dc26 100644
--- a/chrome/browser/resources/chromeos/drive_internals.js
+++ b/chrome/browser/resources/chromeos/drive_internals.js
@@ -209,6 +209,15 @@
 }
 
 /**
+ * Updates the service log section.
+ * @param {Array} log Log lines.
+ */
+function updateOtherServiceLogsUrl(url) {
+  var link = $('other-logs');
+  link.setAttribute('href', url);
+}
+
+/**
  * Creates an element named |elementName| containing the content |text|.
  * @param {string} elementName Name of the new element to be created.
  * @param {string} text Text to be contained in the new element.
diff --git a/chrome/browser/resources/chromeos/echo/manifest.json b/chrome/browser/resources/chromeos/echo/manifest.json
index b0efc05..9643ccc 100644
--- a/chrome/browser/resources/chromeos/echo/manifest.json
+++ b/chrome/browser/resources/chromeos/echo/manifest.json
@@ -54,7 +54,7 @@
       "*://www.google.no/*chromebook/*",
       "*://www.google.co.nz/*chromebook/*",
       "*://www.google.se/*chromebook/*",
-      "*://chromebook*-dot-googwebreview.appspot.com/*chromebook/*"
+      "*://chromebook-dot-googwebreview.appspot.com/*chromebook/*"
     ]
   }
 }
diff --git a/chrome/browser/send_tab_to_self/send_tab_to_self_desktop_util.cc b/chrome/browser/send_tab_to_self/send_tab_to_self_desktop_util.cc
index 632178b..1cf67ba 100644
--- a/chrome/browser/send_tab_to_self/send_tab_to_self_desktop_util.cc
+++ b/chrome/browser/send_tab_to_self/send_tab_to_self_desktop_util.cc
@@ -9,6 +9,7 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/send_tab_to_self/desktop_notification_handler.h"
 #include "chrome/browser/sync/send_tab_to_self_sync_service_factory.h"
 #include "components/send_tab_to_self/send_tab_to_self_model.h"
@@ -22,10 +23,10 @@
 
 namespace send_tab_to_self {
 
-void CreateNewEntry(content::WebContents* tab, Profile* profile) {
+void CreateNewEntry(content::WebContents* tab, const GURL& link_url) {
   content::NavigationEntry* navigation_entry =
       tab->GetController().GetLastCommittedEntry();
-
+  Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext());
   GURL url = navigation_entry->GetURL();
   std::string title = base::UTF16ToUTF8(navigation_entry->GetTitle());
   base::Time navigation_time = navigation_entry->GetTimestamp();
@@ -43,9 +44,14 @@
     return;
   }
 
-  const SendTabToSelfEntry* entry =
-      model->AddEntry(url, title, navigation_time, target_device);
-
+  const SendTabToSelfEntry* entry;
+  if (link_url.is_valid()) {
+    // When share a link.
+    entry = model->AddEntry(link_url, "", base::Time(), target_device);
+  } else {
+    // When share a tab.
+    entry = model->AddEntry(url, title, navigation_time, target_device);
+  }
   if (entry) {
     DesktopNotificationHandler(profile).DisplaySendingConfirmation(*entry);
   } else {
diff --git a/chrome/browser/send_tab_to_self/send_tab_to_self_desktop_util.h b/chrome/browser/send_tab_to_self/send_tab_to_self_desktop_util.h
index 63f232e..344fbe2 100644
--- a/chrome/browser/send_tab_to_self/send_tab_to_self_desktop_util.h
+++ b/chrome/browser/send_tab_to_self/send_tab_to_self_desktop_util.h
@@ -6,8 +6,9 @@
 #define CHROME_BROWSER_SEND_TAB_TO_SELF_SEND_TAB_TO_SELF_DESKTOP_UTIL_H_
 
 #include <string>
+#include "url/gurl.h"
 
-class Profile;
+class GURL;
 
 namespace content {
 class WebContents;
@@ -33,10 +34,9 @@
 const char kOmniboxMenu[] = "OmniboxMenu";
 const char kTabMenu[] = "TabMenu";
 
-// Add a new entry to SendTabToSelfModel when user click "Share to my devices"
-// option
-// TODO(crbug.com/945386): Flip parameter order.
-void CreateNewEntry(content::WebContents* tab, Profile* profile);
+// Add a new entry to SendTabToSelfModel when user click "Share to your
+// devices" option.
+void CreateNewEntry(content::WebContents* tab, const GURL& link_url = GURL());
 
 // Get the icon for send tab to self menu item.
 gfx::ImageSkia* GetImageSkia();
diff --git a/chrome/browser/send_tab_to_self/send_tab_to_self_desktop_util_unittest.cc b/chrome/browser/send_tab_to_self/send_tab_to_self_desktop_util_unittest.cc
index c8b819a..d1c1a77 100644
--- a/chrome/browser/send_tab_to_self/send_tab_to_self_desktop_util_unittest.cc
+++ b/chrome/browser/send_tab_to_self/send_tab_to_self_desktop_util_unittest.cc
@@ -106,8 +106,13 @@
   EXPECT_CALL(*model_mock, AddEntry(url, title, navigation_time,
                                     target_device_sync_cache_guid))
       .WillOnce(testing::Return(nullptr));
+  CreateNewEntry(tab);
 
-  CreateNewEntry(tab, profile());
+  GURL link_url = GURL("https://www.1112233.com");
+  EXPECT_CALL(*model_mock, AddEntry(link_url, "", base::Time(),
+                                    target_device_sync_cache_guid))
+      .WillOnce(testing::Return(nullptr));
+  CreateNewEntry(tab, link_url);
 }
 
 }  // namespace
diff --git a/chrome/browser/send_tab_to_self/send_tab_to_self_util.cc b/chrome/browser/send_tab_to_self/send_tab_to_self_util.cc
index b191e84..84dd4d5 100644
--- a/chrome/browser/send_tab_to_self/send_tab_to_self_util.cc
+++ b/chrome/browser/send_tab_to_self/send_tab_to_self_util.cc
@@ -48,14 +48,26 @@
   return is_http_or_https && !is_native_page && !is_incognito_mode;
 }
 
-bool ShouldOfferFeature(Profile* profile, content::WebContents* web_contents) {
-  if (!profile || !web_contents) {
+bool ShouldOfferFeature(content::WebContents* web_contents) {
+  if (!web_contents)
     return false;
-  }
-
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents->GetBrowserContext());
   return IsFlagEnabled() && IsUserSyncTypeActive(profile) &&
          IsSyncingOnMultipleDevices(profile) &&
          IsContentRequirementsMet(web_contents->GetURL(), profile);
 }
 
+bool ShouldOfferFeatureForLink(content::WebContents* web_contents,
+                               const GURL& link_url) {
+  if (!web_contents)
+    return false;
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents->GetBrowserContext());
+  return IsFlagEnabled() && IsUserSyncTypeActive(profile) &&
+         IsSyncingOnMultipleDevices(profile) &&
+         (IsContentRequirementsMet(web_contents->GetURL(), profile) ||
+          IsContentRequirementsMet(link_url, profile));
+}
+
 }  // namespace send_tab_to_self
diff --git a/chrome/browser/send_tab_to_self/send_tab_to_self_util.h b/chrome/browser/send_tab_to_self/send_tab_to_self_util.h
index ef5dc72..2c3f52f7 100644
--- a/chrome/browser/send_tab_to_self/send_tab_to_self_util.h
+++ b/chrome/browser/send_tab_to_self/send_tab_to_self_util.h
@@ -29,9 +29,13 @@
 //  User is not in Incongnito mode.
 bool IsContentRequirementsMet(const GURL& gurl, Profile* profile);
 
-// Returns true if all conditions are true and shows the option onto the menu
-bool ShouldOfferFeature(Profile* profile, content::WebContents* web_contents);
+// Returns true if all conditions are true and shows the option onto the menu.
+bool ShouldOfferFeature(content::WebContents* web_contents);
 
+// Returns true if all conditions are true and shows the option onto the link
+// menu.
+bool ShouldOfferFeatureForLink(content::WebContents* web_contents,
+                               const GURL& link_url);
 }  // namespace send_tab_to_self
 
 #endif  // CHROME_BROWSER_SEND_TAB_TO_SELF_SEND_TAB_TO_SELF_UTIL_H_
diff --git a/chrome/browser/sync/test/integration/single_client_send_tab_to_self_sync_test.cc b/chrome/browser/sync/test/integration/single_client_send_tab_to_self_sync_test.cc
index 1e53418..6ba109bf 100644
--- a/chrome/browser/sync/test/integration/single_client_send_tab_to_self_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_send_tab_to_self_sync_test.cc
@@ -81,7 +81,6 @@
   ASSERT_TRUE(SetupSync());
 
   EXPECT_FALSE(send_tab_to_self::ShouldOfferFeature(
-      GetBrowser(0)->profile(),
       GetBrowser(0)->tab_strip_model()->GetActiveWebContents()));
 }
 
diff --git a/chrome/browser/ui/ash/accessibility/fake_accessibility_controller.cc b/chrome/browser/ui/ash/accessibility/fake_accessibility_controller.cc
index c602ad5..90b7ae1 100644
--- a/chrome/browser/ui/ash/accessibility/fake_accessibility_controller.cc
+++ b/chrome/browser/ui/ash/accessibility/fake_accessibility_controller.cc
@@ -47,9 +47,6 @@
 void FakeAccessibilityController::SetCaretBounds(
     const gfx::Rect& bounds_in_screen) {}
 
-void FakeAccessibilityController::SetAccessibilityPanelAlwaysVisible(
-    bool always_visible) {}
-
 void FakeAccessibilityController::SetAccessibilityPanelBounds(
     const gfx::Rect& bounds,
     ash::mojom::AccessibilityPanelState state) {}
diff --git a/chrome/browser/ui/ash/accessibility/fake_accessibility_controller.h b/chrome/browser/ui/ash/accessibility/fake_accessibility_controller.h
index e94bbc2..8594d49 100644
--- a/chrome/browser/ui/ash/accessibility/fake_accessibility_controller.h
+++ b/chrome/browser/ui/ash/accessibility/fake_accessibility_controller.h
@@ -31,7 +31,6 @@
   void BrailleDisplayStateChanged(bool connected) override;
   void SetFocusHighlightRect(const gfx::Rect& bounds_in_screen) override;
   void SetCaretBounds(const gfx::Rect& bounds_in_screen) override;
-  void SetAccessibilityPanelAlwaysVisible(bool always_visible) override;
   void SetAccessibilityPanelBounds(
       const gfx::Rect& bounds,
       ash::mojom::AccessibilityPanelState state) override;
diff --git a/chrome/browser/ui/tabs/tab_menu_model.cc b/chrome/browser/ui/tabs/tab_menu_model.cc
index 779d9d1..790e6b4 100644
--- a/chrome/browser/ui/tabs/tab_menu_model.cc
+++ b/chrome/browser/ui/tabs/tab_menu_model.cc
@@ -84,7 +84,7 @@
                           IDS_TAB_CXMENU_SOUND_UNMUTE_SITE, num_affected_tabs));
 
   if (send_tab_to_self::ShouldOfferFeature(
-          tab_strip->profile(), tab_strip->GetWebContentsAt(index))) {
+          tab_strip->GetWebContentsAt(index))) {
     send_tab_to_self::RecordSendTabToSelfClickResult(
         send_tab_to_self::kTabMenu, SendTabToSelfClickResult::kShowItem);
     AddSeparator(ui::NORMAL_SEPARATOR);
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc
index b34ca79..f3bc50c 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -1217,7 +1217,7 @@
     case CommandSendTabToSelf: {
       send_tab_to_self::RecordSendTabToSelfClickResult(
           send_tab_to_self::kTabMenu, SendTabToSelfClickResult::kClickItem);
-      send_tab_to_self::CreateNewEntry(GetActiveWebContents(), profile_);
+      send_tab_to_self::CreateNewEntry(GetActiveWebContents());
       break;
     }
 
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
index a884d83..e6bade01 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -482,8 +482,7 @@
     case IDC_SEND_TAB_TO_SELF:
       send_tab_to_self::RecordSendTabToSelfClickResult(
           send_tab_to_self::kOmniboxMenu, SendTabToSelfClickResult::kClickItem);
-      send_tab_to_self::CreateNewEntry(location_bar_view_->GetWebContents(),
-                                       location_bar_view_->profile());
+      send_tab_to_self::CreateNewEntry(location_bar_view_->GetWebContents());
       return;
 
     // These commands do invoke the popup.
@@ -1706,7 +1705,6 @@
 void OmniboxViewViews::UpdateContextMenu(ui::SimpleMenuModel* menu_contents) {
   // Only add this menu entry if SendTabToSelf feature is enabled.
   if (send_tab_to_self::ShouldOfferFeature(
-          location_bar_view_->profile(),
           location_bar_view_->GetWebContents())) {
     send_tab_to_self::RecordSendTabToSelfClickResult(
         send_tab_to_self::kOmniboxMenu, SendTabToSelfClickResult::kShowItem);
diff --git a/chrome/browser/ui/views/payments/payment_request_dialog_view.cc b/chrome/browser/ui/views/payments/payment_request_dialog_view.cc
index d88d6b8..e9cbb44804 100644
--- a/chrome/browser/ui/views/payments/payment_request_dialog_view.cc
+++ b/chrome/browser/ui/views/payments/payment_request_dialog_view.cc
@@ -85,11 +85,6 @@
     ++number_of_initialization_tasks_;
   }
 
-  if (!request->spec()->IsInitialized()) {
-    request->spec()->AddInitializationObserver(this);
-    ++number_of_initialization_tasks_;
-  }
-
   if (number_of_initialization_tasks_ > 0) {
     ShowProcessingSpinner();
   } else if (observer_for_testing_) {
diff --git a/chrome/browser/ui/views/payments/payment_request_show_promise_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_show_promise_browsertest.cc
deleted file mode 100644
index 5b0eebff..0000000
--- a/chrome/browser/ui/views/payments/payment_request_show_promise_browsertest.cc
+++ /dev/null
@@ -1,334 +0,0 @@
-// 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 "base/strings/utf_string_conversions.h"
-#include "build/build_config.h"
-#include "chrome/browser/ui/views/payments/payment_request_browsertest_base.h"
-#include "chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h"
-#include "components/autofill/core/browser/autofill_profile.h"
-#include "components/autofill/core/browser/autofill_test_utils.h"
-#include "components/web_modal/web_contents_modal_dialog_manager.h"
-#include "content/public/test/browser_test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/views/controls/label.h"
-#include "ui/views/view.h"
-
-namespace payments {
-namespace {
-
-class PaymentRequestShowPromiseTest : public PaymentRequestBrowserTestBase {
- protected:
-  PaymentRequestShowPromiseTest() {}
-  ~PaymentRequestShowPromiseTest() override {}
-
-  // Installs the payment handler for "basic-card" that responds to
-  // "paymentrequest" events by echoing back the "total" object.
-  void InstallEchoPaymentHandlerForBasicCard() {
-    std::string contents;
-    ASSERT_TRUE(content::ExecuteScriptAndExtractString(
-        GetActiveWebContents(), "install();", &contents));
-    ASSERT_EQ(contents, "instruments.set(): Payment handler installed.");
-  }
-
-  // Allows to skip UI into payment handler for "basic-card".
-  void EnalbeSkipUIForForBasicCard() {
-    std::vector<PaymentRequest*> requests =
-        GetPaymentRequests(GetActiveWebContents());
-    ASSERT_EQ(1U, requests.size());
-    requests.front()
-        ->set_skip_ui_for_non_url_payment_method_identifiers_for_test();
-  }
-
-  // Shows the browser payment sheet.
-  void ShowBrowserPaymentSheet() {
-    ResetEventWaiterForSequence({DialogEvent::PROCESSING_SPINNER_SHOWN,
-                                 DialogEvent::PROCESSING_SPINNER_HIDDEN,
-                                 DialogEvent::SPEC_DONE_UPDATING,
-                                 DialogEvent::PROCESSING_SPINNER_HIDDEN,
-                                 DialogEvent::DIALOG_OPENED});
-    ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), "buy();"));
-    WaitForObservedEvent();
-    EXPECT_TRUE(web_modal::WebContentsModalDialogManager::FromWebContents(
-                    GetActiveWebContents())
-                    ->IsDialogActive());
-  }
-
-  // Verifies that the payment sheet total is |total_amount_string|.
-  void ExpectTotal(const std::string& total_amount_string) {
-    EXPECT_EQ(base::ASCIIToUTF16(total_amount_string),
-              GetLabelText(DialogViewID::ORDER_SUMMARY_TOTAL_AMOUNT_LABEL));
-  }
-
-  // Verifies that the shipping address section does not display any warning
-  // messages.
-  void ExpectNoShippingWarningMessage() {
-    views::View* view = dialog_view()->GetViewByID(
-        static_cast<int>(DialogViewID::WARNING_LABEL));
-    if (!view || !view->visible())
-      return;
-
-    EXPECT_EQ(base::string16(), static_cast<views::Label*>(view)->text());
-  }
-
-  // Verifies that the shipping address section has |expected_message| in the
-  // header.
-  void ExpectShippingWarningMessage(const std::string& expected_message) {
-    EXPECT_EQ(base::ASCIIToUTF16(expected_message),
-              GetLabelText(DialogViewID::WARNING_LABEL));
-  }
-
-  // Selects another shipping address.
-  void SelectAnotherShippingAddress() {
-    ResetEventWaiterForSequence({DialogEvent::PROCESSING_SPINNER_SHOWN,
-                                 DialogEvent::PROCESSING_SPINNER_HIDDEN,
-                                 DialogEvent::SPEC_DONE_UPDATING});
-    ClickOnChildInListViewAndWait(
-        /*child_index=*/1, /*total_num_children=*/2,
-        DialogViewID::SHIPPING_ADDRESS_SHEET_LIST_VIEW);
-  }
-
-  // Selects the only shipping address.
-  void SelectTheOnlyShippingAddress() {
-    ResetEventWaiterForSequence({DialogEvent::PROCESSING_SPINNER_SHOWN,
-                                 DialogEvent::PROCESSING_SPINNER_HIDDEN,
-                                 DialogEvent::SPEC_DONE_UPDATING});
-    ClickOnChildInListViewAndWait(
-        /*child_index=*/0, /*total_num_children=*/1,
-        DialogViewID::SHIPPING_ADDRESS_SHEET_LIST_VIEW);
-  }
-
-  // Verifies that the first shipping option cost is |amount_string|.
-  void ExpectShippingCost(const std::string& amount_string) {
-    EXPECT_EQ(base::ASCIIToUTF16(amount_string),
-              GetLabelText(DialogViewID::SHIPPING_OPTION_AMOUNT));
-  }
-
-  // Clicks the "Pay" button and waits for the dialog to close.
-  void Pay() {
-    ResetEventWaiterForSequence(
-        {DialogEvent::PROCESSING_SPINNER_SHOWN, DialogEvent::DIALOG_CLOSED});
-    ClickOnDialogViewAndWait(DialogViewID::PAY_BUTTON, dialog_view());
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(PaymentRequestShowPromiseTest);
-};
-
-IN_PROC_BROWSER_TEST_F(PaymentRequestShowPromiseTest, DigitalGoods) {
-  NavigateTo("/show_promise/digital_goods.html");
-  InstallEchoPaymentHandlerForBasicCard();
-  ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), "create();"));
-  ShowBrowserPaymentSheet();
-
-  EXPECT_TRUE(IsPayButtonEnabled());
-
-  OpenOrderSummaryScreen();
-
-  ExpectTotal("$1.00");
-
-  ClickOnBackArrow();
-  Pay();
-
-  ExpectBodyContains({R"({"currency":"USD","value":"1.00"})"});
-}
-
-IN_PROC_BROWSER_TEST_F(PaymentRequestShowPromiseTest, SingleOptionShipping) {
-  NavigateTo("/show_promise/single_option_shipping.html");
-  InstallEchoPaymentHandlerForBasicCard();
-  AddAutofillProfile(autofill::test::GetFullProfile());
-  AddAutofillProfile(autofill::test::GetFullProfile2());
-  ShowBrowserPaymentSheet();
-
-  EXPECT_TRUE(IsPayButtonEnabled());
-
-  OpenOrderSummaryScreen();
-
-  ExpectTotal("$1.00");
-
-  ClickOnBackArrow();
-  OpenShippingAddressSectionScreen();
-
-  ExpectNoShippingWarningMessage();
-
-  SelectAnotherShippingAddress();
-
-  ExpectNoShippingWarningMessage();
-
-  ClickOnBackArrow();
-  OpenShippingOptionSectionScreen();
-
-  ExpectShippingCost("$0.00");
-
-  ClickOnBackArrow();
-
-  EXPECT_TRUE(IsPayButtonEnabled());
-
-  Pay();
-
-  ExpectBodyContains({R"({"currency":"USD","value":"1.00"})"});
-}
-
-IN_PROC_BROWSER_TEST_F(PaymentRequestShowPromiseTest,
-                       SingleOptionShippingWithUpdate) {
-  NavigateTo("/show_promise/single_option_shipping_with_update.html");
-  InstallEchoPaymentHandlerForBasicCard();
-  AddAutofillProfile(autofill::test::GetFullProfile());
-  AddAutofillProfile(autofill::test::GetFullProfile2());
-  ShowBrowserPaymentSheet();
-
-  EXPECT_TRUE(IsPayButtonEnabled());
-
-  OpenOrderSummaryScreen();
-
-  ExpectTotal("$1.00");
-
-  ClickOnBackArrow();
-  OpenShippingAddressSectionScreen();
-
-  ExpectNoShippingWarningMessage();
-
-  SelectAnotherShippingAddress();
-
-  ExpectNoShippingWarningMessage();
-
-  ClickOnBackArrow();
-  OpenShippingOptionSectionScreen();
-
-  ExpectShippingCost("$0.00");
-
-  ClickOnBackArrow();
-
-  EXPECT_TRUE(IsPayButtonEnabled());
-
-  Pay();
-
-  ExpectBodyContains({R"({"currency":"USD","value":"1.00"})"});
-}
-
-IN_PROC_BROWSER_TEST_F(PaymentRequestShowPromiseTest, CannotShipError) {
-  NavigateTo("/show_promise/us_only_shipping.html");
-  InstallEchoPaymentHandlerForBasicCard();
-  AddAutofillProfile(autofill::test::GetFullCanadianProfile());
-  ShowBrowserPaymentSheet();
-
-  EXPECT_FALSE(IsPayButtonEnabled());
-
-  OpenOrderSummaryScreen();
-
-  ExpectTotal("$1.00");
-
-  ClickOnBackArrow();
-  OpenShippingAddressSectionScreen();
-
-  ExpectShippingWarningMessage(
-      "To see shipping methods and requirements, select an address");
-
-  SelectTheOnlyShippingAddress();
-
-  ExpectShippingWarningMessage("Cannot ship outside of US.");
-
-  ClickOnBackArrow();
-
-  EXPECT_FALSE(IsPayButtonEnabled());
-
-  ClickOnCancel();
-}
-
-#if defined(OS_WIN) || defined(OS_MACOSX)
-// Times out flakily on Windows and Mac.
-#define CanShipAfterCheckingAddress_MAYBE CanShipAfterCheckingAddress_DISABLED
-#else
-#define CanShipAfterCheckingAddress_MAYBE CanShipAfterCheckingAddress
-#endif
-IN_PROC_BROWSER_TEST_F(PaymentRequestShowPromiseTest,
-                       CanShipAfterCheckingAddress_MAYBE) {
-  NavigateTo("/show_promise/us_only_shipping.html");
-  InstallEchoPaymentHandlerForBasicCard();
-  AddAutofillProfile(autofill::test::GetFullProfile());
-  ShowBrowserPaymentSheet();
-
-  EXPECT_FALSE(IsPayButtonEnabled());
-
-  OpenOrderSummaryScreen();
-
-  ExpectTotal("$1.00");
-
-  ClickOnBackArrow();
-  OpenShippingAddressSectionScreen();
-
-  ExpectShippingWarningMessage(
-      "To see shipping methods and requirements, select an address");
-
-  SelectTheOnlyShippingAddress();
-
-  EXPECT_TRUE(IsPayButtonEnabled());
-
-  Pay();
-
-  ExpectBodyContains({R"({"currency":"USD","value":"1.00"})"});
-}
-
-IN_PROC_BROWSER_TEST_F(PaymentRequestShowPromiseTest, SkipUI) {
-  NavigateTo("/show_promise/digital_goods.html");
-  InstallEchoPaymentHandlerForBasicCard();
-  ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), "create();"));
-  EnalbeSkipUIForForBasicCard();
-  ResetEventWaiterForSequence(
-      {DialogEvent::PROCESSING_SPINNER_SHOWN,
-       DialogEvent::PROCESSING_SPINNER_HIDDEN, DialogEvent::SPEC_DONE_UPDATING,
-       DialogEvent::PROCESSING_SPINNER_HIDDEN, DialogEvent::DIALOG_OPENED,
-       DialogEvent::PROCESSING_SPINNER_SHOWN, DialogEvent::DIALOG_CLOSED});
-  ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), "buy();"));
-  WaitForObservedEvent();
-
-  ExpectBodyContains({R"({"currency":"USD","value":"1.00"})"});
-}
-
-IN_PROC_BROWSER_TEST_F(PaymentRequestShowPromiseTest, Reject) {
-  NavigateTo("/show_promise/reject.html");
-  ResetEventWaiterForSequence(
-      {DialogEvent::PROCESSING_SPINNER_SHOWN, DialogEvent::DIALOG_CLOSED});
-  ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), "buy();"));
-  WaitForObservedEvent();
-
-  ExpectBodyContains({R"(AbortError)"});
-}
-
-IN_PROC_BROWSER_TEST_F(PaymentRequestShowPromiseTest, Timeout) {
-  NavigateTo("/show_promise/timeout.html");
-  ResetEventWaiterForSequence(
-      {DialogEvent::PROCESSING_SPINNER_SHOWN, DialogEvent::DIALOG_CLOSED});
-  ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), "buy();"));
-  WaitForObservedEvent();
-
-  ExpectBodyContains({R"(AbortError)"});
-}
-
-IN_PROC_BROWSER_TEST_F(PaymentRequestShowPromiseTest,
-                       UnsupportedPaymentMethod) {
-  NavigateTo("/show_promise/unsupported.html");
-  ResetEventWaiterForSequence(
-      {DialogEvent::PROCESSING_SPINNER_SHOWN,
-       DialogEvent::PROCESSING_SPINNER_HIDDEN, DialogEvent::SPEC_DONE_UPDATING,
-       DialogEvent::PROCESSING_SPINNER_HIDDEN, DialogEvent::NOT_SUPPORTED_ERROR,
-       DialogEvent::DIALOG_CLOSED});
-  ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), "buy();"));
-  WaitForObservedEvent();
-
-  ExpectBodyContains(
-      {R"(NotSupportedError: The payment method "foo" is not supported)"});
-}
-
-IN_PROC_BROWSER_TEST_F(PaymentRequestShowPromiseTest, InvalidDetails) {
-  NavigateTo("/show_promise/invalid_details.html");
-  ResetEventWaiterForSequence(
-      {DialogEvent::PROCESSING_SPINNER_SHOWN, DialogEvent::DIALOG_CLOSED});
-  ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), "buy();"));
-  WaitForObservedEvent();
-
-  ExpectBodyContains({R"(Total amount value should be non-negative)"});
-}
-
-}  // namespace
-}  // namespace payments
diff --git a/chrome/browser/ui/views/profiles/avatar_toolbar_button.cc b/chrome/browser/ui/views/profiles/avatar_toolbar_button.cc
index 68ab208..21986217 100644
--- a/chrome/browser/ui/views/profiles/avatar_toolbar_button.cc
+++ b/chrome/browser/ui/views/profiles/avatar_toolbar_button.cc
@@ -268,7 +268,7 @@
     // This can happen if the user deletes the current profile.
     return true;
   }
-  return entry->IsUsingDefaultAvatar() &&
+  return entry->GetAvatarIconIndex() == 0 &&
          g_browser_process->profile_manager()
                  ->GetProfileAttributesStorage()
                  .GetNumberOfProfiles() == 1 &&
diff --git a/chrome/browser/ui/webui/chromeos/drive_internals_ui.cc b/chrome/browser/ui/webui/chromeos/drive_internals_ui.cc
index 46e535b..670f76e 100644
--- a/chrome/browser/ui/webui/chromeos/drive_internals_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/drive_internals_ui.cc
@@ -50,6 +50,7 @@
 #include "google_apis/drive/drive_api_error_codes.h"
 #include "google_apis/drive/drive_api_parser.h"
 #include "google_apis/drive/time_util.h"
+#include "net/base/filename_util.h"
 
 using content::BrowserThread;
 
@@ -760,6 +761,10 @@
     if (log_path.empty())
       return;
 
+    MaybeCallJavascript(
+        "updateOtherServiceLogsUrl",
+        base::Value(net::FilePathToFileURL(log_path.DirName()).spec()));
+
     base::PostTaskWithTraitsAndReplyWithResult(
         FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
         base::BindOnce(&GetServiceLogContents, log_path,
diff --git a/chrome/browser/web_applications/components/BUILD.gn b/chrome/browser/web_applications/components/BUILD.gn
index 61fce11..2e9ad68 100644
--- a/chrome/browser/web_applications/components/BUILD.gn
+++ b/chrome/browser/web_applications/components/BUILD.gn
@@ -89,6 +89,8 @@
   deps = [
     ":components",
     "//base",
+    "//base/test:test_support",
+    "//content/public/browser",
     "//url",
   ]
 }
diff --git a/chrome/browser/web_applications/components/pending_app_manager.cc b/chrome/browser/web_applications/components/pending_app_manager.cc
index dd47b58c..5bca790 100644
--- a/chrome/browser/web_applications/components/pending_app_manager.cc
+++ b/chrome/browser/web_applications/components/pending_app_manager.cc
@@ -10,16 +10,32 @@
 
 #include "base/bind_helpers.h"
 #include "base/stl_util.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "chrome/browser/web_applications/components/web_app_constants.h"
 
 namespace web_app {
 
+PendingAppManager::SynchronizeRequest::SynchronizeRequest(
+    SynchronizeCallback callback,
+    int remaining_requests)
+    : callback(std::move(callback)), remaining_requests(remaining_requests) {}
+
+PendingAppManager::SynchronizeRequest::~SynchronizeRequest() = default;
+
+PendingAppManager::SynchronizeRequest& PendingAppManager::SynchronizeRequest::
+operator=(PendingAppManager::SynchronizeRequest&&) = default;
+
+PendingAppManager::SynchronizeRequest::SynchronizeRequest(
+    SynchronizeRequest&& other) = default;
+
 PendingAppManager::PendingAppManager() = default;
 
 PendingAppManager::~PendingAppManager() = default;
 
 void PendingAppManager::SynchronizeInstalledApps(
     std::vector<InstallOptions> desired_apps_install_options,
-    InstallSource install_source) {
+    InstallSource install_source,
+    SynchronizeCallback callback) {
   DCHECK(std::all_of(desired_apps_install_options.begin(),
                      desired_apps_install_options.end(),
                      [&install_source](const InstallOptions& install_options) {
@@ -35,10 +51,66 @@
   }
   std::sort(desired_urls.begin(), desired_urls.end());
 
+  auto urls_to_remove =
+      base::STLSetDifference<std::vector<GURL>>(current_urls, desired_urls);
+
+  // Run callback immediately if there's no work to be done.
+  if (urls_to_remove.empty() && desired_apps_install_options.empty()) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::BindOnce(std::move(callback), SynchronizeResult::kSuccess));
+    return;
+  }
+
+  // TODO(calamity): Move this to the top of the function once PolicyPrefsTest
+  // no longer crashes because of it.
+  // Only one concurrent SynchronizeInstalledApps() expected per InstallSource.
+  DCHECK(!base::ContainsKey(synchronize_requests_, install_source));
+
+  // Add the callback to a map and call once all installs/uninstalls finish.
+  synchronize_requests_.insert_or_assign(
+      install_source,
+      SynchronizeRequest(std::move(callback),
+                         urls_to_remove.size() + desired_urls.size()));
+
   UninstallApps(
-      base::STLSetDifference<std::vector<GURL>>(current_urls, desired_urls),
-      base::DoNothing());
-  InstallApps(std::move(desired_apps_install_options), base::DoNothing());
+      urls_to_remove,
+      base::BindRepeating(&PendingAppManager::UninstallForSynchronizeCallback,
+                          base::Unretained(this), install_source));
+  InstallApps(
+      std::move(desired_apps_install_options),
+      base::BindRepeating(&PendingAppManager::InstallForSynchronizeCallback,
+                          base::Unretained(this), install_source));
+}
+
+void PendingAppManager::InstallForSynchronizeCallback(InstallSource source,
+                                                      const GURL& app_url,
+                                                      InstallResultCode code) {
+  OnAppSynchronized(source, code == InstallResultCode::kSuccess ||
+                                code == InstallResultCode::kAlreadyInstalled);
+}
+
+void PendingAppManager::UninstallForSynchronizeCallback(InstallSource source,
+                                                        const GURL& app_url,
+                                                        bool succeeded) {
+  OnAppSynchronized(source, succeeded);
+}
+
+void PendingAppManager::OnAppSynchronized(InstallSource source,
+                                          bool succeeded) {
+  auto it = synchronize_requests_.find(source);
+  DCHECK(it != synchronize_requests_.end());
+
+  SynchronizeRequest& request = it->second;
+  if (!succeeded)
+    request.result = SynchronizeResult::kFailed;
+
+  DCHECK_GT(request.remaining_requests, 0);
+  if (--request.remaining_requests == 0) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(std::move(request.callback), request.result));
+    synchronize_requests_.erase(source);
+  }
 }
 
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/components/pending_app_manager.h b/chrome/browser/web_applications/components/pending_app_manager.h
index 3e706a2..f423a3a 100644
--- a/chrome/browser/web_applications/components/pending_app_manager.h
+++ b/chrome/browser/web_applications/components/pending_app_manager.h
@@ -10,7 +10,8 @@
 #include <string>
 #include <vector>
 
-#include "base/callback_forward.h"
+#include "base/callback.h"
+#include "base/containers/flat_map.h"
 #include "base/macros.h"
 #include "chrome/browser/web_applications/components/install_options.h"
 #include "url/gurl.h"
@@ -27,6 +28,11 @@
 // should wait for the update request to finish before uninstalling the app.
 class PendingAppManager {
  public:
+  enum class SynchronizeResult {
+    kSuccess = 0,
+    kFailed = 1,
+  };
+
   using OnceInstallCallback =
       base::OnceCallback<void(const GURL& app_url, InstallResultCode code)>;
   using RepeatingInstallCallback =
@@ -34,6 +40,8 @@
                                    InstallResultCode code)>;
   using UninstallCallback =
       base::RepeatingCallback<void(const GURL& app_url, bool succeeded)>;
+  using SynchronizeCallback =
+      base::OnceCallback<void(SynchronizeResult result)>;
 
   PendingAppManager();
   virtual ~PendingAppManager();
@@ -77,16 +85,45 @@
   // All apps in |desired_apps_install_options| should have |install_source| as
   // their source.
   //
+  // Once all installs/uninstalls are complete, |callback| will be run with the
+  // success/failure status of the synchronization.
+  //
   // Note that this returns after queueing work (installation and
   // uninstallation) to be done. It does not wait until that work is complete.
   void SynchronizeInstalledApps(
       std::vector<InstallOptions> desired_apps_install_options,
-      InstallSource install_source);
+      InstallSource install_source,
+      SynchronizeCallback callback);
 
   // Returns the app id for |url| if the PendingAppManager is aware of it.
   virtual base::Optional<std::string> LookupAppId(const GURL& url) const = 0;
 
  private:
+  struct SynchronizeRequest {
+    SynchronizeRequest(SynchronizeCallback callback, int remaining_requests);
+    ~SynchronizeRequest();
+
+    SynchronizeRequest& operator=(SynchronizeRequest&&);
+    SynchronizeRequest(SynchronizeRequest&& other);
+
+    SynchronizeCallback callback;
+    int remaining_requests;
+    SynchronizeResult result = SynchronizeResult::kSuccess;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(SynchronizeRequest);
+  };
+
+  void InstallForSynchronizeCallback(InstallSource source,
+                                     const GURL& app_url,
+                                     InstallResultCode code);
+  void UninstallForSynchronizeCallback(InstallSource source,
+                                       const GURL& app_url,
+                                       bool succeeded);
+  void OnAppSynchronized(InstallSource source, bool succeeded);
+
+  base::flat_map<InstallSource, SynchronizeRequest> synchronize_requests_;
+
   DISALLOW_COPY_AND_ASSIGN(PendingAppManager);
 };
 
diff --git a/chrome/browser/web_applications/components/pending_app_manager_unittest.cc b/chrome/browser/web_applications/components/pending_app_manager_unittest.cc
index 8df0b4c..62ad75c 100644
--- a/chrome/browser/web_applications/components/pending_app_manager_unittest.cc
+++ b/chrome/browser/web_applications/components/pending_app_manager_unittest.cc
@@ -8,6 +8,10 @@
 #include <sstream>
 #include <vector>
 
+#include "base/bind_helpers.h"
+#include "base/run_loop.h"
+#include "base/test/bind_test_util.h"
+#include "base/test/scoped_task_environment.h"
 #include "chrome/browser/web_applications/components/test_pending_app_manager.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -24,8 +28,17 @@
       install_options_list.emplace_back(url, LaunchContainer::kWindow,
                                         InstallSource::kInternal);
     }
+
+    base::RunLoop run_loop;
     pending_app_manager_.SynchronizeInstalledApps(
-        std::move(install_options_list), InstallSource::kInternal);
+        std::move(install_options_list), InstallSource::kInternal,
+        base::BindLambdaForTesting(
+            [&run_loop](PendingAppManager::SynchronizeResult result) {
+              ASSERT_EQ(PendingAppManager::SynchronizeResult::kSuccess, result);
+              run_loop.Quit();
+            }));
+    // Wait for SynchronizeInstalledApps to finish.
+    run_loop.Run();
   }
 
   void Expect(int deduped_install_count,
@@ -42,6 +55,7 @@
     EXPECT_EQ(installed_app_urls, urls);
   }
 
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
   TestPendingAppManager pending_app_manager_;
 };
 
diff --git a/chrome/browser/web_applications/components/policy/web_app_policy_manager.cc b/chrome/browser/web_applications/components/policy/web_app_policy_manager.cc
index 3d7c2cb..09df440c 100644
--- a/chrome/browser/web_applications/components/policy/web_app_policy_manager.cc
+++ b/chrome/browser/web_applications/components/policy/web_app_policy_manager.cc
@@ -105,7 +105,8 @@
   }
 
   pending_app_manager_->SynchronizeInstalledApps(
-      std::move(install_options_list), InstallSource::kExternalPolicy);
+      std::move(install_options_list), InstallSource::kExternalPolicy,
+      base::DoNothing());
 }
 
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/components/test_pending_app_manager.cc b/chrome/browser/web_applications/components/test_pending_app_manager.cc
index f5ebd95..17e348c8 100644
--- a/chrome/browser/web_applications/components/test_pending_app_manager.cc
+++ b/chrome/browser/web_applications/components/test_pending_app_manager.cc
@@ -7,7 +7,11 @@
 #include <string>
 #include <utility>
 
+#include "base/bind.h"
 #include "base/callback.h"
+#include "base/sequenced_task_runner.h"
+#include "base/test/bind_test_util.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "url/gurl.h"
 
@@ -27,16 +31,19 @@
 void TestPendingAppManager::Install(InstallOptions install_options,
                                     OnceInstallCallback callback) {
   // TODO(nigeltao): Add error simulation when error codes are added to the API.
-
-  auto i = installed_apps_.find(install_options.url);
-  if (i == installed_apps_.end()) {
-    installed_apps_[install_options.url] = install_options.install_source;
-    deduped_install_count_++;
-  }
-
-  install_requests_.push_back(std::move(install_options));
-  std::move(callback).Run(install_requests().back().url,
-                          InstallResultCode::kSuccess);
+  auto do_install = base::BindLambdaForTesting(
+      [this, install_options](OnceInstallCallback callback) {
+        auto i = installed_apps_.find(install_options.url);
+        if (i == installed_apps_.end()) {
+          installed_apps_[install_options.url] = install_options.install_source;
+          deduped_install_count_++;
+        }
+        install_requests_.push_back(install_options);
+        std::move(callback).Run(install_options.url,
+                                InstallResultCode::kSuccess);
+      });
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(do_install, std::move(callback)));
 }
 
 void TestPendingAppManager::InstallApps(
@@ -48,15 +55,20 @@
 
 void TestPendingAppManager::UninstallApps(std::vector<GURL> uninstall_urls,
                                           const UninstallCallback& callback) {
-  for (auto& url : uninstall_urls) {
-    auto i = installed_apps_.find(url);
-    if (i != installed_apps_.end()) {
-      installed_apps_.erase(i);
-      deduped_uninstall_count_++;
-    }
+  auto do_uninstall =
+      base::BindLambdaForTesting([&](UninstallCallback callback, GURL url) {
+        auto i = installed_apps_.find(url);
+        if (i != installed_apps_.end()) {
+          installed_apps_.erase(i);
+          deduped_uninstall_count_++;
+        }
 
-    uninstall_requests_.push_back(url);
-    callback.Run(url, true /* succeeded */);
+        uninstall_requests_.push_back(url);
+        callback.Run(url, true /* succeeded */);
+      });
+  for (const auto& url : uninstall_urls) {
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(do_uninstall, callback, url));
   }
 }
 
diff --git a/chrome/browser/web_applications/components/test_pending_app_manager.h b/chrome/browser/web_applications/components/test_pending_app_manager.h
index 00c82958..2501df37 100644
--- a/chrome/browser/web_applications/components/test_pending_app_manager.h
+++ b/chrome/browser/web_applications/components/test_pending_app_manager.h
@@ -54,6 +54,7 @@
   base::Optional<std::string> LookupAppId(const GURL& url) const override;
 
  private:
+  void DoInstall(InstallOptions install_options, OnceInstallCallback callback);
   std::vector<InstallOptions> install_requests_;
   std::vector<GURL> uninstall_requests_;
 
diff --git a/chrome/browser/web_applications/system_web_app_manager.cc b/chrome/browser/web_applications/system_web_app_manager.cc
index 7b5a4fa0..6583d62 100644
--- a/chrome/browser/web_applications/system_web_app_manager.cc
+++ b/chrome/browser/web_applications/system_web_app_manager.cc
@@ -66,7 +66,8 @@
   }
 
   pending_app_manager_->SynchronizeInstalledApps(
-      std::move(install_options_list), InstallSource::kSystemInstalled);
+      std::move(install_options_list), InstallSource::kSystemInstalled,
+      base::DoNothing());
 }
 
 base::Optional<std::string> SystemWebAppManager::GetAppIdForSystemApp(
diff --git a/chrome/browser/web_applications/web_app_provider.cc b/chrome/browser/web_applications/web_app_provider.cc
index b18c7f59..cb71a7a7 100644
--- a/chrome/browser/web_applications/web_app_provider.cc
+++ b/chrome/browser/web_applications/web_app_provider.cc
@@ -239,7 +239,8 @@
 void WebAppProvider::OnScanForExternalWebApps(
     std::vector<InstallOptions> desired_apps_install_options) {
   pending_app_manager_->SynchronizeInstalledApps(
-      std::move(desired_apps_install_options), InstallSource::kExternalDefault);
+      std::move(desired_apps_install_options), InstallSource::kExternalDefault,
+      base::DoNothing());
 }
 
 }  // namespace web_app
diff --git a/chrome/renderer/content_settings_observer.cc b/chrome/renderer/content_settings_observer.cc
index 1d59daa..65ccd52 100644
--- a/chrome/renderer/content_settings_observer.cc
+++ b/chrome/renderer/content_settings_observer.cc
@@ -511,9 +511,16 @@
   if (update_count == 0)
     return;
 
-  UMA_HISTOGRAM_CUSTOM_TIMES("ClientHints.PersistDuration", duration,
-                             base::TimeDelta::FromSeconds(1),
-                             base::TimeDelta::FromDays(365), 100);
+  UMA_HISTOGRAM_CUSTOM_TIMES(
+      "ClientHints.PersistDuration", duration, base::TimeDelta::FromSeconds(1),
+      // TODO(crbug.com/949034): Rename and fix this histogram to have some
+      // intended max value. We throw away the 32 most-significant bits of the
+      // 64-bit time delta in milliseconds. Before it happened silently in
+      // histogram.cc, now it is explicit here. The previous value of 365 days
+      // effectively turns into roughly 17 days when getting cast to int.
+      base::TimeDelta::FromMilliseconds(
+          static_cast<int>(base::TimeDelta::FromDays(365).InMilliseconds())),
+      100);
 
   UMA_HISTOGRAM_COUNTS_100("ClientHints.UpdateSize", update_count);
 
diff --git a/chrome/renderer/security_interstitials/security_interstitial_page_controller.cc b/chrome/renderer/security_interstitials/security_interstitial_page_controller.cc
index 126e46c..df7986e 100644
--- a/chrome/renderer/security_interstitials/security_interstitial_page_controller.cc
+++ b/chrome/renderer/security_interstitials/security_interstitial_page_controller.cc
@@ -35,8 +35,10 @@
     return;
 
   v8::Local<v8::Object> global = context->Global();
-  global->Set(gin::StringToV8(isolate, "certificateErrorPageController"),
-              controller.ToV8());
+  global
+      ->Set(context, gin::StringToV8(isolate, "certificateErrorPageController"),
+            controller.ToV8())
+      .Check();
 }
 
 SecurityInterstitialPageController::SecurityInterstitialPageController(
diff --git a/chrome/renderer/supervised_user/supervised_user_error_page_controller.cc b/chrome/renderer/supervised_user/supervised_user_error_page_controller.cc
index 451d1421..656c16c 100644
--- a/chrome/renderer/supervised_user/supervised_user_error_page_controller.cc
+++ b/chrome/renderer/supervised_user/supervised_user_error_page_controller.cc
@@ -34,8 +34,11 @@
     return;
 
   v8::Local<v8::Object> global = context->Global();
-  global->Set(gin::StringToV8(isolate, "supervisedUserErrorPageController"),
-              controller.ToV8());
+  global
+      ->Set(context,
+            gin::StringToV8(isolate, "supervisedUserErrorPageController"),
+            controller.ToV8())
+      .Check();
 }
 
 SupervisedUserErrorPageController::SupervisedUserErrorPageController(
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 13e679e..aee2876 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1681,7 +1681,6 @@
         "../browser/ui/views/payments/payment_request_payment_app_browsertest.cc",
         "../browser/ui/views/payments/payment_request_payment_response_browsertest.cc",
         "../browser/ui/views/payments/payment_request_shipping_address_instance_browsertest.cc",
-        "../browser/ui/views/payments/payment_request_show_promise_browsertest.cc",
         "../browser/ui/views/payments/payment_request_update_with_browsertest.cc",
         "../browser/ui/views/payments/payment_request_use_stats_browsertest.cc",
         "../browser/ui/views/payments/payment_sheet_view_controller_browsertest.cc",
diff --git a/chromecast/media/base/slew_volume_unittests.cc b/chromecast/media/base/slew_volume_unittests.cc
index 30d450b..26244e46 100644
--- a/chromecast/media/base/slew_volume_unittests.cc
+++ b/chromecast/media/base/slew_volume_unittests.cc
@@ -36,7 +36,8 @@
     sine[i * 2 + 1] = cos(static_cast<float>(i + 1) * frequency * 2 * M_PI) *
                       std::numeric_limits<int32_t>::max();
   }
-  data->FromInterleaved(sine.data(), frames, kBytesPerSample);
+  data->FromInterleaved<::media::SignedInt32SampleTypeTraits>(sine.data(),
+                                                              frames);
   return data;
 }
 
diff --git a/chromecast/media/cma/backend/filter_group_unittest.cc b/chromecast/media/cma/backend/filter_group_unittest.cc
index 5582dc2..8394c02 100644
--- a/chromecast/media/cma/backend/filter_group_unittest.cc
+++ b/chromecast/media/cma/backend/filter_group_unittest.cc
@@ -26,7 +26,6 @@
 // Total of Test samples including left and right channels.
 #define NUM_SAMPLES 64
 
-constexpr size_t kBytesPerSample = sizeof(int32_t);
 constexpr int kNumInputChannels = 2;
 constexpr int kInputSampleRate = 48000;
 constexpr int kInputFrames = NUM_SAMPLES / 2;
@@ -163,7 +162,8 @@
 std::unique_ptr<::media::AudioBus> GetTestData() {
   int samples = NUM_SAMPLES / kNumInputChannels;
   auto data = ::media::AudioBus::Create(kNumInputChannels, samples);
-  data->FromInterleaved(kTestData, samples, kBytesPerSample);
+  data->FromInterleaved<::media::SignedInt32SampleTypeTraits>(kTestData,
+                                                              samples);
   return data;
 }
 
diff --git a/chromecast/media/cma/backend/stream_mixer_external_audio_pipeline_unittest.cc b/chromecast/media/cma/backend/stream_mixer_external_audio_pipeline_unittest.cc
index 105ff7e..9051e74 100644
--- a/chromecast/media/cma/backend/stream_mixer_external_audio_pipeline_unittest.cc
+++ b/chromecast/media/cma/backend/stream_mixer_external_audio_pipeline_unittest.cc
@@ -184,15 +184,15 @@
 
   // Prepare data for test.
   const size_t kSampleSize = 64;
-  char test_data[kSampleSize];
+  uint8_t test_data[kSampleSize];
   for (size_t i = 0; i < kSampleSize; ++i)
     test_data[i] = i;
 
   // Set test data in AudioBus.
   const auto kNumFrames = kSampleSize / kNumChannels;
   auto data = ::media::AudioBus::Create(kNumChannels, kNumFrames);
-  const size_t kBytesPerSample = sizeof(test_data[0]);
-  data->FromInterleaved(&test_data, kNumFrames, kBytesPerSample);
+  data->FromInterleaved<::media::UnsignedInt8SampleTypeTraits>(test_data,
+                                                               kNumFrames);
   // Prepare data for compare.
   auto expected = ::media::AudioBus::Create(kNumChannels, kNumFrames);
   data->CopyTo(expected.get());
diff --git a/chromecast/media/cma/backend/stream_mixer_unittest.cc b/chromecast/media/cma/backend/stream_mixer_unittest.cc
index a703af6..167fb36 100644
--- a/chromecast/media/cma/backend/stream_mixer_unittest.cc
+++ b/chromecast/media/cma/backend/stream_mixer_unittest.cc
@@ -142,7 +142,8 @@
   CHECK_LT(index, NUM_DATA_SETS);
   int frames = NUM_SAMPLES / kNumChannels;
   auto data = ::media::AudioBus::Create(kNumChannels, frames);
-  data->FromInterleaved(kTestData[index], frames, kBytesPerSample);
+  data->FromInterleaved<::media::SignedInt32SampleTypeTraits>(kTestData[index],
+                                                              frames);
   return data;
 }
 
@@ -709,7 +710,8 @@
   // Populate the streams with data.
   for (size_t i = 0; i < inputs.size(); ++i) {
     auto test_data = ::media::AudioBus::Create(kNumChannels, kNumFrames);
-    test_data->FromInterleaved(kEdgeData[i], kNumFrames, kBytesPerSample);
+    test_data->FromInterleaved<::media::SignedInt32SampleTypeTraits>(
+        kEdgeData[i], kNumFrames);
     inputs[i]->SetData(std::move(test_data));
     EXPECT_CALL(*inputs[i], FillAudioPlaybackFrames(_, _, _)).Times(1);
   }
@@ -724,7 +726,8 @@
 
   // Use the hand-calculated results above.
   auto expected = ::media::AudioBus::Create(kNumChannels, kNumFrames);
-  expected->FromInterleaved(kResult, kNumFrames, kBytesPerSample);
+  expected->FromInterleaved<::media::SignedInt32SampleTypeTraits>(kResult,
+                                                                  kNumFrames);
 
   CompareAudioData(*expected, *actual);
 
diff --git a/chromeos/services/assistant/audio_decoder/assistant_audio_decoder.cc b/chromeos/services/assistant/audio_decoder/assistant_audio_decoder.cc
index 9a68d8c0..71e0265 100644
--- a/chromeos/services/assistant/audio_decoder/assistant_audio_decoder.cc
+++ b/chromeos/services/assistant/audio_decoder/assistant_audio_decoder.cc
@@ -136,8 +136,8 @@
     const int bytes_to_alloc =
         audio_bus->frames() * kBytesPerSample * audio_bus->channels();
     std::vector<uint8_t> buffer(bytes_to_alloc);
-    audio_bus->ToInterleaved(audio_bus->frames(), kBytesPerSample,
-                             buffer.data());
+    audio_bus->ToInterleaved<media::SignedInt16SampleTypeTraits>(
+        audio_bus->frames(), reinterpret_cast<int16_t*>(buffer.data()));
     buffers.emplace_back(buffer);
   }
   client_->OnNewBuffers(buffers);
diff --git a/components/arc/BUILD.gn b/components/arc/BUILD.gn
index f8d9345..f43fdd8 100644
--- a/components/arc/BUILD.gn
+++ b/components/arc/BUILD.gn
@@ -216,6 +216,7 @@
     "//components/keyed_service/content",
     "//components/prefs",
     "//components/user_manager",
+    "//components/version_info",
     "//content/public/common",
     "//mojo/public/cpp/platform",
     "//mojo/public/cpp/system",
@@ -366,6 +367,7 @@
     "//components/session_manager/core:core",
     "//components/user_manager",
     "//components/user_manager:test_support",
+    "//components/version_info",
     "//content/public/common",
     "//content/test:test_support",
     "//device/bluetooth",
diff --git a/components/arc/DEPS b/components/arc/DEPS
index 1aad430..e9ddbc7d 100644
--- a/components/arc/DEPS
+++ b/components/arc/DEPS
@@ -11,6 +11,7 @@
   "+components/session_manager/core",
   "+components/timers",
   "+components/user_manager",
+  "+components/version_info",
   "+media/base/video_codecs.h",
   "+media/video/video_encode_accelerator.h",
   "+mojo",
diff --git a/components/arc/arc_features.cc b/components/arc/arc_features.cc
index 0e1b8c2..2ba0fcf 100644
--- a/components/arc/arc_features.cc
+++ b/components/arc/arc_features.cc
@@ -22,6 +22,10 @@
     "ArcCleanDataOnRegularToChildTransition",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Controls experimental Custom Tabs feature for ARC.
+const base::Feature kCustomTabsExperimentFeature{
+    "ArcCustomTabsExperiment", base::FEATURE_ENABLED_BY_DEFAULT};
+
 // Controls whether ARC handles child->regular account transition.
 const base::Feature kEnableChildToRegularTransitionFeature{
     "ArcEnableChildToRegularTransition", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/components/arc/arc_features.h b/components/arc/arc_features.h
index 0fea34b..bb40106 100644
--- a/components/arc/arc_features.h
+++ b/components/arc/arc_features.h
@@ -15,6 +15,7 @@
 extern const base::Feature kAvailableForChildAccountFeature;
 extern const base::Feature kBootCompletedBroadcastFeature;
 extern const base::Feature kCleanArcDataOnRegularToChildTransitionFeature;
+extern const base::Feature kCustomTabsExperimentFeature;
 extern const base::Feature kEnableChildToRegularTransitionFeature;
 extern const base::Feature kEnableDocumentsProviderInFilesAppFeature;
 extern const base::Feature kEnableRegularToChildTransitionFeature;
diff --git a/components/arc/session/arc_session.cc b/components/arc/session/arc_session.cc
index 27406351..b57398a 100644
--- a/components/arc/session/arc_session.cc
+++ b/components/arc/session/arc_session.cc
@@ -29,9 +29,10 @@
 // static
 std::unique_ptr<ArcSession> ArcSession::Create(
     ArcBridgeService* arc_bridge_service,
-    ash::DefaultScaleFactorRetriever* retriever) {
+    ash::DefaultScaleFactorRetriever* retriever,
+    version_info::Channel channel) {
   return std::make_unique<ArcSessionImpl>(
-      ArcSessionImpl::CreateDelegate(arc_bridge_service, retriever));
+      ArcSessionImpl::CreateDelegate(arc_bridge_service, retriever, channel));
 }
 
 }  // namespace arc
diff --git a/components/arc/session/arc_session.h b/components/arc/session/arc_session.h
index 19de852..d7d7cbe 100644
--- a/components/arc/session/arc_session.h
+++ b/components/arc/session/arc_session.h
@@ -23,6 +23,10 @@
 class FilePath;
 }
 
+namespace version_info {
+enum class Channel;
+}
+
 namespace arc {
 
 class ArcBridgeService;
@@ -87,7 +91,8 @@
   // Creates a default instance of ArcSession.
   static std::unique_ptr<ArcSession> Create(
       ArcBridgeService* arc_bridge_service,
-      ash::DefaultScaleFactorRetriever* retriever);
+      ash::DefaultScaleFactorRetriever* retriever,
+      version_info::Channel channel);
   virtual ~ArcSession();
 
   // Sends D-Bus message to start a mini-container.
diff --git a/components/arc/session/arc_session_impl.cc b/components/arc/session/arc_session_impl.cc
index d5898ea2..849952ad 100644
--- a/components/arc/session/arc_session_impl.cc
+++ b/components/arc/session/arc_session_impl.cc
@@ -30,6 +30,7 @@
 #include "components/arc/arc_util.h"
 #include "components/arc/session/arc_bridge_host_impl.h"
 #include "components/user_manager/user_manager.h"
+#include "components/version_info/channel.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/platform/named_platform_channel.h"
 #include "mojo/public/cpp/platform/platform_channel.h"
@@ -115,7 +116,8 @@
 class ArcSessionDelegateImpl : public ArcSessionImpl::Delegate {
  public:
   ArcSessionDelegateImpl(ArcBridgeService* arc_bridge_service,
-                         ash::DefaultScaleFactorRetriever* retriever);
+                         ash::DefaultScaleFactorRetriever* retriever,
+                         version_info::Channel channel);
   ~ArcSessionDelegateImpl() override = default;
 
   // ArcSessionImpl::Delegate override.
@@ -124,6 +126,7 @@
   base::ScopedFD ConnectMojo(base::ScopedFD socket_fd,
                              ConnectMojoCallback callback) override;
   void GetLcdDensity(GetLcdDensityCallback callback) override;
+  version_info::Channel GetChannel() override;
 
  private:
   // Synchronously create a UNIX domain socket. This is designed to run on a
@@ -148,6 +151,8 @@
   // Owned by ArcServiceLauncher.
   ash::DefaultScaleFactorRetriever* const default_scale_factor_retriever_;
 
+  const version_info::Channel channel_;
+
   // WeakPtrFactory to use callbacks.
   base::WeakPtrFactory<ArcSessionDelegateImpl> weak_factory_;
 
@@ -156,9 +161,11 @@
 
 ArcSessionDelegateImpl::ArcSessionDelegateImpl(
     ArcBridgeService* arc_bridge_service,
-    ash::DefaultScaleFactorRetriever* retriever)
+    ash::DefaultScaleFactorRetriever* retriever,
+    version_info::Channel channel)
     : arc_bridge_service_(arc_bridge_service),
       default_scale_factor_retriever_(retriever),
+      channel_(channel),
       weak_factory_(this) {}
 
 void ArcSessionDelegateImpl::CreateSocket(CreateSocketCallback callback) {
@@ -201,6 +208,10 @@
       std::move(callback)));
 }
 
+version_info::Channel ArcSessionDelegateImpl::GetChannel() {
+  return channel_;
+}
+
 // static
 base::ScopedFD ArcSessionDelegateImpl::CreateSocketInternal() {
   auto endpoint = mojo::NamedPlatformChannel({kArcBridgeSocketPath});
@@ -319,9 +330,10 @@
 // static
 std::unique_ptr<ArcSessionImpl::Delegate> ArcSessionImpl::CreateDelegate(
     ArcBridgeService* arc_bridge_service,
-    ash::DefaultScaleFactorRetriever* retriever) {
-  return std::make_unique<ArcSessionDelegateImpl>(arc_bridge_service,
-                                                  retriever);
+    ash::DefaultScaleFactorRetriever* retriever,
+    version_info::Channel channel) {
+  return std::make_unique<ArcSessionDelegateImpl>(arc_bridge_service, retriever,
+                                                  channel);
 }
 
 ArcSessionImpl::ArcSessionImpl(std::unique_ptr<Delegate> delegate)
@@ -359,6 +371,12 @@
       base::FeatureList::IsEnabled(arc::kNativeBridgeExperimentFeature));
   request.set_arc_file_picker_experiment(
       base::FeatureList::IsEnabled(arc::kFilePickerExperimentFeature));
+  // Enable Custom Tabs only on Dev and Cannary.
+  const bool is_custom_tab_enabled =
+      base::FeatureList::IsEnabled(arc::kCustomTabsExperimentFeature) &&
+      delegate_->GetChannel() != version_info::Channel::STABLE &&
+      delegate_->GetChannel() != version_info::Channel::BETA;
+  request.set_arc_custom_tabs_experiment(is_custom_tab_enabled);
   request.set_lcd_density(lcd_density);
 
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
diff --git a/components/arc/session/arc_session_impl.h b/components/arc/session/arc_session_impl.h
index 9550d12b..0e980d6 100644
--- a/components/arc/session/arc_session_impl.h
+++ b/components/arc/session/arc_session_impl.h
@@ -155,6 +155,9 @@
     // it's not yet available. Calling this method while there is a pending
     // callback will cancel the pending callback.
     virtual void GetLcdDensity(GetLcdDensityCallback callback) = 0;
+
+    // Returns the channel for the installation.
+    virtual version_info::Channel GetChannel() = 0;
   };
 
   explicit ArcSessionImpl(std::unique_ptr<Delegate> delegate);
@@ -163,7 +166,8 @@
   // Returns default delegate implementation used for the production.
   static std::unique_ptr<Delegate> CreateDelegate(
       ArcBridgeService* arc_bridge_service,
-      ash::DefaultScaleFactorRetriever* retriever);
+      ash::DefaultScaleFactorRetriever* retriever,
+      version_info::Channel channel);
 
   State GetStateForTesting() { return state_; }
 
diff --git a/components/arc/session/arc_session_impl_unittest.cc b/components/arc/session/arc_session_impl_unittest.cc
index e3536d4..34e5821 100644
--- a/components/arc/session/arc_session_impl_unittest.cc
+++ b/components/arc/session/arc_session_impl_unittest.cc
@@ -22,6 +22,7 @@
 #include "components/arc/test/fake_arc_bridge_host.h"
 #include "components/user_manager/fake_user_manager.h"
 #include "components/user_manager/scoped_user_manager.h"
+#include "components/version_info/channel.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -89,6 +90,10 @@
       lcd_density_callback_ = std::move(callback);
   }
 
+  version_info::Channel GetChannel() override {
+    return version_info::Channel::DEFAULT;
+  }
+
   void SetLcdDensity(int32_t lcd_density) {
     lcd_density_ = lcd_density;
     ASSERT_TRUE(!lcd_density_callback_.is_null());
diff --git a/components/autofill/content/renderer/password_generation_agent.cc b/components/autofill/content/renderer/password_generation_agent.cc
index bbf4c19..c0990850 100644
--- a/components/autofill/content/renderer/password_generation_agent.cc
+++ b/components/autofill/content/renderer/password_generation_agent.cc
@@ -906,6 +906,9 @@
           ? password_agent_->GetPasswordFormFromUnownedInputElements()
           : password_agent_->GetPasswordFormFromWebForm(element.Form());
 
+  if (!password_form)
+    return;
+
   std::vector<blink::WebInputElement> passwords = {element};
 
   WebFormControlElement confirmation_password =
diff --git a/components/autofill/core/browser/webdata/autofill_table.cc b/components/autofill/core/browser/webdata/autofill_table.cc
index 44741c8..0b1570d 100644
--- a/components/autofill/core/browser/webdata/autofill_table.cc
+++ b/components/autofill/core/browser/webdata/autofill_table.cc
@@ -2767,9 +2767,9 @@
   while (s.Step()) {
     std::string storage_key = s.ColumnString(0);
     std::string serialized_metadata = s.ColumnString(1);
-    sync_pb::EntityMetadata entity_metadata;
-    if (entity_metadata.ParseFromString(serialized_metadata)) {
-      metadata_batch->AddMetadata(storage_key, entity_metadata);
+    auto entity_metadata = std::make_unique<sync_pb::EntityMetadata>();
+    if (entity_metadata->ParseFromString(serialized_metadata)) {
+      metadata_batch->AddMetadata(storage_key, std::move(entity_metadata));
     } else {
       DLOG(WARNING) << "Failed to deserialize AUTOFILL model type "
                        "sync_pb::EntityMetadata.";
diff --git a/components/autofill_assistant/browser/BUILD.gn b/components/autofill_assistant/browser/BUILD.gn
index 469e1db8..b908c5ff 100644
--- a/components/autofill_assistant/browser/BUILD.gn
+++ b/components/autofill_assistant/browser/BUILD.gn
@@ -121,6 +121,8 @@
     "state.h",
     "string_conversions_util.cc",
     "string_conversions_util.h",
+    "trigger_context.cc",
+    "trigger_context.h",
     "ui_controller.cc",
     "ui_controller.h",
     "ui_delegate.h",
diff --git a/components/autofill_assistant/browser/actions/action_delegate.h b/components/autofill_assistant/browser/actions/action_delegate.h
index ad8e5f9..d894a7d 100644
--- a/components/autofill_assistant/browser/actions/action_delegate.h
+++ b/components/autofill_assistant/browser/actions/action_delegate.h
@@ -60,16 +60,15 @@
   //
   // TODO(crbug.com/806868): Consider embedding that wait right into
   // WebController and eliminate double-lookup.
-  virtual void ShortWaitForElement(ElementCheckType check_type,
-                                   const Selector& selector,
+  virtual void ShortWaitForElement(const Selector& selector,
                                    base::OnceCallback<void(bool)> callback) = 0;
 
-  // Wait for up to |max_wait_time| for the element |selectors| to be visible on
-  // the page, then call |callback| with true if the element was visible, false
-  // otherwise.
+  // Wait for up to |max_wait_time| for the element |selectors| to match
+  // element(s) on the page, then call |callback| with true if at least an
+  // element matched, false otherwise.
   //
   // If |allow_interrupt| interrupts can run while waiting.
-  virtual void WaitForElementVisible(
+  virtual void WaitForElement(
       base::TimeDelta max_wait_time,
       bool allow_interrupt,
       const Selector& selector,
diff --git a/components/autofill_assistant/browser/actions/autofill_action.cc b/components/autofill_assistant/browser/actions/autofill_action.cc
index 1476c51..3c1136bd 100644
--- a/components/autofill_assistant/browser/actions/autofill_action.cc
+++ b/components/autofill_assistant/browser/actions/autofill_action.cc
@@ -75,10 +75,9 @@
 
 void AutofillAction::FillFormWithData(ActionDelegate* delegate) {
   delegate->ShortWaitForElement(
-      kExistenceCheck, selector_,
-      base::BindOnce(&AutofillAction::OnWaitForElement,
-                     weak_ptr_factory_.GetWeakPtr(),
-                     base::Unretained(delegate)));
+      selector_, base::BindOnce(&AutofillAction::OnWaitForElement,
+                                weak_ptr_factory_.GetWeakPtr(),
+                                base::Unretained(delegate)));
 }
 
 void AutofillAction::OnWaitForElement(ActionDelegate* delegate,
diff --git a/components/autofill_assistant/browser/actions/autofill_action_unittest.cc b/components/autofill_assistant/browser/actions/autofill_action_unittest.cc
index ae14a9ef..3462299a 100644
--- a/components/autofill_assistant/browser/actions/autofill_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/autofill_action_unittest.cc
@@ -120,8 +120,8 @@
                                      base::OnceCallback<void()> all_done) {
           checker->Run(&mock_web_controller_, std::move(all_done));
         }));
-    ON_CALL(mock_action_delegate_, OnShortWaitForElement(_, _, _))
-        .WillByDefault(RunOnceCallback<2>(true));
+    ON_CALL(mock_action_delegate_, OnShortWaitForElement(_, _))
+        .WillByDefault(RunOnceCallback<1>(true));
   }
 
  protected:
diff --git a/components/autofill_assistant/browser/actions/click_action.cc b/components/autofill_assistant/browser/actions/click_action.cc
index 8cca8b8..eb44cd4 100644
--- a/components/autofill_assistant/browser/actions/click_action.cc
+++ b/components/autofill_assistant/browser/actions/click_action.cc
@@ -21,16 +21,24 @@
 
 void ClickAction::InternalProcessAction(ActionDelegate* delegate,
                                         ProcessActionCallback callback) {
-  DCHECK_GT(proto_.click().element_to_click().selectors_size(), 0);
+  Selector selector =
+      Selector(proto_.click().element_to_click()).MustBeVisible();
+  if (selector.empty()) {
+    DVLOG(1) << __func__ << ": empty selector";
+    UpdateProcessedAction(INVALID_SELECTOR);
+    std::move(callback).Run(std::move(processed_action_proto_));
+    return;
+  }
   delegate->ShortWaitForElement(
-      kVisibilityCheck, Selector(proto_.click().element_to_click()),
+      selector,
       base::BindOnce(&ClickAction::OnWaitForElement,
                      weak_ptr_factory_.GetWeakPtr(), base::Unretained(delegate),
-                     std::move(callback)));
+                     std::move(callback), selector));
 }
 
 void ClickAction::OnWaitForElement(ActionDelegate* delegate,
                                    ProcessActionCallback callback,
+                                   const Selector& selector,
                                    bool element_found) {
   if (!element_found) {
     UpdateProcessedAction(ELEMENT_RESOLUTION_FAILED);
@@ -39,7 +47,7 @@
   }
 
   delegate->ClickOrTapElement(
-      Selector(proto_.click().element_to_click()),
+      selector,
       base::BindOnce(&::autofill_assistant::ClickAction::OnClick,
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
 }
diff --git a/components/autofill_assistant/browser/actions/click_action.h b/components/autofill_assistant/browser/actions/click_action.h
index 3178042..7ea4728 100644
--- a/components/autofill_assistant/browser/actions/click_action.h
+++ b/components/autofill_assistant/browser/actions/click_action.h
@@ -29,6 +29,7 @@
 
   void OnWaitForElement(ActionDelegate* delegate,
                         ProcessActionCallback callback,
+                        const Selector& selector,
                         bool element_found);
   void OnClick(ProcessActionCallback callback, const ClientStatus& status);
 
diff --git a/components/autofill_assistant/browser/actions/focus_element_action.cc b/components/autofill_assistant/browser/actions/focus_element_action.cc
index 176941ce..ca8c8819 100644
--- a/components/autofill_assistant/browser/actions/focus_element_action.cc
+++ b/components/autofill_assistant/browser/actions/focus_element_action.cc
@@ -24,20 +24,26 @@
 void FocusElementAction::InternalProcessAction(ActionDelegate* delegate,
                                                ProcessActionCallback callback) {
   const FocusElementProto& focus_element = proto_.focus_element();
-  DCHECK_GT(focus_element.element().selectors_size(), 0);
-
   if (!focus_element.title().empty()) {
     delegate->SetStatusMessage(focus_element.title());
   }
+  Selector selector = Selector(focus_element.element()).MustBeVisible();
+  if (selector.empty()) {
+    DVLOG(1) << __func__ << ": empty selector";
+    UpdateProcessedAction(INVALID_SELECTOR);
+    std::move(callback).Run(std::move(processed_action_proto_));
+    return;
+  }
   delegate->ShortWaitForElement(
-      kVisibilityCheck, Selector(focus_element.element()),
+      selector,
       base::BindOnce(&FocusElementAction::OnWaitForElement,
                      weak_ptr_factory_.GetWeakPtr(), base::Unretained(delegate),
-                     std::move(callback)));
+                     std::move(callback), selector));
 }
 
 void FocusElementAction::OnWaitForElement(ActionDelegate* delegate,
                                           ProcessActionCallback callback,
+                                          const Selector& selector,
                                           bool element_found) {
   if (!element_found) {
     UpdateProcessedAction(ELEMENT_RESOLUTION_FAILED);
@@ -46,7 +52,7 @@
   }
 
   delegate->FocusElement(
-      Selector(proto_.focus_element().element()),
+      selector,
       base::BindOnce(&FocusElementAction::OnFocusElement,
                      weak_ptr_factory_.GetWeakPtr(), base::Unretained(delegate),
                      std::move(callback)));
diff --git a/components/autofill_assistant/browser/actions/focus_element_action.h b/components/autofill_assistant/browser/actions/focus_element_action.h
index a390450e..ff9ff0cb 100644
--- a/components/autofill_assistant/browser/actions/focus_element_action.h
+++ b/components/autofill_assistant/browser/actions/focus_element_action.h
@@ -11,6 +11,7 @@
 #include "base/memory/weak_ptr.h"
 
 namespace autofill_assistant {
+
 // An action to focus a given element on Web. Scrolling to it first if required.
 class FocusElementAction : public Action {
  public:
@@ -24,6 +25,7 @@
 
   void OnWaitForElement(ActionDelegate* delegate,
                         ProcessActionCallback callback,
+                        const Selector& selector,
                         bool element_found);
   void OnFocusElement(ActionDelegate* delegate,
                       ProcessActionCallback callback,
diff --git a/components/autofill_assistant/browser/actions/highlight_element_action.cc b/components/autofill_assistant/browser/actions/highlight_element_action.cc
index c15ceeb2..27235b0 100644
--- a/components/autofill_assistant/browser/actions/highlight_element_action.cc
+++ b/components/autofill_assistant/browser/actions/highlight_element_action.cc
@@ -22,16 +22,24 @@
 void HighlightElementAction::InternalProcessAction(
     ActionDelegate* delegate,
     ProcessActionCallback callback) {
-  DCHECK_GT(proto_.highlight_element().element().selectors_size(), 0);
+  Selector selector =
+      Selector(proto_.highlight_element().element()).MustBeVisible();
+  if (selector.empty()) {
+    DVLOG(1) << __func__ << ": empty selector";
+    UpdateProcessedAction(INVALID_SELECTOR);
+    std::move(callback).Run(std::move(processed_action_proto_));
+    return;
+  }
   delegate->ShortWaitForElement(
-      kVisibilityCheck, Selector(proto_.highlight_element().element()),
+      selector,
       base::BindOnce(&HighlightElementAction::OnWaitForElement,
                      weak_ptr_factory_.GetWeakPtr(), base::Unretained(delegate),
-                     std::move(callback)));
+                     std::move(callback), selector));
 }
 
 void HighlightElementAction::OnWaitForElement(ActionDelegate* delegate,
                                               ProcessActionCallback callback,
+                                              const Selector& selector,
                                               bool element_found) {
   if (!element_found) {
     UpdateProcessedAction(ELEMENT_RESOLUTION_FAILED);
@@ -40,7 +48,7 @@
   }
 
   delegate->HighlightElement(
-      Selector(proto_.highlight_element().element()),
+      selector,
       base::BindOnce(&HighlightElementAction::OnHighlightElement,
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
 }
diff --git a/components/autofill_assistant/browser/actions/highlight_element_action.h b/components/autofill_assistant/browser/actions/highlight_element_action.h
index 7f76232..ac9f151 100644
--- a/components/autofill_assistant/browser/actions/highlight_element_action.h
+++ b/components/autofill_assistant/browser/actions/highlight_element_action.h
@@ -13,6 +13,7 @@
 #include "components/autofill_assistant/browser/actions/action.h"
 
 namespace autofill_assistant {
+
 // An action to highlight an element on Web.
 // TODO(crbug.com/806868): This action should be more configurable instead of
 // using hardcoded css styling since it depends on the content of a page.
@@ -28,6 +29,7 @@
 
   void OnWaitForElement(ActionDelegate* delegate,
                         ProcessActionCallback callback,
+                        const Selector& selector,
                         bool element_found);
   void OnHighlightElement(ProcessActionCallback callback,
                           const ClientStatus& status);
diff --git a/components/autofill_assistant/browser/actions/mock_action_delegate.h b/components/autofill_assistant/browser/actions/mock_action_delegate.h
index 5c4399f..e1b3816 100644
--- a/components/autofill_assistant/browser/actions/mock_action_delegate.h
+++ b/components/autofill_assistant/browser/actions/mock_action_delegate.h
@@ -25,26 +25,23 @@
   MOCK_METHOD2(RunElementChecks,
                void(BatchElementChecker*, base::OnceCallback<void()>));
 
-  void ShortWaitForElement(ElementCheckType check_type,
-                           const Selector& selector,
+  void ShortWaitForElement(const Selector& selector,
                            base::OnceCallback<void(bool)> callback) override {
-    OnShortWaitForElement(check_type, selector, callback);
+    OnShortWaitForElement(selector, callback);
   }
 
-  MOCK_METHOD3(OnShortWaitForElement,
-               void(ElementCheckType check_type,
-                    const Selector& selector,
-                    base::OnceCallback<void(bool)>&));
+  MOCK_METHOD2(OnShortWaitForElement,
+               void(const Selector& selector, base::OnceCallback<void(bool)>&));
 
-  void WaitForElementVisible(
+  void WaitForElement(
       base::TimeDelta max_wait_time,
       bool allow_interrupt,
       const Selector& selector,
       base::OnceCallback<void(ProcessedActionStatusProto)> callback) override {
-    OnWaitForElementVisible(max_wait_time, allow_interrupt, selector, callback);
+    OnWaitForElement(max_wait_time, allow_interrupt, selector, callback);
   }
 
-  MOCK_METHOD4(OnWaitForElementVisible,
+  MOCK_METHOD4(OnWaitForElement,
                void(base::TimeDelta,
                     bool,
                     const Selector&,
diff --git a/components/autofill_assistant/browser/actions/prompt_action.cc b/components/autofill_assistant/browser/actions/prompt_action.cc
index d9f769f..f97baf1b 100644
--- a/components/autofill_assistant/browser/actions/prompt_action.cc
+++ b/components/autofill_assistant/browser/actions/prompt_action.cc
@@ -131,8 +131,8 @@
 
 bool PromptAction::HasAutoSelect() {
   for (int i = 0; i < proto_.prompt().choices_size(); i++) {
-    Selector selector(
-        proto_.prompt().choices(i).auto_select_if_element_exists());
+    Selector selector =
+        Selector(proto_.prompt().choices(i).auto_select_if_element_exists());
     if (!selector.empty())
       return true;
   }
@@ -145,15 +145,14 @@
   // Wait as long as necessary for one of the elements to show up. This is
   // cancelled by CancelPrompt()
   for (int i = 0; i < proto_.prompt().choices_size(); i++) {
-    Selector selector(
-        proto_.prompt().choices(i).auto_select_if_element_exists());
+    Selector selector =
+        Selector(proto_.prompt().choices(i).auto_select_if_element_exists());
     if (selector.empty())
       continue;
 
     auto_select_checker_->AddElementCheck(
-        kExistenceCheck, selector,
-        base::BindOnce(&PromptAction::OnAutoSelectElementExists,
-                       weak_ptr_factory_.GetWeakPtr(), i));
+        selector, base::BindOnce(&PromptAction::OnAutoSelectElementExists,
+                                 weak_ptr_factory_.GetWeakPtr(), i));
   }
   delegate_->RunElementChecks(auto_select_checker_.get(),
                               base::BindOnce(&PromptAction::OnAutoSelectDone,
diff --git a/components/autofill_assistant/browser/actions/prompt_action_unittest.cc b/components/autofill_assistant/browser/actions/prompt_action_unittest.cc
index 2d8368b..b8d748e 100644
--- a/components/autofill_assistant/browser/actions/prompt_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/prompt_action_unittest.cc
@@ -34,8 +34,8 @@
             base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME) {}
 
   void SetUp() override {
-    ON_CALL(mock_web_controller_, OnElementCheck(_, _, _))
-        .WillByDefault(RunOnceCallback<2>(false));
+    ON_CALL(mock_web_controller_, OnElementCheck(_, _))
+        .WillByDefault(RunOnceCallback<1>(false));
     ON_CALL(mock_web_controller_, OnGetFieldValue(_, _))
         .WillByDefault(RunOnceCallback<1>(false, ""));
 
@@ -120,14 +120,14 @@
   ASSERT_THAT(chips_, Pointee(IsEmpty()));
 
   EXPECT_CALL(mock_web_controller_,
-              OnElementCheck(kExistenceCheck, Eq(Selector({"element"})), _))
-      .WillRepeatedly(RunOnceCallback<2>(true));
+              OnElementCheck(Eq(Selector({"element"})), _))
+      .WillRepeatedly(RunOnceCallback<1>(true));
   task_env_.FastForwardBy(base::TimeDelta::FromSeconds(1));
   ASSERT_THAT(chips_, Pointee(SizeIs(1)));
 
   EXPECT_CALL(mock_web_controller_,
-              OnElementCheck(kExistenceCheck, Eq(Selector({"element"})), _))
-      .WillRepeatedly(RunOnceCallback<2>(false));
+              OnElementCheck(Eq(Selector({"element"})), _))
+      .WillRepeatedly(RunOnceCallback<1>(false));
   task_env_.FastForwardBy(base::TimeDelta::FromSeconds(1));
   ASSERT_THAT(chips_, Pointee(IsEmpty()));
 }
@@ -142,8 +142,8 @@
   action.ProcessAction(&mock_action_delegate_, callback_.Get());
 
   EXPECT_CALL(mock_web_controller_,
-              OnElementCheck(kExistenceCheck, Eq(Selector({"element"})), _))
-      .WillRepeatedly(RunOnceCallback<2>(true));
+              OnElementCheck(Eq(Selector({"element"})), _))
+      .WillRepeatedly(RunOnceCallback<1>(true));
 
   EXPECT_CALL(mock_action_delegate_, CancelPrompt());
   EXPECT_CALL(
@@ -173,8 +173,8 @@
   ASSERT_THAT(chips_, Pointee(SizeIs(1)));
 
   EXPECT_CALL(mock_web_controller_,
-              OnElementCheck(kExistenceCheck, Eq(Selector({"element"})), _))
-      .WillRepeatedly(RunOnceCallback<2>(true));
+              OnElementCheck(Eq(Selector({"element"})), _))
+      .WillRepeatedly(RunOnceCallback<1>(true));
   EXPECT_CALL(
       callback_,
       Run(Pointee(AllOf(Property(&ProcessedActionProto::status, ACTION_APPLIED),
diff --git a/components/autofill_assistant/browser/actions/select_option_action.cc b/components/autofill_assistant/browser/actions/select_option_action.cc
index 508d282f..5c9572d 100644
--- a/components/autofill_assistant/browser/actions/select_option_action.cc
+++ b/components/autofill_assistant/browser/actions/select_option_action.cc
@@ -24,18 +24,29 @@
   const SelectOptionProto& select_option = proto_.select_option();
 
   // A non prefilled |select_option| is not supported.
-  DCHECK(select_option.has_selected_option());
-  DCHECK_GT(select_option.element().selectors_size(), 0);
-
+  if (!select_option.has_selected_option()) {
+    DVLOG(1) << __func__ << ": empty option";
+    UpdateProcessedAction(INVALID_ACTION);
+    std::move(callback).Run(std::move(processed_action_proto_));
+    return;
+  }
+  Selector selector = Selector(select_option.element());
+  if (selector.empty()) {
+    DVLOG(1) << __func__ << ": empty selector";
+    UpdateProcessedAction(INVALID_SELECTOR);
+    std::move(callback).Run(std::move(processed_action_proto_));
+    return;
+  }
   delegate->ShortWaitForElement(
-      kExistenceCheck, Selector(select_option.element()),
+      selector,
       base::BindOnce(&SelectOptionAction::OnWaitForElement,
                      weak_ptr_factory_.GetWeakPtr(), base::Unretained(delegate),
-                     std::move(callback)));
+                     std::move(callback), selector));
 }
 
 void SelectOptionAction::OnWaitForElement(ActionDelegate* delegate,
                                           ProcessActionCallback callback,
+                                          const Selector& selector,
                                           bool element_found) {
   if (!element_found) {
     UpdateProcessedAction(ELEMENT_RESOLUTION_FAILED);
@@ -44,8 +55,7 @@
   }
 
   delegate->SelectOption(
-      Selector(proto_.select_option().element()),
-      proto_.select_option().selected_option(),
+      selector, proto_.select_option().selected_option(),
       base::BindOnce(&::autofill_assistant::SelectOptionAction::OnSelectOption,
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
 }
diff --git a/components/autofill_assistant/browser/actions/select_option_action.h b/components/autofill_assistant/browser/actions/select_option_action.h
index 6fd743394..64c5081 100644
--- a/components/autofill_assistant/browser/actions/select_option_action.h
+++ b/components/autofill_assistant/browser/actions/select_option_action.h
@@ -13,6 +13,7 @@
 #include "components/autofill_assistant/browser/actions/action.h"
 
 namespace autofill_assistant {
+
 // An action to select an option on a given element on Web.
 class SelectOptionAction : public Action {
  public:
@@ -26,6 +27,7 @@
 
   void OnWaitForElement(ActionDelegate* delegate,
                         ProcessActionCallback callback,
+                        const Selector& selector,
                         bool element_found);
   void OnSelectOption(ProcessActionCallback callback,
                       const ClientStatus& status);
diff --git a/components/autofill_assistant/browser/actions/set_attribute_action.cc b/components/autofill_assistant/browser/actions/set_attribute_action.cc
index 7ecb8304..9a7ae57 100644
--- a/components/autofill_assistant/browser/actions/set_attribute_action.cc
+++ b/components/autofill_assistant/browser/actions/set_attribute_action.cc
@@ -22,15 +22,23 @@
 
 void SetAttributeAction::InternalProcessAction(ActionDelegate* delegate,
                                                ProcessActionCallback callback) {
+  Selector selector = Selector(proto_.set_attribute().element());
+  if (selector.empty()) {
+    DVLOG(1) << __func__ << ": empty selector";
+    UpdateProcessedAction(INVALID_SELECTOR);
+    std::move(callback).Run(std::move(processed_action_proto_));
+    return;
+  }
   delegate->ShortWaitForElement(
-      kExistenceCheck, Selector(proto_.set_attribute().element()),
+      selector,
       base::BindOnce(&SetAttributeAction::OnWaitForElement,
                      weak_ptr_factory_.GetWeakPtr(), base::Unretained(delegate),
-                     std::move(callback)));
+                     std::move(callback), selector));
 }
 
 void SetAttributeAction::OnWaitForElement(ActionDelegate* delegate,
                                           ProcessActionCallback callback,
+                                          const Selector& selector,
                                           bool element_found) {
   if (!element_found) {
     UpdateProcessedAction(ELEMENT_RESOLUTION_FAILED);
@@ -39,8 +47,7 @@
   }
 
   delegate->SetAttribute(
-      Selector(proto_.set_attribute().element()),
-      ExtractVector(proto_.set_attribute().attribute()),
+      selector, ExtractVector(proto_.set_attribute().attribute()),
       proto_.set_attribute().value(),
       base::BindOnce(&SetAttributeAction::OnSetAttribute,
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
diff --git a/components/autofill_assistant/browser/actions/set_attribute_action.h b/components/autofill_assistant/browser/actions/set_attribute_action.h
index 3bd8807..83947df 100644
--- a/components/autofill_assistant/browser/actions/set_attribute_action.h
+++ b/components/autofill_assistant/browser/actions/set_attribute_action.h
@@ -13,6 +13,7 @@
 #include "components/autofill_assistant/browser/actions/action.h"
 
 namespace autofill_assistant {
+
 // An action to set the attribute of an element.
 class SetAttributeAction : public Action {
  public:
@@ -26,6 +27,7 @@
 
   void OnWaitForElement(ActionDelegate* delegate,
                         ProcessActionCallback callback,
+                        const Selector& selector,
                         bool element_found);
   void OnSetAttribute(ProcessActionCallback callback,
                       const ClientStatus& status);
diff --git a/components/autofill_assistant/browser/actions/set_form_field_value_action.cc b/components/autofill_assistant/browser/actions/set_form_field_value_action.cc
index 8550e3b..67f5208 100644
--- a/components/autofill_assistant/browser/actions/set_form_field_value_action.cc
+++ b/components/autofill_assistant/browser/actions/set_form_field_value_action.cc
@@ -26,15 +26,24 @@
 void SetFormFieldValueAction::InternalProcessAction(
     ActionDelegate* delegate,
     ProcessActionCallback callback) {
+  Selector selector =
+      Selector(proto_.set_form_value().element()).MustBeVisible();
+  if (selector.empty()) {
+    DVLOG(1) << __func__ << ": empty selector";
+    UpdateProcessedAction(INVALID_SELECTOR);
+    std::move(callback).Run(std::move(processed_action_proto_));
+    return;
+  }
   delegate->ShortWaitForElement(
-      kVisibilityCheck, Selector(proto_.set_form_value().element()),
+      selector,
       base::BindOnce(&SetFormFieldValueAction::OnWaitForElement,
                      weak_ptr_factory_.GetWeakPtr(), base::Unretained(delegate),
-                     std::move(callback)));
+                     std::move(callback), selector));
 }
 
 void SetFormFieldValueAction::OnWaitForElement(ActionDelegate* delegate,
                                                ProcessActionCallback callback,
+                                               const Selector& selector,
                                                bool element_found) {
   if (!element_found) {
     UpdateProcessedAction(ELEMENT_RESOLUTION_FAILED);
@@ -42,12 +51,13 @@
     return;
   }
   // Start with first value, then call OnSetFieldValue() recursively until done.
-  OnSetFieldValue(delegate, std::move(callback),
-                  /* next = */ 0, OkClientStatus());
+  OnSetFieldValue(delegate, std::move(callback), selector, /* next = */ 0,
+                  OkClientStatus());
 }
 
 void SetFormFieldValueAction::OnSetFieldValue(ActionDelegate* delegate,
                                               ProcessActionCallback callback,
+                                              const Selector& selector,
                                               int next,
                                               const ClientStatus& status) {
   // If something went wrong or we are out of values: finish
@@ -58,7 +68,6 @@
   }
 
   const auto& key_field = proto_.set_form_value().value(next);
-  const auto& selector = Selector(proto_.set_form_value().element());
   bool simulate_key_presses = proto_.set_form_value().simulate_key_presses();
   switch (key_field.keypress_case()) {
     case SetFormFieldValueProto_KeyPress::kText:
@@ -70,7 +79,7 @@
             selector, key_field.text(), simulate_key_presses,
             base::BindOnce(&SetFormFieldValueAction::OnSetFieldValue,
                            weak_ptr_factory_.GetWeakPtr(), delegate,
-                           std::move(callback),
+                           std::move(callback), selector,
                            /* next = */ next + 1));
       } else {
         // Trigger a check for keyboard fallback when |SetFieldValue| is done.
@@ -79,7 +88,7 @@
             base::BindOnce(
                 &SetFormFieldValueAction::OnSetFieldValueAndCheckFallback,
                 weak_ptr_factory_.GetWeakPtr(), delegate, std::move(callback),
-                /* next = */ next));
+                selector, /* next = */ next));
       }
       break;
     case SetFormFieldValueProto_KeyPress::kKeycode:
@@ -92,14 +101,14 @@
             selector, {key_field.keycode()},
             base::BindOnce(&SetFormFieldValueAction::OnSetFieldValue,
                            weak_ptr_factory_.GetWeakPtr(), delegate,
-                           std::move(callback),
+                           std::move(callback), selector,
                            /* next = */ next + 1));
       } else {
         DVLOG(3)
             << "SetFormFieldValueProto_KeyPress: field `keycode' is deprecated "
             << "and only supports US-ASCII values (encountered "
             << key_field.keycode() << "). Use field `key' instead.";
-        OnSetFieldValue(delegate, std::move(callback), next,
+        OnSetFieldValue(delegate, std::move(callback), selector, next,
                         ClientStatus(INVALID_ACTION));
       }
       break;
@@ -108,12 +117,12 @@
           selector, UTF8ToUnicode(key_field.keyboard_input()),
           base::BindOnce(&SetFormFieldValueAction::OnSetFieldValue,
                          weak_ptr_factory_.GetWeakPtr(), delegate,
-                         std::move(callback),
+                         std::move(callback), selector,
                          /* next = */ next + 1));
       break;
     default:
       DVLOG(1) << "Unrecognized field for SetFormFieldValueProto_KeyPress";
-      OnSetFieldValue(delegate, std::move(callback), next,
+      OnSetFieldValue(delegate, std::move(callback), selector, next,
                       ClientStatus(INVALID_ACTION));
       break;
   }
@@ -122,30 +131,31 @@
 void SetFormFieldValueAction::OnSetFieldValueAndCheckFallback(
     ActionDelegate* delegate,
     ProcessActionCallback callback,
+    const Selector& selector,
     int next,
     const ClientStatus& status) {
   if (!status.ok()) {
-    OnSetFieldValue(delegate, std::move(callback), next + 1, status);
+    OnSetFieldValue(delegate, std::move(callback), selector, next + 1, status);
     return;
   }
   delegate->GetFieldValue(
-      Selector(proto_.set_form_value().element()),
-      base::BindOnce(&SetFormFieldValueAction::OnGetFieldValue,
-                     weak_ptr_factory_.GetWeakPtr(), delegate,
-                     std::move(callback), next));
+      selector, base::BindOnce(&SetFormFieldValueAction::OnGetFieldValue,
+                               weak_ptr_factory_.GetWeakPtr(), delegate,
+                               std::move(callback), selector, next));
 }
 
 void SetFormFieldValueAction::OnGetFieldValue(ActionDelegate* delegate,
                                               ProcessActionCallback callback,
+                                              const Selector& selector,
                                               int next,
                                               bool get_value_status,
                                               const std::string& value) {
   const auto& key_field = proto_.set_form_value().value(next);
-  const auto& selector = Selector(proto_.set_form_value().element());
 
   // Move to next value if |GetFieldValue| failed.
   if (!get_value_status) {
-    OnSetFieldValue(delegate, std::move(callback), next + 1, OkClientStatus());
+    OnSetFieldValue(delegate, std::move(callback), selector, next + 1,
+                    OkClientStatus());
     return;
   }
 
@@ -163,13 +173,14 @@
         selector, key_field.text(), /*simulate_key_presses = */ true,
         base::BindOnce(&SetFormFieldValueAction::OnSetFieldValue,
                        weak_ptr_factory_.GetWeakPtr(), delegate,
-                       std::move(callback),
+                       std::move(callback), selector,
                        /* next = */ next + 1));
     return;
   }
 
   // Move to next value in all other cases.
-  OnSetFieldValue(delegate, std::move(callback), next + 1, OkClientStatus());
+  OnSetFieldValue(delegate, std::move(callback), selector, next + 1,
+                  OkClientStatus());
 }
 
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/actions/set_form_field_value_action.h b/components/autofill_assistant/browser/actions/set_form_field_value_action.h
index 0ac0c52..69222c0 100644
--- a/components/autofill_assistant/browser/actions/set_form_field_value_action.h
+++ b/components/autofill_assistant/browser/actions/set_form_field_value_action.h
@@ -13,6 +13,7 @@
 #include "components/autofill_assistant/browser/actions/action.h"
 
 namespace autofill_assistant {
+
 // An action to set the value of a form input element.
 class SetFormFieldValueAction : public Action {
  public:
@@ -26,21 +27,25 @@
 
   void OnWaitForElement(ActionDelegate* delegate,
                         ProcessActionCallback callback,
+                        const Selector& selector,
                         bool element_found);
 
   void OnGetFieldValue(ActionDelegate* delegate,
                        ProcessActionCallback callback,
+                       const Selector& selector,
                        int next,
                        bool status,
                        const std::string& value);
 
   void OnSetFieldValue(ActionDelegate* delegate,
                        ProcessActionCallback callback,
+                       const Selector& selector,
                        int next,
                        const ClientStatus& status);
 
   void OnSetFieldValueAndCheckFallback(ActionDelegate* delegate,
                                        ProcessActionCallback callback,
+                                       const Selector& selector,
                                        int next,
                                        const ClientStatus& status);
 
diff --git a/components/autofill_assistant/browser/actions/upload_dom_action.cc b/components/autofill_assistant/browser/actions/upload_dom_action.cc
index e79e5153..f1d45d9 100644
--- a/components/autofill_assistant/browser/actions/upload_dom_action.cc
+++ b/components/autofill_assistant/browser/actions/upload_dom_action.cc
@@ -21,16 +21,22 @@
 
 void UploadDomAction::InternalProcessAction(ActionDelegate* delegate,
                                             ProcessActionCallback callback) {
-  DCHECK_GT(proto_.upload_dom().tree_root().selectors_size(), 0);
+  Selector selector = Selector(proto_.upload_dom().tree_root());
+  if (selector.empty()) {
+    DVLOG(1) << __func__ << ": empty selector";
+    UpdateProcessedAction(INVALID_SELECTOR);
+    return;
+  }
   delegate->ShortWaitForElement(
-      kExistenceCheck, Selector(proto_.upload_dom().tree_root()),
+      selector,
       base::BindOnce(&UploadDomAction::OnWaitForElement,
                      weak_ptr_factory_.GetWeakPtr(), base::Unretained(delegate),
-                     std::move(callback)));
+                     std::move(callback), selector));
 }
 
 void UploadDomAction::OnWaitForElement(ActionDelegate* delegate,
                                        ProcessActionCallback callback,
+                                       const Selector& selector,
                                        bool element_found) {
   if (!element_found) {
     UpdateProcessedAction(ELEMENT_RESOLUTION_FAILED);
@@ -39,7 +45,7 @@
   }
 
   delegate->GetOuterHtml(
-      Selector(proto_.upload_dom().tree_root()),
+      selector,
       base::BindOnce(&UploadDomAction::OnGetOuterHtml,
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
 }
diff --git a/components/autofill_assistant/browser/actions/upload_dom_action.h b/components/autofill_assistant/browser/actions/upload_dom_action.h
index c53ab60..17d64a0 100644
--- a/components/autofill_assistant/browser/actions/upload_dom_action.h
+++ b/components/autofill_assistant/browser/actions/upload_dom_action.h
@@ -25,6 +25,7 @@
 
   void OnWaitForElement(ActionDelegate* delegate,
                         ProcessActionCallback callback,
+                        const Selector& selector,
                         bool element_found);
   void OnGetOuterHtml(ProcessActionCallback callback,
                       const ClientStatus& status,
diff --git a/components/autofill_assistant/browser/actions/wait_for_dom_action.cc b/components/autofill_assistant/browser/actions/wait_for_dom_action.cc
index 9b3db5f..a58a7a7 100644
--- a/components/autofill_assistant/browser/actions/wait_for_dom_action.cc
+++ b/components/autofill_assistant/browser/actions/wait_for_dom_action.cc
@@ -27,10 +27,11 @@
 
 void WaitForDomAction::InternalProcessAction(ActionDelegate* delegate,
                                              ProcessActionCallback callback) {
-  DCHECK_GT(proto_.wait_for_dom().selectors_size(), 0);
-  Selector a_selector;
-  for (const auto& selector : proto_.wait_for_dom().selectors()) {
-    a_selector.selectors.emplace_back(selector);
+  Selector selector = Selector(proto_.wait_for_dom().wait_until());
+  if (selector.empty()) {
+    DVLOG(1) << __func__ << ": no selector specified for WaitForDom";
+    OnCheckDone(std::move(callback), INVALID_SELECTOR);
+    return;
   }
 
   base::TimeDelta max_wait_time = kDefaultCheckDuration;
@@ -38,8 +39,8 @@
   if (timeout_ms > 0)
     max_wait_time = base::TimeDelta::FromMilliseconds(timeout_ms);
 
-  delegate->WaitForElementVisible(
-      max_wait_time, proto_.wait_for_dom().allow_interrupt(), a_selector,
+  delegate->WaitForElement(
+      max_wait_time, proto_.wait_for_dom().allow_interrupt(), selector,
       base::BindOnce(&WaitForDomAction::OnCheckDone,
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
 }
diff --git a/components/autofill_assistant/browser/batch_element_checker.cc b/components/autofill_assistant/browser/batch_element_checker.cc
index f3f0989..741ee50 100644
--- a/components/autofill_assistant/browser/batch_element_checker.cc
+++ b/components/autofill_assistant/browser/batch_element_checker.cc
@@ -18,13 +18,11 @@
 
 BatchElementChecker::~BatchElementChecker() {}
 
-void BatchElementChecker::AddElementCheck(ElementCheckType check_type,
-                                          const Selector& selector,
+void BatchElementChecker::AddElementCheck(const Selector& selector,
                                           ElementCheckCallback callback) {
   DCHECK(!started_);
 
-  element_check_callbacks_[std::make_pair(check_type, selector)].emplace_back(
-      std::move(callback));
+  element_check_callbacks_[selector].emplace_back(std::move(callback));
 }
 
 void BatchElementChecker::AddFieldValueCheck(const Selector& selector,
@@ -49,9 +47,8 @@
       element_check_callbacks_.size() + get_field_value_callbacks_.size() + 1;
 
   for (auto& entry : element_check_callbacks_) {
-    const auto& call_arguments = entry.first;
     web_controller->ElementCheck(
-        call_arguments.first, call_arguments.second, /* strict= */ false,
+        entry.first, /* strict= */ false,
         base::BindOnce(
             &BatchElementChecker::OnElementChecked,
             weak_ptr_factory_.GetWeakPtr(),
diff --git a/components/autofill_assistant/browser/batch_element_checker.h b/components/autofill_assistant/browser/batch_element_checker.h
index 161c43c..ff41fabc4 100644
--- a/components/autofill_assistant/browser/batch_element_checker.h
+++ b/components/autofill_assistant/browser/batch_element_checker.h
@@ -20,9 +20,6 @@
 namespace autofill_assistant {
 class WebController;
 
-// Types of element checks.
-enum ElementCheckType { kExistenceCheck, kVisibilityCheck };
-
 // Helper for checking a set of elements at the same time. It avoids duplicate
 // checks.
 class BatchElementChecker {
@@ -45,16 +42,8 @@
 
   // Checks an an element.
   //
-  // kElementCheck checks whether at least one element given by |selector|
-  // exists on the web page.
-  //
-  // kVisibilityCheck checks whether at least one element given by |selector|
-  // is visible on the page.
-  //
   // New element checks cannot be added once Run has been called.
-  void AddElementCheck(ElementCheckType check_type,
-                       const Selector& selector,
-                       ElementCheckCallback callback);
+  void AddElementCheck(const Selector& selector, ElementCheckCallback callback);
 
   // Gets the value of |selector| and return the result through |callback|. The
   // returned value will be the empty string in case of error or empty value.
@@ -79,8 +68,7 @@
 
   // A map of ElementCheck arguments (check_type, selector) to callbacks that
   // take the result of the check.
-  std::map<std::pair<ElementCheckType, Selector>,
-           std::vector<ElementCheckCallback>>
+  std::map<Selector, std::vector<ElementCheckCallback>>
       element_check_callbacks_;
 
   // A map of GetFieldValue arguments (selector) to callbacks that take the
diff --git a/components/autofill_assistant/browser/batch_element_checker_unittest.cc b/components/autofill_assistant/browser/batch_element_checker_unittest.cc
index d6e7d37e..dd9e7a2 100644
--- a/components/autofill_assistant/browser/batch_element_checker_unittest.cc
+++ b/components/autofill_assistant/browser/batch_element_checker_unittest.cc
@@ -41,14 +41,15 @@
                           base::Unretained(this), name);
   }
 
-  void OnElementVisibilityCheck(const std::string& name, bool result) {
+  void OnVisibilityRequirementCheck(const std::string& name, bool result) {
     element_visible_results_[name] = result;
   }
 
-  BatchElementChecker::ElementCheckCallback ElementVisibilityCallback(
+  BatchElementChecker::ElementCheckCallback VisibilityRequirementCallback(
       const std::string& name) {
-    return base::BindOnce(&BatchElementCheckerTest::OnElementVisibilityCheck,
-                          base::Unretained(this), name);
+    return base::BindOnce(
+        &BatchElementCheckerTest::OnVisibilityRequirementCheck,
+        base::Unretained(this), name);
   }
 
   void OnFieldValueCheck(const std::string& name,
@@ -84,16 +85,15 @@
 
 TEST_F(BatchElementCheckerTest, Empty) {
   EXPECT_TRUE(checks_.empty());
-  checks_.AddElementCheck(kExistenceCheck, Selector({"exists"}),
+  checks_.AddElementCheck(Selector({"exists"}),
                           ElementExistenceCallback("exists"));
   EXPECT_FALSE(checks_.empty());
 }
 
 TEST_F(BatchElementCheckerTest, OneElementFound) {
-  EXPECT_CALL(mock_web_controller_,
-              OnElementCheck(kExistenceCheck, Eq(Selector({"exists"})), _))
-      .WillOnce(RunOnceCallback<2>(true));
-  checks_.AddElementCheck(kExistenceCheck, Selector({"exists"}),
+  EXPECT_CALL(mock_web_controller_, OnElementCheck(Eq(Selector({"exists"})), _))
+      .WillOnce(RunOnceCallback<1>(true));
+  checks_.AddElementCheck(Selector({"exists"}),
                           ElementExistenceCallback("exists"));
   Run("was_run");
 
@@ -102,11 +102,10 @@
 }
 
 TEST_F(BatchElementCheckerTest, OneElementNotFound) {
-  EXPECT_CALL(
-      mock_web_controller_,
-      OnElementCheck(kExistenceCheck, Eq(Selector({"does_not_exist"})), _))
-      .WillOnce(RunOnceCallback<2>(false));
-  checks_.AddElementCheck(kExistenceCheck, Selector({"does_not_exist"}),
+  EXPECT_CALL(mock_web_controller_,
+              OnElementCheck(Eq(Selector({"does_not_exist"})), _))
+      .WillOnce(RunOnceCallback<1>(false));
+  checks_.AddElementCheck(Selector({"does_not_exist"}),
                           ElementExistenceCallback("does_not_exist"));
   Run("was_run");
 
@@ -145,26 +144,20 @@
 }
 
 TEST_F(BatchElementCheckerTest, MultipleElements) {
-  EXPECT_CALL(mock_web_controller_,
-              OnElementCheck(kExistenceCheck, Eq(Selector({"1"})), _))
-      .WillOnce(RunOnceCallback<2>(true));
-  EXPECT_CALL(mock_web_controller_,
-              OnElementCheck(kExistenceCheck, Eq(Selector({"2"})), _))
-      .WillOnce(RunOnceCallback<2>(true));
-  EXPECT_CALL(mock_web_controller_,
-              OnElementCheck(kExistenceCheck, Eq(Selector({"3"})), _))
-      .WillOnce(RunOnceCallback<2>(false));
+  EXPECT_CALL(mock_web_controller_, OnElementCheck(Eq(Selector({"1"})), _))
+      .WillOnce(RunOnceCallback<1>(true));
+  EXPECT_CALL(mock_web_controller_, OnElementCheck(Eq(Selector({"2"})), _))
+      .WillOnce(RunOnceCallback<1>(true));
+  EXPECT_CALL(mock_web_controller_, OnElementCheck(Eq(Selector({"3"})), _))
+      .WillOnce(RunOnceCallback<1>(false));
   EXPECT_CALL(mock_web_controller_, OnGetFieldValue(Eq(Selector({"4"})), _))
       .WillOnce(RunOnceCallback<1>(true, "value"));
   EXPECT_CALL(mock_web_controller_, OnGetFieldValue(Eq(Selector({"5"})), _))
       .WillOnce(RunOnceCallback<1>(false, ""));
 
-  checks_.AddElementCheck(kExistenceCheck, Selector({"1"}),
-                          ElementExistenceCallback("1"));
-  checks_.AddElementCheck(kExistenceCheck, Selector({"2"}),
-                          ElementExistenceCallback("2"));
-  checks_.AddElementCheck(kExistenceCheck, Selector({"3"}),
-                          ElementExistenceCallback("3"));
+  checks_.AddElementCheck(Selector({"1"}), ElementExistenceCallback("1"));
+  checks_.AddElementCheck(Selector({"2"}), ElementExistenceCallback("2"));
+  checks_.AddElementCheck(Selector({"3"}), ElementExistenceCallback("3"));
   checks_.AddFieldValueCheck(Selector({"4"}), FieldValueCallback("4"));
   checks_.AddFieldValueCheck(Selector({"5"}), FieldValueCallback("5"));
   Run("was_run");
@@ -178,19 +171,15 @@
 }
 
 TEST_F(BatchElementCheckerTest, DeduplicateElementExists) {
-  EXPECT_CALL(mock_web_controller_,
-              OnElementCheck(kExistenceCheck, Eq(Selector({"1"})), _))
-      .WillOnce(RunOnceCallback<2>(true));
-  EXPECT_CALL(mock_web_controller_,
-              OnElementCheck(kExistenceCheck, Eq(Selector({"2"})), _))
-      .WillOnce(RunOnceCallback<2>(true));
+  EXPECT_CALL(mock_web_controller_, OnElementCheck(Eq(Selector({"1"})), _))
+      .WillOnce(RunOnceCallback<1>(true));
+  EXPECT_CALL(mock_web_controller_, OnElementCheck(Eq(Selector({"2"})), _))
+      .WillOnce(RunOnceCallback<1>(true));
 
-  checks_.AddElementCheck(kExistenceCheck, Selector({"1"}),
-                          ElementExistenceCallback("first 1"));
-  checks_.AddElementCheck(kExistenceCheck, Selector({"1"}),
+  checks_.AddElementCheck(Selector({"1"}), ElementExistenceCallback("first 1"));
+  checks_.AddElementCheck(Selector({"1"}),
                           ElementExistenceCallback("second 1"));
-  checks_.AddElementCheck(kExistenceCheck, Selector({"2"}),
-                          ElementExistenceCallback("2"));
+  checks_.AddElementCheck(Selector({"2"}), ElementExistenceCallback("2"));
 
   Run("was_run");
 
@@ -202,18 +191,18 @@
 
 TEST_F(BatchElementCheckerTest, DeduplicateElementVisible) {
   EXPECT_CALL(mock_web_controller_,
-              OnElementCheck(kVisibilityCheck, Eq(Selector({"1"})), _))
-      .WillOnce(RunOnceCallback<2>(true));
+              OnElementCheck(Eq(Selector({"1"}).MustBeVisible()), _))
+      .WillOnce(RunOnceCallback<1>(true));
   EXPECT_CALL(mock_web_controller_,
-              OnElementCheck(kVisibilityCheck, Eq(Selector({"2"})), _))
-      .WillOnce(RunOnceCallback<2>(true));
+              OnElementCheck(Eq(Selector({"2"}).MustBeVisible()), _))
+      .WillOnce(RunOnceCallback<1>(true));
 
-  checks_.AddElementCheck(kVisibilityCheck, Selector({"1"}),
-                          ElementVisibilityCallback("first 1"));
-  checks_.AddElementCheck(kVisibilityCheck, Selector({"1"}),
-                          ElementVisibilityCallback("second 1"));
-  checks_.AddElementCheck(kVisibilityCheck, Selector({"2"}),
-                          ElementVisibilityCallback("2"));
+  checks_.AddElementCheck(Selector({"1"}).MustBeVisible(),
+                          VisibilityRequirementCallback("first 1"));
+  checks_.AddElementCheck(Selector({"1"}).MustBeVisible(),
+                          VisibilityRequirementCallback("second 1"));
+  checks_.AddElementCheck(Selector({"2"}).MustBeVisible(),
+                          VisibilityRequirementCallback("2"));
 
   Run("was_run");
 
diff --git a/components/autofill_assistant/browser/client_status.cc b/components/autofill_assistant/browser/client_status.cc
index 70c40695..ed08ec7 100644
--- a/components/autofill_assistant/browser/client_status.cc
+++ b/components/autofill_assistant/browser/client_status.cc
@@ -100,6 +100,10 @@
       out << "ELEMENT_UNSTABLE";
       break;
 
+    case ProcessedActionStatusProto::INVALID_SELECTOR:
+      out << "INVALID_SELECTOR";
+      break;
+
     case ProcessedActionStatusProto::OPTION_VALUE_NOT_FOUND:
       out << "OPTION_VALUE_NOT_FOUND";
       break;
diff --git a/components/autofill_assistant/browser/controller.cc b/components/autofill_assistant/browser/controller.cc
index f47a33d..847767c 100644
--- a/components/autofill_assistant/browser/controller.cc
+++ b/components/autofill_assistant/browser/controller.cc
@@ -110,8 +110,9 @@
   return memory_.get();
 }
 
-const std::map<std::string, std::string>& Controller::GetParameters() {
-  return parameters_;
+const TriggerContext* Controller::GetTriggerContext() {
+  DCHECK(trigger_context_);
+  return trigger_context_.get();
 }
 
 autofill::PersonalDataManager* Controller::GetPersonalDataManager() {
@@ -287,7 +288,7 @@
     script_domain_ = url.host();
     DVLOG(2) << "GetScripts for " << script_domain_;
     GetService()->GetScriptsForUrl(
-        url, parameters_,
+        url, trigger_context_.get(),
         base::BindOnce(&Controller::OnGetScripts, base::Unretained(this), url));
   } else {
     script_tracker()->CheckScripts();
@@ -516,7 +517,8 @@
 void Controller::OnGetCookie(bool has_cookie) {
   if (has_cookie) {
     // This code is only active with the experiment parameter.
-    parameters_.insert(
+    // TODO(crbug.com/806868): Remove the cookie experiment.
+    trigger_context_->script_parameters.insert(
         std::make_pair(kWebsiteVisitedBeforeParameterName, kTrueValue));
     OnSetCookie(has_cookie);
     return;
@@ -547,7 +549,7 @@
 
 void Controller::MaybeSetInitialDetails() {
   auto details = std::make_unique<Details>();
-  if (details->UpdateFromParameters(parameters_))
+  if (details->UpdateFromParameters(trigger_context_->script_parameters))
     SetDetails(std::move(details));
 }
 
@@ -557,12 +559,12 @@
 }
 
 void Controller::Start(const GURL& initial_url,
-                       const std::map<std::string, std::string>& parameters) {
+                       std::unique_ptr<TriggerContext> trigger_context) {
   if (state_ != AutofillAssistantState::INACTIVE) {
     NOTREACHED();
     return;
   }
-  parameters_ = parameters;
+  trigger_context_ = std::move(trigger_context);
   initial_url_ = initial_url;
   EnterState(AutofillAssistantState::STARTING);
   client_->ShowUI();
@@ -613,7 +615,7 @@
 
   dict.SetKey("status", base::Value(status_message_));
   std::vector<base::Value> parameters_js;
-  for (const auto& entry : parameters_) {
+  for (const auto& entry : trigger_context_->script_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));
@@ -879,8 +881,9 @@
 }
 
 bool Controller::IsCookieExperimentEnabled() const {
-  auto iter = parameters_.find(kCookieExperimentName);
-  return iter != parameters_.end() && iter->second == "1";
+  auto iter = trigger_context_->script_parameters.find(kCookieExperimentName);
+  return iter != trigger_context_->script_parameters.end() &&
+         iter->second == "1";
 }
 
 void Controller::OnTouchableAreaChanged(const std::vector<RectF>& areas) {
diff --git a/components/autofill_assistant/browser/controller.h b/components/autofill_assistant/browser/controller.h
index 30314c9..6e37ddd7 100644
--- a/components/autofill_assistant/browser/controller.h
+++ b/components/autofill_assistant/browser/controller.h
@@ -21,6 +21,7 @@
 #include "components/autofill_assistant/browser/script_tracker.h"
 #include "components/autofill_assistant/browser/service.h"
 #include "components/autofill_assistant/browser/state.h"
+#include "components/autofill_assistant/browser/trigger_context.h"
 #include "components/autofill_assistant/browser/ui_delegate.h"
 #include "components/autofill_assistant/browser/web_controller.h"
 #include "content/public/browser/web_contents_delegate.h"
@@ -58,7 +59,7 @@
 
   // Called when autofill assistant can start executing scripts.
   void Start(const GURL& initial_url,
-             const std::map<std::string, std::string>& parameters);
+             std::unique_ptr<TriggerContext> trigger_context);
 
   // Initiates a clean shutdown.
   //
@@ -80,7 +81,7 @@
   UiController* GetUiController() override;
   WebController* GetWebController() override;
   ClientMemory* GetClientMemory() override;
-  const std::map<std::string, std::string>& GetParameters() override;
+  const TriggerContext* GetTriggerContext() override;
   autofill::PersonalDataManager* GetPersonalDataManager() override;
   content::WebContents* GetWebContents() override;
   void SetTouchableElementArea(const ElementAreaProto& area) override;
@@ -213,7 +214,7 @@
 
   // Lazily instantiate in GetService().
   std::unique_ptr<Service> service_;
-  std::map<std::string, std::string> parameters_;
+  std::unique_ptr<TriggerContext> trigger_context_;
 
   // Lazily instantiate in GetClientMemory().
   std::unique_ptr<ClientMemory> memory_;
diff --git a/components/autofill_assistant/browser/controller_unittest.cc b/components/autofill_assistant/browser/controller_unittest.cc
index bdd24646..f983dbdf 100644
--- a/components/autofill_assistant/browser/controller_unittest.cc
+++ b/components/autofill_assistant/browser/controller_unittest.cc
@@ -15,6 +15,7 @@
 #include "components/autofill_assistant/browser/mock_ui_controller.h"
 #include "components/autofill_assistant/browser/mock_web_controller.h"
 #include "components/autofill_assistant/browser/service.h"
+#include "components/autofill_assistant/browser/trigger_context.h"
 #include "content/public/test/test_browser_context.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/web_contents_tester.h"
@@ -103,16 +104,16 @@
     ON_CALL(*mock_service_, OnGetActions(_, _, _, _, _, _))
         .WillByDefault(RunOnceCallback<5>(true, ""));
 
-    ON_CALL(*mock_service_, OnGetNextActions(_, _, _, _))
-        .WillByDefault(RunOnceCallback<3>(true, ""));
+    ON_CALL(*mock_service_, OnGetNextActions(_, _, _, _, _))
+        .WillByDefault(RunOnceCallback<4>(true, ""));
 
     ON_CALL(mock_ui_controller_, OnStateChanged(_))
         .WillByDefault(Invoke([this](AutofillAssistantState state) {
           states_.emplace_back(state);
         }));
 
-    ON_CALL(*mock_web_controller_, OnElementCheck(_, _, _))
-        .WillByDefault(RunOnceCallback<2>(false));
+    ON_CALL(*mock_web_controller_, OnElementCheck(_, _))
+        .WillByDefault(RunOnceCallback<1>(false));
   }
 
  protected:
@@ -144,7 +145,7 @@
   void Start() { Start("http://initialurl.com"); }
 
   void Start(const std::string& url) {
-    controller_->Start(GURL(url), /* parameters= */ {});
+    controller_->Start(GURL(url), std::make_unique<TriggerContext>());
   }
 
   void SetLastCommittedUrl(const GURL& url) {
@@ -401,13 +402,16 @@
 
 TEST_F(ControllerTest, ForwardParameters) {
   EXPECT_CALL(*mock_service_,
-              OnGetScriptsForUrl(_, Contains(Pair("a", "b")), _))
+              OnGetScriptsForUrl(_,
+                                 Field(&TriggerContext::script_parameters,
+                                       Contains(Pair("a", "b"))),
+                                 _))
       .WillOnce(RunOnceCallback<2>(true, ""));
 
   GURL initialUrl("http://example.com/");
-  std::map<std::string, std::string> parameters;
-  parameters["a"] = "b";
-  controller_->Start(initialUrl, parameters);
+  std::unique_ptr<TriggerContext> context(new TriggerContext);
+  context->script_parameters["a"] = "b";
+  controller_->Start(initialUrl, std::move(context));
 }
 
 TEST_F(ControllerTest, Autostart) {
@@ -499,7 +503,7 @@
   EXPECT_CALL(*mock_service_, OnGetScriptsForUrl(Eq(initialUrl), _, _))
       .WillOnce(RunOnceCallback<2>(true, ""));
 
-  controller_->Start(initialUrl, /* parameters= */ {});
+  controller_->Start(initialUrl, std::make_unique<TriggerContext>());
 }
 
 TEST_F(ControllerTest, CookieExperimentEnabled) {
@@ -511,9 +515,9 @@
   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);
+  std::unique_ptr<TriggerContext> trigger_context(new TriggerContext);
+  trigger_context->script_parameters.insert(std::make_pair("EXP_COOKIE", "1"));
+  controller_->Start(initialUrl, std::move(trigger_context));
 
   // TODO(crbug.com): Make IsCookieExperimentEnabled private and remove this
   // test when we pass the cookie data along in the initial request so that it
@@ -625,8 +629,8 @@
     EXPECT_EQ(AutofillAssistantState::STARTING, controller_->GetState());
   }
 
-  EXPECT_CALL(*mock_web_controller_, OnElementCheck(_, _, _))
-      .WillRepeatedly(RunOnceCallback<2>(true));
+  EXPECT_CALL(*mock_web_controller_, OnElementCheck(_, _))
+      .WillRepeatedly(RunOnceCallback<1>(true));
   thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1));
 
   EXPECT_EQ(AutofillAssistantState::AUTOSTART_FALLBACK_PROMPT,
diff --git a/components/autofill_assistant/browser/element_area.cc b/components/autofill_assistant/browser/element_area.cc
index 2617d5c..af39e3c2 100644
--- a/components/autofill_assistant/browser/element_area.cc
+++ b/components/autofill_assistant/browser/element_area.cc
@@ -45,7 +45,7 @@
     for (const auto& element_proto : rectangle_proto.elements()) {
       rectangle.positions.emplace_back();
       ElementPosition& position = rectangle.positions.back();
-      position.selector = Selector(element_proto);
+      position.selector = Selector(element_proto).MustBeVisible();
       DVLOG(3) << "  " << position.selector;
     }
   }
diff --git a/components/autofill_assistant/browser/element_area_unittest.cc b/components/autofill_assistant/browser/element_area_unittest.cc
index b4c0188..441ea54 100644
--- a/components/autofill_assistant/browser/element_area_unittest.cc
+++ b/components/autofill_assistant/browser/element_area_unittest.cc
@@ -114,7 +114,7 @@
 
 TEST_F(ElementAreaTest, OneRectangle) {
   EXPECT_CALL(mock_web_controller_,
-              OnGetElementPosition(Eq(Selector({"#found"})), _))
+              OnGetElementPosition(Eq(Selector({"#found"}).MustBeVisible()), _))
       .WillOnce(RunOnceCallback<1>(true, RectF(0.25f, 0.25f, 0.75f, 0.75f)));
 
   SetElement("#found");
@@ -126,7 +126,7 @@
 
 TEST_F(ElementAreaTest, CallOnUpdate) {
   EXPECT_CALL(mock_web_controller_,
-              OnGetElementPosition(Eq(Selector({"#found"})), _))
+              OnGetElementPosition(Eq(Selector({"#found"}).MustBeVisible()), _))
       .WillOnce(RunOnceCallback<1>(true, RectF(0.25f, 0.25f, 0.75f, 0.75f)));
 
   SetElement("#found");
@@ -135,11 +135,13 @@
 }
 
 TEST_F(ElementAreaTest, TwoRectangles) {
-  EXPECT_CALL(mock_web_controller_,
-              OnGetElementPosition(Eq(Selector({"#top_left"})), _))
+  EXPECT_CALL(
+      mock_web_controller_,
+      OnGetElementPosition(Eq(Selector({"#top_left"}).MustBeVisible()), _))
       .WillOnce(RunOnceCallback<1>(true, RectF(0.0f, 0.0f, 0.25f, 0.25f)));
-  EXPECT_CALL(mock_web_controller_,
-              OnGetElementPosition(Eq(Selector({"#bottom_right"})), _))
+  EXPECT_CALL(
+      mock_web_controller_,
+      OnGetElementPosition(Eq(Selector({"#bottom_right"}).MustBeVisible()), _))
       .WillOnce(RunOnceCallback<1>(true, RectF(0.25f, 0.25f, 1.0f, 1.0f)));
 
   ElementAreaProto area_proto;
@@ -154,11 +156,13 @@
 }
 
 TEST_F(ElementAreaTest, OneRectangleTwoElements) {
-  EXPECT_CALL(mock_web_controller_,
-              OnGetElementPosition(Eq(Selector({"#element1"})), _))
+  EXPECT_CALL(
+      mock_web_controller_,
+      OnGetElementPosition(Eq(Selector({"#element1"}).MustBeVisible()), _))
       .WillOnce(RunOnceCallback<1>(true, RectF(0.1f, 0.3f, 0.2f, 0.4f)));
-  EXPECT_CALL(mock_web_controller_,
-              OnGetElementPosition(Eq(Selector({"#element2"})), _))
+  EXPECT_CALL(
+      mock_web_controller_,
+      OnGetElementPosition(Eq(Selector({"#element2"}).MustBeVisible()), _))
       .WillOnce(RunOnceCallback<1>(true, RectF(0.5f, 0.2f, 0.6f, 0.5f)));
 
   ElementAreaProto area_proto;
@@ -173,14 +177,16 @@
 }
 
 TEST_F(ElementAreaTest, DoNotReportIncompleteRectangles) {
-  EXPECT_CALL(mock_web_controller_,
-              OnGetElementPosition(Eq(Selector({"#element1"})), _))
+  EXPECT_CALL(
+      mock_web_controller_,
+      OnGetElementPosition(Eq(Selector({"#element1"}).MustBeVisible()), _))
       .WillOnce(RunOnceCallback<1>(true, RectF(0.1f, 0.3f, 0.2f, 0.4f)));
 
   // Getting the position of #element2 neither succeeds nor fails, simulating an
   // intermediate state which shouldn't be reported to the callback.
-  EXPECT_CALL(mock_web_controller_,
-              OnGetElementPosition(Eq(Selector({"#element2"})), _))
+  EXPECT_CALL(
+      mock_web_controller_,
+      OnGetElementPosition(Eq(Selector({"#element2"}).MustBeVisible()), _))
       .WillOnce(DoNothing());  // overrides default action
 
   ElementAreaProto area_proto;
@@ -197,17 +203,21 @@
 }
 
 TEST_F(ElementAreaTest, OneRectangleFourElements) {
-  EXPECT_CALL(mock_web_controller_,
-              OnGetElementPosition(Eq(Selector({"#element1"})), _))
+  EXPECT_CALL(
+      mock_web_controller_,
+      OnGetElementPosition(Eq(Selector({"#element1"}).MustBeVisible()), _))
       .WillOnce(RunOnceCallback<1>(true, RectF(0.0f, 0.0f, 0.1f, 0.1f)));
-  EXPECT_CALL(mock_web_controller_,
-              OnGetElementPosition(Eq(Selector({"#element2"})), _))
+  EXPECT_CALL(
+      mock_web_controller_,
+      OnGetElementPosition(Eq(Selector({"#element2"}).MustBeVisible()), _))
       .WillOnce(RunOnceCallback<1>(true, RectF(0.9f, 0.9f, 1.0f, 1.0f)));
-  EXPECT_CALL(mock_web_controller_,
-              OnGetElementPosition(Eq(Selector({"#element3"})), _))
+  EXPECT_CALL(
+      mock_web_controller_,
+      OnGetElementPosition(Eq(Selector({"#element3"}).MustBeVisible()), _))
       .WillOnce(RunOnceCallback<1>(true, RectF(0.0f, 0.9f, 0.1f, 1.0f)));
-  EXPECT_CALL(mock_web_controller_,
-              OnGetElementPosition(Eq(Selector({"#element4"})), _))
+  EXPECT_CALL(
+      mock_web_controller_,
+      OnGetElementPosition(Eq(Selector({"#element4"}).MustBeVisible()), _))
       .WillOnce(RunOnceCallback<1>(true, RectF(0.9f, 0.0f, 1.0f, 0.1f)));
 
   ElementAreaProto area_proto;
@@ -224,11 +234,13 @@
 }
 
 TEST_F(ElementAreaTest, OneRectangleMissingElementsReported) {
-  EXPECT_CALL(mock_web_controller_,
-              OnGetElementPosition(Eq(Selector({"#element1"})), _))
+  EXPECT_CALL(
+      mock_web_controller_,
+      OnGetElementPosition(Eq(Selector({"#element1"}).MustBeVisible()), _))
       .WillOnce(RunOnceCallback<1>(true, RectF(0.1f, 0.1f, 0.2f, 0.2f)));
-  EXPECT_CALL(mock_web_controller_,
-              OnGetElementPosition(Eq(Selector({"#element2"})), _))
+  EXPECT_CALL(
+      mock_web_controller_,
+      OnGetElementPosition(Eq(Selector({"#element2"}).MustBeVisible()), _))
       .WillOnce(RunOnceCallback<1>(false, RectF()));
 
   ElementAreaProto area_proto;
@@ -246,11 +258,13 @@
 }
 
 TEST_F(ElementAreaTest, FullWidthRectangle) {
-  EXPECT_CALL(mock_web_controller_,
-              OnGetElementPosition(Eq(Selector({"#element1"})), _))
+  EXPECT_CALL(
+      mock_web_controller_,
+      OnGetElementPosition(Eq(Selector({"#element1"}).MustBeVisible()), _))
       .WillOnce(RunOnceCallback<1>(true, RectF(0.1f, 0.3f, 0.2f, 0.4f)));
-  EXPECT_CALL(mock_web_controller_,
-              OnGetElementPosition(Eq(Selector({"#element2"})), _))
+  EXPECT_CALL(
+      mock_web_controller_,
+      OnGetElementPosition(Eq(Selector({"#element2"}).MustBeVisible()), _))
       .WillOnce(RunOnceCallback<1>(true, RectF(0.5f, 0.7f, 0.6f, 0.8f)));
 
   ElementAreaProto area_proto;
@@ -267,8 +281,9 @@
 
 TEST_F(ElementAreaTest, ElementMovesAfterUpdate) {
   testing::InSequence seq;
-  EXPECT_CALL(mock_web_controller_,
-              OnGetElementPosition(Eq(Selector({"#element"})), _))
+  EXPECT_CALL(
+      mock_web_controller_,
+      OnGetElementPosition(Eq(Selector({"#element"}).MustBeVisible()), _))
       .WillOnce(RunOnceCallback<1>(true, RectF(0.0f, 0.25f, 1.0f, 0.5f)))
       .WillOnce(RunOnceCallback<1>(true, RectF(0.0f, 0.5f, 1.0f, 0.75f)));
 
@@ -291,8 +306,9 @@
 
 TEST_F(ElementAreaTest, ElementMovesWithTime) {
   testing::InSequence seq;
-  EXPECT_CALL(mock_web_controller_,
-              OnGetElementPosition(Eq(Selector({"#element"})), _))
+  EXPECT_CALL(
+      mock_web_controller_,
+      OnGetElementPosition(Eq(Selector({"#element"}).MustBeVisible()), _))
       .WillOnce(RunOnceCallback<1>(true, RectF(0.0f, 0.25f, 1.0f, 0.5f)))
       .WillOnce(RunOnceCallback<1>(true, RectF(0.0f, 0.5f, 1.0f, 0.75f)));
 
diff --git a/components/autofill_assistant/browser/element_precondition.cc b/components/autofill_assistant/browser/element_precondition.cc
index 5c433f3..a4fee3d5 100644
--- a/components/autofill_assistant/browser/element_precondition.cc
+++ b/components/autofill_assistant/browser/element_precondition.cc
@@ -46,8 +46,7 @@
     base::OnceCallback<void(bool)> callback =
         base::BindOnce(&ElementPrecondition::OnCheckElementExists,
                        weak_ptr_factory_.GetWeakPtr());
-    batch_checks->AddElementCheck(kExistenceCheck, selector,
-                                  std::move(callback));
+    batch_checks->AddElementCheck(selector, std::move(callback));
   }
   for (size_t i = 0; i < form_value_match_.size(); i++) {
     const auto& value_match = form_value_match_[i];
diff --git a/components/autofill_assistant/browser/element_precondition_unittest.cc b/components/autofill_assistant/browser/element_precondition_unittest.cc
index 5b0d6f5..79dcff9 100644
--- a/components/autofill_assistant/browser/element_precondition_unittest.cc
+++ b/components/autofill_assistant/browser/element_precondition_unittest.cc
@@ -26,16 +26,13 @@
 class ElementPreconditionTest : public testing::Test {
  public:
   void SetUp() override {
+    ON_CALL(mock_web_controller_, OnElementCheck(Eq(Selector({"exists"})), _))
+        .WillByDefault(RunOnceCallback<1>(true));
+    ON_CALL(mock_web_controller_, OnElementCheck(Eq(Selector({"empty"})), _))
+        .WillByDefault(RunOnceCallback<1>(true));
     ON_CALL(mock_web_controller_,
-            OnElementCheck(kExistenceCheck, Eq(Selector({"exists"})), _))
-        .WillByDefault(RunOnceCallback<2>(true));
-    ON_CALL(mock_web_controller_,
-            OnElementCheck(kExistenceCheck, Eq(Selector({"empty"})), _))
-        .WillByDefault(RunOnceCallback<2>(true));
-    ON_CALL(
-        mock_web_controller_,
-        OnElementCheck(kExistenceCheck, Eq(Selector({"does_not_exist"})), _))
-        .WillByDefault(RunOnceCallback<2>(false));
+            OnElementCheck(Eq(Selector({"does_not_exist"})), _))
+        .WillByDefault(RunOnceCallback<1>(false));
 
     ON_CALL(mock_web_controller_, OnGetFieldValue(Eq(Selector({"exists"})), _))
         .WillByDefault(RunOnceCallback<1>(true, "foo"));
diff --git a/components/autofill_assistant/browser/fake_script_executor_delegate.cc b/components/autofill_assistant/browser/fake_script_executor_delegate.cc
index 7a3426c..f12ada6 100644
--- a/components/autofill_assistant/browser/fake_script_executor_delegate.cc
+++ b/components/autofill_assistant/browser/fake_script_executor_delegate.cc
@@ -31,9 +31,8 @@
   return &memory_;
 }
 
-const std::map<std::string, std::string>&
-FakeScriptExecutorDelegate::GetParameters() {
-  return parameters_;
+TriggerContext* FakeScriptExecutorDelegate::GetTriggerContext() {
+  return &trigger_context_;
 }
 
 autofill::PersonalDataManager*
diff --git a/components/autofill_assistant/browser/fake_script_executor_delegate.h b/components/autofill_assistant/browser/fake_script_executor_delegate.h
index 4670bac..28c92c2 100644
--- a/components/autofill_assistant/browser/fake_script_executor_delegate.h
+++ b/components/autofill_assistant/browser/fake_script_executor_delegate.h
@@ -12,6 +12,7 @@
 
 #include "components/autofill_assistant/browser/client_memory.h"
 #include "components/autofill_assistant/browser/script_executor_delegate.h"
+#include "components/autofill_assistant/browser/trigger_context.h"
 
 namespace autofill_assistant {
 
@@ -27,7 +28,7 @@
   UiController* GetUiController() override;
   WebController* GetWebController() override;
   ClientMemory* GetClientMemory() override;
-  const std::map<std::string, std::string>& GetParameters() override;
+  TriggerContext* GetTriggerContext() override;
   autofill::PersonalDataManager* GetPersonalDataManager() override;
   content::WebContents* GetWebContents() override;
   void EnterState(AutofillAssistantState state) override;
@@ -57,7 +58,7 @@
   }
 
   std::map<std::string, std::string>* GetMutableParameters() {
-    return &parameters_;
+    return &trigger_context_.script_parameters;
   }
 
   AutofillAssistantState GetState() { return state_; }
@@ -76,7 +77,7 @@
   UiController* ui_controller_ = nullptr;
   WebController* web_controller_ = nullptr;
   ClientMemory memory_;
-  std::map<std::string, std::string> parameters_;
+  TriggerContext trigger_context_;
   AutofillAssistantState state_ = AutofillAssistantState::INACTIVE;
   std::string status_message_;
   std::unique_ptr<Details> details_;
diff --git a/components/autofill_assistant/browser/mock_run_once_callback.h b/components/autofill_assistant/browser/mock_run_once_callback.h
index 4f75fe3..a4721f0 100644
--- a/components/autofill_assistant/browser/mock_run_once_callback.h
+++ b/components/autofill_assistant/browser/mock_run_once_callback.h
@@ -67,6 +67,12 @@
   return std::move(std::get<k>(args)).Run(p0, p1, p2, p3, p4, p5);
 }
 
+ACTION_TEMPLATE(RunOnceCallback,
+                HAS_1_TEMPLATE_PARAMS(int, k),
+                AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6)) {
+  return std::move(std::get<k>(args)).Run(p0, p1, p2, p3, p4, p5, p6);
+}
+
 // Template for capturing a base::OnceCallback passed to a mocked method
 //
 // This is useful to run the callback later on, at an appropriate time.
diff --git a/components/autofill_assistant/browser/mock_service.h b/components/autofill_assistant/browser/mock_service.h
index 307df246..23ed84e 100644
--- a/components/autofill_assistant/browser/mock_service.h
+++ b/components/autofill_assistant/browser/mock_service.h
@@ -20,44 +20,46 @@
   ~MockService() override;
 
   void GetScriptsForUrl(const GURL& url,
-                        const std::map<std::string, std::string>& parameters,
+                        const TriggerContext* trigger_context,
                         ResponseCallback callback) override {
     // Transforming callback into a references allows using RunOnceCallback on
     // the argument.
-    OnGetScriptsForUrl(url, parameters, callback);
+    OnGetScriptsForUrl(url, trigger_context, callback);
   }
   MOCK_METHOD3(OnGetScriptsForUrl,
                void(const GURL& url,
-                    const std::map<std::string, std::string>& parameters,
+                    const TriggerContext* trigger_context,
                     ResponseCallback& callback));
 
   void GetActions(const std::string& script_path,
                   const GURL& url,
-                  const std::map<std::string, std::string>& parameters,
+                  const TriggerContext* trigger_context,
                   const std::string& global_payload,
                   const std::string& script_payload,
                   ResponseCallback callback) override {
-    OnGetActions(script_path, url, parameters, global_payload, script_payload,
-                 callback);
+    OnGetActions(script_path, url, trigger_context, global_payload,
+                 script_payload, callback);
   }
   MOCK_METHOD6(OnGetActions,
                void(const std::string& script_path,
                     const GURL& url,
-                    const std::map<std::string, std::string>& parameters,
+                    const TriggerContext* trigger_context,
                     const std::string& global_payload,
                     const std::string& script_payload,
                     ResponseCallback& callback));
 
   void GetNextActions(
+      const TriggerContext* trigger_context,
       const std::string& previous_global_payload,
       const std::string& previous_script_payload,
       const std::vector<ProcessedActionProto>& processed_actions,
       ResponseCallback callback) override {
-    OnGetNextActions(previous_global_payload, previous_script_payload,
-                     processed_actions, callback);
+    OnGetNextActions(trigger_context, previous_global_payload,
+                     previous_script_payload, processed_actions, callback);
   }
-  MOCK_METHOD4(OnGetNextActions,
-               void(const std::string& previous_global_payload,
+  MOCK_METHOD5(OnGetNextActions,
+               void(const TriggerContext* trigger_context,
+                    const std::string& previous_global_payload,
                     const std::string& previous_script_payload,
                     const std::vector<ProcessedActionProto>& processed_actions,
                     ResponseCallback& callback));
diff --git a/components/autofill_assistant/browser/mock_web_controller.h b/components/autofill_assistant/browser/mock_web_controller.h
index e2d446a..2dd4db2e 100644
--- a/components/autofill_assistant/browser/mock_web_controller.h
+++ b/components/autofill_assistant/browser/mock_web_controller.h
@@ -42,15 +42,13 @@
                void(const Selector& selector,
                     base::OnceCallback<void(const ClientStatus&)>& callback));
 
-  void ElementCheck(ElementCheckType check_type,
-                    const Selector& selector,
+  void ElementCheck(const Selector& selector,
                     bool strict,
                     base::OnceCallback<void(bool)> callback) override {
-    OnElementCheck(check_type, selector, callback);
+    OnElementCheck(selector, callback);
   }
-  MOCK_METHOD3(OnElementCheck,
-               void(ElementCheckType check_type,
-                    const Selector& selector,
+  MOCK_METHOD2(OnElementCheck,
+               void(const Selector& selector,
                     base::OnceCallback<void(bool)>& callback));
 
   void GetFieldValue(
diff --git a/components/autofill_assistant/browser/protocol_utils.cc b/components/autofill_assistant/browser/protocol_utils.cc
index 6480392..033a423 100644
--- a/components/autofill_assistant/browser/protocol_utils.cc
+++ b/components/autofill_assistant/browser/protocol_utils.cc
@@ -46,19 +46,29 @@
   }
 }
 
+void FillClientContext(const ClientContextProto& client_context,
+                       const TriggerContext& trigger_context,
+                       ClientContextProto* proto) {
+  proto->CopyFrom(client_context);
+  if (!trigger_context.experiment_ids.empty()) {
+    proto->set_experiment_ids(trigger_context.experiment_ids);
+  }
+}
+
 }  // namespace
 
 // static
 std::string ProtocolUtils::CreateGetScriptsRequest(
     const GURL& url,
-    const std::map<std::string, std::string>& parameters,
+    const TriggerContext& trigger_context,
     const ClientContextProto& client_context) {
   DCHECK(!url.is_empty());
 
   SupportsScriptRequestProto script_proto;
   script_proto.set_url(url.spec());
-  script_proto.mutable_client_context()->CopyFrom(client_context);
-  AddScriptParametersToProto(parameters,
+  FillClientContext(client_context, trigger_context,
+                    script_proto.mutable_client_context());
+  AddScriptParametersToProto(trigger_context.script_parameters,
                              script_proto.mutable_script_parameters());
   std::string serialized_script_proto;
   bool success = script_proto.SerializeToString(&serialized_script_proto);
@@ -95,7 +105,7 @@
 std::string ProtocolUtils::CreateInitialScriptActionsRequest(
     const std::string& script_path,
     const GURL& url,
-    const std::map<std::string, std::string>& parameters,
+    const TriggerContext& trigger_context,
     const std::string& global_payload,
     const std::string& script_payload,
     const ClientContextProto& client_context) {
@@ -107,9 +117,11 @@
   query->add_script_path(script_path);
   query->set_url(url.spec());
   query->set_policy(PolicyType::SCRIPT);
+  FillClientContext(client_context, trigger_context,
+                    request_proto.mutable_client_context());
   AddScriptParametersToProto(
-      parameters, initial_request_proto->mutable_script_parameters());
-  request_proto.mutable_client_context()->CopyFrom(client_context);
+      trigger_context.script_parameters,
+      initial_request_proto->mutable_script_parameters());
 
   if (!global_payload.empty()) {
     request_proto.set_global_payload(global_payload);
@@ -127,6 +139,7 @@
 
 // static
 std::string ProtocolUtils::CreateNextScriptActionsRequest(
+    const TriggerContext& trigger_context,
     const std::string& global_payload,
     const std::string& script_payload,
     const std::vector<ProcessedActionProto>& processed_actions,
@@ -139,7 +152,8 @@
   for (const auto& processed_action : processed_actions) {
     next_request->add_processed_actions()->MergeFrom(processed_action);
   }
-  request_proto.mutable_client_context()->CopyFrom(client_context);
+  FillClientContext(client_context, trigger_context,
+                    request_proto.mutable_client_context());
   std::string serialized_request_proto;
   bool success = request_proto.SerializeToString(&serialized_request_proto);
   DCHECK(success);
diff --git a/components/autofill_assistant/browser/protocol_utils.h b/components/autofill_assistant/browser/protocol_utils.h
index 0bc04f4..0b25449 100644
--- a/components/autofill_assistant/browser/protocol_utils.h
+++ b/components/autofill_assistant/browser/protocol_utils.h
@@ -14,6 +14,7 @@
 #include "components/autofill_assistant/browser/actions/action.h"
 #include "components/autofill_assistant/browser/script.h"
 #include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/trigger_context.h"
 
 class GURL;
 
@@ -25,7 +26,7 @@
   // |url|.
   static std::string CreateGetScriptsRequest(
       const GURL& url,
-      const std::map<std::string, std::string>& parameters,
+      const TriggerContext& trigger_context,
       const ClientContextProto& client_context);
 
   // Convert |script_proto| to a script struct and if the script is valid, add
@@ -40,13 +41,14 @@
   static std::string CreateInitialScriptActionsRequest(
       const std::string& script_path,
       const GURL& url,
-      const std::map<std::string, std::string>& parameters,
+      const TriggerContext& trigger_context,
       const std::string& global_payload,
       const std::string& script_payload,
       const ClientContextProto& client_context);
 
   // Create request to get next sequence of actions for a script.
   static std::string CreateNextScriptActionsRequest(
+      const TriggerContext& trigger_context,
       const std::string& global_payload,
       const std::string& script_payload,
       const std::vector<ProcessedActionProto>& processed_actions,
diff --git a/components/autofill_assistant/browser/protocol_utils_unittest.cc b/components/autofill_assistant/browser/protocol_utils_unittest.cc
index 74037423..d81a161a 100644
--- a/components/autofill_assistant/browser/protocol_utils_unittest.cc
+++ b/components/autofill_assistant/browser/protocol_utils_unittest.cc
@@ -97,17 +97,19 @@
 }
 
 TEST(ProtocolUtilsTest, CreateInitialScriptActionsRequest) {
-  std::map<std::string, std::string> parameters;
-  parameters["a"] = "b";
-  parameters["c"] = "d";
+  TriggerContext trigger_context;
+  trigger_context.script_parameters["a"] = "b";
+  trigger_context.script_parameters["c"] = "d";
+  trigger_context.experiment_ids = "1,2,3";
 
   ScriptActionRequestProto request;
   EXPECT_TRUE(
       request.ParseFromString(ProtocolUtils::CreateInitialScriptActionsRequest(
-          "script_path", GURL("http://example.com/"), parameters,
+          "script_path", GURL("http://example.com/"), trigger_context,
           "global_payload", "script_payload", CreateClientContextProto())));
 
   AssertClientContext(request.client_context());
+  EXPECT_THAT(request.client_context().experiment_ids(), Eq("1,2,3"));
 
   const InitialScriptActionsRequestProto& initial = request.initial_request();
   EXPECT_THAT(initial.query().script_path(), ElementsAre("script_path"));
@@ -121,16 +123,38 @@
   EXPECT_EQ("script_payload", request.script_payload());
 }
 
+TEST(ProtocolUtilsTest, CreateNextScriptActionsRequest) {
+  TriggerContext trigger_context;
+  trigger_context.script_parameters["a"] = "b";
+  trigger_context.script_parameters["c"] = "d";
+  trigger_context.experiment_ids = "1,2,3";
+
+  ScriptActionRequestProto request;
+  std::vector<ProcessedActionProto> processed_actions;
+  processed_actions.emplace_back(ProcessedActionProto());
+  EXPECT_TRUE(
+      request.ParseFromString(ProtocolUtils::CreateNextScriptActionsRequest(
+          trigger_context, "global_payload", "script_payload",
+          processed_actions, CreateClientContextProto())));
+
+  AssertClientContext(request.client_context());
+  EXPECT_THAT(request.client_context().experiment_ids(), Eq("1,2,3"));
+  EXPECT_EQ(1, request.next_request().processed_actions().size());
+}
+
 TEST(ProtocolUtilsTest, CreateGetScriptsRequest) {
-  std::map<std::string, std::string> parameters;
-  parameters["a"] = "b";
-  parameters["c"] = "d";
+  TriggerContext trigger_context;
+  trigger_context.script_parameters["a"] = "b";
+  trigger_context.script_parameters["c"] = "d";
+  trigger_context.experiment_ids = "1,2,3";
 
   SupportsScriptRequestProto request;
   EXPECT_TRUE(request.ParseFromString(ProtocolUtils::CreateGetScriptsRequest(
-      GURL("http://example.com/"), parameters, CreateClientContextProto())));
+      GURL("http://example.com/"), trigger_context,
+      CreateClientContextProto())));
 
   AssertClientContext(request.client_context());
+  EXPECT_THAT(request.client_context().experiment_ids(), Eq("1,2,3"));
 
   EXPECT_EQ("http://example.com/", request.url());
   ASSERT_EQ(2, request.script_parameters_size());
diff --git a/components/autofill_assistant/browser/script_executor.cc b/components/autofill_assistant/browser/script_executor.cc
index 940b30d..a12eb344 100644
--- a/components/autofill_assistant/browser/script_executor.cc
+++ b/components/autofill_assistant/browser/script_executor.cc
@@ -112,7 +112,7 @@
 
   DVLOG(2) << "GetActions for " << delegate_->GetCurrentURL().host();
   delegate_->GetService()->GetActions(
-      script_path_, delegate_->GetCurrentURL(), delegate_->GetParameters(),
+      script_path_, delegate_->GetCurrentURL(), delegate_->GetTriggerContext(),
       last_global_payload_, last_script_payload_,
       base::BindOnce(&ScriptExecutor::OnGetActions,
                      weak_ptr_factory_.GetWeakPtr()));
@@ -124,14 +124,12 @@
 }
 
 void ScriptExecutor::ShortWaitForElement(
-    ElementCheckType check_type,
     const Selector& selector,
     base::OnceCallback<void(bool)> callback) {
-  WaitForElement(kShortWaitForElementDeadline, check_type, selector,
-                 std::move(callback));
+  WaitForElement(kShortWaitForElementDeadline, selector, std::move(callback));
 }
 
-void ScriptExecutor::WaitForElementVisible(
+void ScriptExecutor::WaitForElement(
     base::TimeDelta max_wait_time,
     bool allow_interrupt,
     const Selector& selector,
@@ -139,13 +137,13 @@
   if (!allow_interrupt || ordered_interrupts_->empty()) {
     // No interrupts to worry about. Just run normal wait.
     WaitForElement(
-        max_wait_time, kVisibilityCheck, selector,
+        max_wait_time, selector,
         base::BindOnce(&ScriptExecutor::OnWaitForElementVisibleNoInterrupts,
                        weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
     return;
   }
   wait_with_interrupts_ = std::make_unique<WaitWithInterrupts>(
-      this, max_wait_time, kVisibilityCheck, selector,
+      this, max_wait_time, selector,
       base::BindOnce(&ScriptExecutor::OnWaitForElementVisibleWithInterrupts,
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
   wait_with_interrupts_->Run();
@@ -524,7 +522,8 @@
 
 void ScriptExecutor::GetNextActions() {
   delegate_->GetService()->GetNextActions(
-      last_global_payload_, last_script_payload_, processed_actions_,
+      delegate_->GetTriggerContext(), last_global_payload_,
+      last_script_payload_, processed_actions_,
       base::BindOnce(&ScriptExecutor::OnGetActions,
                      weak_ptr_factory_.GetWeakPtr()));
 }
@@ -552,20 +551,18 @@
 }
 
 void ScriptExecutor::WaitForElement(base::TimeDelta max_wait_time,
-                                    ElementCheckType check_type,
                                     const Selector& selector,
                                     base::OnceCallback<void(bool)> callback) {
   retry_timer_.Start(
       max_wait_time,
       base::BindRepeating(&ScriptExecutor::CheckForElement,
-                          weak_ptr_factory_.GetWeakPtr(), check_type, selector),
+                          weak_ptr_factory_.GetWeakPtr(), selector),
       std::move(callback));
 }
 
-void ScriptExecutor::CheckForElement(ElementCheckType check_type,
-                                     const Selector& selector,
+void ScriptExecutor::CheckForElement(const Selector& selector,
                                      base::OnceCallback<void(bool)> callback) {
-  delegate_->GetWebController()->ElementCheck(check_type, selector,
+  delegate_->GetWebController()->ElementCheck(selector,
                                               /* strict= */ false,
                                               std::move(callback));
 }
@@ -601,12 +598,10 @@
 ScriptExecutor::WaitWithInterrupts::WaitWithInterrupts(
     ScriptExecutor* main_script,
     base::TimeDelta max_wait_time,
-    ElementCheckType check_type,
     const Selector& selector,
     WaitWithInterrupts::Callback callback)
     : main_script_(main_script),
       max_wait_time_(max_wait_time),
-      check_type_(check_type),
       selector_(selector),
       callback_(std::move(callback)),
       retry_timer_(kPeriodicElementCheck),
@@ -644,9 +639,8 @@
   runnable_interrupts_.clear();
   batch_element_checker_ = std::make_unique<BatchElementChecker>();
   batch_element_checker_->AddElementCheck(
-      check_type_, selector_,
-      base::BindOnce(&WaitWithInterrupts::OnElementCheckDone,
-                     base::Unretained(this)));
+      selector_, base::BindOnce(&WaitWithInterrupts::OnElementCheckDone,
+                                base::Unretained(this)));
   for (const auto* interrupt : *main_script_->ordered_interrupts_) {
     if (ran_interrupts_.find(interrupt->handle.path) != ran_interrupts_.end()) {
       // Only run an interrupt once in a WaitWithInterrupts, to avoid loops.
@@ -655,7 +649,8 @@
 
     interrupt->precondition->Check(
         main_script_->delegate_->GetCurrentURL(), batch_element_checker_.get(),
-        main_script_->delegate_->GetParameters(), *main_script_->scripts_state_,
+        main_script_->delegate_->GetTriggerContext()->script_parameters,
+        *main_script_->scripts_state_,
         base::BindOnce(&WaitWithInterrupts::OnPreconditionCheckDone,
                        weak_ptr_factory_.GetWeakPtr(),
                        base::Unretained(interrupt)));
diff --git a/components/autofill_assistant/browser/script_executor.h b/components/autofill_assistant/browser/script_executor.h
index d06e473..3e0081f7 100644
--- a/components/autofill_assistant/browser/script_executor.h
+++ b/components/autofill_assistant/browser/script_executor.h
@@ -104,10 +104,9 @@
   // Override ActionDelegate:
   void RunElementChecks(BatchElementChecker* checker,
                         base::OnceCallback<void()> all_done) override;
-  void ShortWaitForElement(ElementCheckType check_type,
-                           const Selector& selector,
+  void ShortWaitForElement(const Selector& selector,
                            base::OnceCallback<void(bool)> callback) override;
-  void WaitForElementVisible(
+  void WaitForElement(
       base::TimeDelta max_wait_time,
       bool allow_interrupt,
       const Selector& selector,
@@ -198,7 +197,6 @@
     // |main_script_| must not be null and outlive this instance.
     WaitWithInterrupts(ScriptExecutor* main_script,
                        base::TimeDelta max_wait_time,
-                       ElementCheckType check_type,
                        const Selector& selectors,
                        WaitWithInterrupts::Callback callback);
     ~WaitWithInterrupts() override;
@@ -236,7 +234,6 @@
 
     ScriptExecutor* main_script_;
     const base::TimeDelta max_wait_time_;
-    const ElementCheckType check_type_;
     const Selector selector_;
     WaitWithInterrupts::Callback callback_;
 
@@ -281,11 +278,9 @@
   void GetNextActions();
   void OnProcessedAction(std::unique_ptr<ProcessedActionProto> action);
   void WaitForElement(base::TimeDelta max_wait_time,
-                      ElementCheckType check_type,
                       const Selector& selectors,
                       base::OnceCallback<void(bool)> callback);
-  void CheckForElement(ElementCheckType check_type,
-                       const Selector& selectors,
+  void CheckForElement(const Selector& selectors,
                        base::OnceCallback<void(bool)> callback);
   void OnWaitForElementVisibleWithInterrupts(
       base::OnceCallback<void(ProcessedActionStatusProto)> callback,
diff --git a/components/autofill_assistant/browser/script_executor_delegate.h b/components/autofill_assistant/browser/script_executor_delegate.h
index 8881a0f..4820d09 100644
--- a/components/autofill_assistant/browser/script_executor_delegate.h
+++ b/components/autofill_assistant/browser/script_executor_delegate.h
@@ -31,6 +31,7 @@
 class UiController;
 class WebController;
 class ClientMemory;
+struct TriggerContext;
 
 class ScriptExecutorDelegate {
  public:
@@ -39,7 +40,7 @@
   virtual UiController* GetUiController() = 0;
   virtual WebController* GetWebController() = 0;
   virtual ClientMemory* GetClientMemory() = 0;
-  virtual const std::map<std::string, std::string>& GetParameters() = 0;
+  virtual const TriggerContext* GetTriggerContext() = 0;
   virtual autofill::PersonalDataManager* GetPersonalDataManager() = 0;
   virtual content::WebContents* GetWebContents() = 0;
   virtual void EnterState(AutofillAssistantState state) = 0;
diff --git a/components/autofill_assistant/browser/script_executor_unittest.cc b/components/autofill_assistant/browser/script_executor_unittest.cc
index 9ee5776..944a513 100644
--- a/components/autofill_assistant/browser/script_executor_unittest.cc
+++ b/components/autofill_assistant/browser/script_executor_unittest.cc
@@ -65,8 +65,8 @@
     ON_CALL(mock_web_controller_, OnClickOrTapElement(_, _))
         .WillByDefault(RunOnceCallback<1>(ClientStatus(OTHER_ACTION_STATUS)));
 
-    ON_CALL(mock_web_controller_, OnElementCheck(_, _, _))
-        .WillByDefault(RunOnceCallback<2>(true));
+    ON_CALL(mock_web_controller_, OnElementCheck(_, _))
+        .WillByDefault(RunOnceCallback<1>(true));
     ON_CALL(mock_web_controller_, OnFocusElement(_, _))
         .WillByDefault(RunOnceCallback<1>(OkClientStatus()));
   }
@@ -104,7 +104,7 @@
     interruptible.set_global_payload("main script global payload");
     interruptible.set_script_payload("main script payload");
     auto* wait_action = interruptible.add_actions()->mutable_wait_for_dom();
-    wait_action->add_selectors(element);
+    wait_action->mutable_wait_until()->add_selectors(element);
     wait_action->set_allow_interrupt(true);
     interruptible.add_actions()->mutable_tell()->set_message(path);
     EXPECT_CALL(mock_service_, OnGetActions(StrEq(path), _, _, _, _, _))
@@ -181,8 +181,9 @@
   (*parameters)["param2"] = "value2";
   EXPECT_CALL(mock_service_,
               OnGetActions(StrEq(kScriptPath), _,
-                           AllOf(Contains(Pair("param1", "value1")),
-                                 Contains(Pair("param2", "value2"))),
+                           Field(&TriggerContext::script_parameters,
+                                 AllOf(Contains(Pair("param1", "value1")),
+                                       Contains(Pair("param2", "value2")))),
                            _, _, _))
       .WillOnce(RunOnceCallback<5>(true, ""));
 
@@ -202,9 +203,9 @@
       .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
 
   std::vector<ProcessedActionProto> processed_actions_capture;
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _))
-      .WillOnce(DoAll(SaveArg<2>(&processed_actions_capture),
-                      RunOnceCallback<3>(true, "")));
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+      .WillOnce(DoAll(SaveArg<3>(&processed_actions_capture),
+                      RunOnceCallback<4>(true, "")));
   EXPECT_CALL(executor_callback_,
               Run(AllOf(Field(&ScriptExecutor::Result::success, true),
                         Field(&ScriptExecutor::Result::at_end,
@@ -226,12 +227,12 @@
   next_actions_response.add_actions()->mutable_tell()->set_message("3");
   std::vector<ProcessedActionProto> processed_actions1_capture;
   std::vector<ProcessedActionProto> processed_actions2_capture;
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _))
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
       .WillOnce(
-          DoAll(SaveArg<2>(&processed_actions1_capture),
-                RunOnceCallback<3>(true, Serialize(next_actions_response))))
-      .WillOnce(DoAll(SaveArg<2>(&processed_actions2_capture),
-                      RunOnceCallback<3>(true, "")));
+          DoAll(SaveArg<3>(&processed_actions1_capture),
+                RunOnceCallback<4>(true, Serialize(next_actions_response))))
+      .WillOnce(DoAll(SaveArg<3>(&processed_actions2_capture),
+                      RunOnceCallback<4>(true, "")));
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
   executor_->Run(executor_callback_.Get());
@@ -248,9 +249,9 @@
       .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
 
   std::vector<ProcessedActionProto> processed_actions_capture;
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _))
-      .WillOnce(DoAll(SaveArg<2>(&processed_actions_capture),
-                      RunOnceCallback<3>(true, "")));
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+      .WillOnce(DoAll(SaveArg<3>(&processed_actions_capture),
+                      RunOnceCallback<4>(true, "")));
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
   executor_->Run(executor_callback_.Get());
@@ -266,8 +267,8 @@
   EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
       .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
 
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _))
-      .WillOnce(RunOnceCallback<3>(true, ""));
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+      .WillOnce(RunOnceCallback<4>(true, ""));
   EXPECT_CALL(executor_callback_,
               Run(AllOf(Field(&ScriptExecutor::Result::success, true),
                         Field(&ScriptExecutor::Result::at_end,
@@ -282,8 +283,8 @@
   EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
       .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
 
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _))
-      .WillOnce(RunOnceCallback<3>(true, ""));
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+      .WillOnce(RunOnceCallback<4>(true, ""));
   EXPECT_CALL(executor_callback_,
               Run(AllOf(Field(&ScriptExecutor::Result::success, true),
                         Field(&ScriptExecutor::Result::at_end,
@@ -310,12 +311,12 @@
       "will run after error");
   std::vector<ProcessedActionProto> processed_actions1_capture;
   std::vector<ProcessedActionProto> processed_actions2_capture;
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _))
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
       .WillOnce(
-          DoAll(SaveArg<2>(&processed_actions1_capture),
-                RunOnceCallback<3>(true, Serialize(next_actions_response))))
-      .WillOnce(DoAll(SaveArg<2>(&processed_actions2_capture),
-                      RunOnceCallback<3>(true, "")));
+          DoAll(SaveArg<3>(&processed_actions1_capture),
+                RunOnceCallback<4>(true, Serialize(next_actions_response))))
+      .WillOnce(DoAll(SaveArg<3>(&processed_actions2_capture),
+                      RunOnceCallback<4>(true, "")));
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
   executor_->Run(executor_callback_.Get());
@@ -341,9 +342,9 @@
       .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
 
   std::vector<ProcessedActionProto> processed_actions_capture;
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _))
-      .WillOnce(DoAll(SaveArg<2>(&processed_actions_capture),
-                      RunOnceCallback<3>(true, "")));
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+      .WillOnce(DoAll(SaveArg<3>(&processed_actions_capture),
+                      RunOnceCallback<4>(true, "")));
 
   // executor_callback_.Run() not expected to be run just yet, as the action is
   // delayed.
@@ -368,8 +369,8 @@
 
   EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
       .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _))
-      .WillOnce(RunOnceCallback<3>(true, ""));
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+      .WillOnce(RunOnceCallback<4>(true, ""));
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
 
@@ -388,8 +389,8 @@
 
   EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
       .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _))
-      .WillOnce(RunOnceCallback<3>(true, ""));
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+      .WillOnce(RunOnceCallback<4>(true, ""));
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
 
@@ -403,8 +404,8 @@
   actions_response.add_actions()->mutable_tell()->set_message("Hello");
   EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
       .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _))
-      .WillOnce(RunOnceCallback<3>(false, ""));
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+      .WillOnce(RunOnceCallback<4>(false, ""));
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, false)));
   delegate_.SetDetails(std::make_unique<Details>());  // empty, but not null
@@ -439,8 +440,8 @@
   initial_actions_response.add_actions()->mutable_tell()->set_message("ok");
   EXPECT_CALL(mock_service_, OnGetActions(StrEq(kScriptPath), _, _, _, _, _))
       .WillOnce(RunOnceCallback<5>(true, Serialize(initial_actions_response)));
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _))
-      .WillOnce(RunOnceCallback<3>(true, ""));
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+      .WillOnce(RunOnceCallback<4>(true, ""));
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
   executor_->Run(executor_callback_.Get());
@@ -462,9 +463,9 @@
   ActionsResponseProto next_actions_response;
   next_actions_response.set_global_payload("last global payload");
   next_actions_response.set_script_payload("last payload");
-  EXPECT_CALL(mock_service_, OnGetNextActions("actions global payload",
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, "actions global payload",
                                               "actions payload", _, _))
-      .WillOnce(RunOnceCallback<3>(true, Serialize(next_actions_response)));
+      .WillOnce(RunOnceCallback<4>(true, Serialize(next_actions_response)));
 
   EXPECT_CALL(executor_callback_, Run(_));
   executor_->Run(executor_callback_.Get());
@@ -483,9 +484,9 @@
                                           "initial payload", _))
       .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
 
-  EXPECT_CALL(mock_service_, OnGetNextActions("actions global payload",
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, "actions global payload",
                                               "actions payload", _, _))
-      .WillOnce(RunOnceCallback<3>(false, ""));
+      .WillOnce(RunOnceCallback<4>(false, ""));
 
   EXPECT_CALL(executor_callback_, Run(_));
   executor_->Run(executor_callback_.Get());
@@ -503,11 +504,11 @@
   // Both scripts ends after the first set of actions. Capture the results.
   std::vector<ProcessedActionProto> processed_actions1_capture;
   std::vector<ProcessedActionProto> processed_actions2_capture;
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _))
-      .WillOnce(DoAll(SaveArg<2>(&processed_actions1_capture),
-                      RunOnceCallback<3>(true, "")))
-      .WillOnce(DoAll(SaveArg<2>(&processed_actions2_capture),
-                      RunOnceCallback<3>(true, "")));
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+      .WillOnce(DoAll(SaveArg<3>(&processed_actions1_capture),
+                      RunOnceCallback<4>(true, "")))
+      .WillOnce(DoAll(SaveArg<3>(&processed_actions2_capture),
+                      RunOnceCallback<4>(true, "")));
 
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
@@ -543,13 +544,14 @@
   {
     testing::InSequence seq;
     EXPECT_CALL(mock_service_,
-                OnGetNextActions(_, "payload for interrupt1", _, _))
-        .WillOnce(RunOnceCallback<3>(true, ""));
+                OnGetNextActions(_, _, "payload for interrupt1", _, _))
+        .WillOnce(RunOnceCallback<4>(true, ""));
     EXPECT_CALL(mock_service_,
-                OnGetNextActions(_, "payload for interrupt2", _, _))
-        .WillOnce(RunOnceCallback<3>(true, ""));
-    EXPECT_CALL(mock_service_, OnGetNextActions(_, "main script payload", _, _))
-        .WillOnce(RunOnceCallback<3>(true, ""));
+                OnGetNextActions(_, _, "payload for interrupt2", _, _))
+        .WillOnce(RunOnceCallback<4>(true, ""));
+    EXPECT_CALL(mock_service_,
+                OnGetNextActions(_, _, "main script payload", _, _))
+        .WillOnce(RunOnceCallback<4>(true, ""));
   }
 
   EXPECT_CALL(executor_callback_,
@@ -569,7 +571,7 @@
   ActionsResponseProto interruptible;
   for (int i = 0; i < 3; i++) {
     auto* wait_action = interruptible.add_actions()->mutable_wait_for_dom();
-    wait_action->add_selectors("element");
+    wait_action->mutable_wait_until()->add_selectors("element");
     wait_action->set_allow_interrupt(true);
   }
   EXPECT_CALL(mock_service_, OnGetActions(StrEq("script_path"), _, _, _, _, _))
@@ -584,8 +586,8 @@
       .WillRepeatedly(RunOnceCallback<5>(true, Serialize(interrupt_actions)));
 
   // All scripts succeed with no more actions.
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _))
-      .WillRepeatedly(RunOnceCallback<3>(true, ""));
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+      .WillRepeatedly(RunOnceCallback<4>(true, ""));
 
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
@@ -601,20 +603,20 @@
       "last global payload from interrupt");
   next_interrupt_actions_response.set_script_payload(
       "last payload from interrupt");
-  EXPECT_CALL(mock_service_, OnGetNextActions("global payload for interrupt",
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, "global payload for interrupt",
                                               "payload for interrupt", _, _))
       .WillOnce(
-          RunOnceCallback<3>(true, Serialize(next_interrupt_actions_response)));
+          RunOnceCallback<4>(true, Serialize(next_interrupt_actions_response)));
 
   ActionsResponseProto next_main_actions_response;
   next_main_actions_response.set_global_payload(
       "last global payload from main");
   next_main_actions_response.set_script_payload("last payload from main");
   EXPECT_CALL(mock_service_,
-              OnGetNextActions("last global payload from interrupt",
+              OnGetNextActions(_, "last global payload from interrupt",
                                "main script payload", _, _))
       .WillOnce(
-          RunOnceCallback<3>(true, Serialize(next_main_actions_response)));
+          RunOnceCallback<4>(true, Serialize(next_main_actions_response)));
 
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
@@ -628,13 +630,13 @@
   SetupInterruptibleScript(kScriptPath, "element");
   SetupInterrupt("interrupt", "interrupt_trigger");
 
-  EXPECT_CALL(mock_service_, OnGetNextActions("global payload for interrupt",
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, "global payload for interrupt",
                                               "payload for interrupt", _, _))
-      .WillOnce(RunOnceCallback<3>(false, ""));
+      .WillOnce(RunOnceCallback<4>(false, ""));
 
-  EXPECT_CALL(mock_service_, OnGetNextActions("global payload for interrupt",
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, "global payload for interrupt",
                                               "main script payload", _, _))
-      .WillOnce(RunOnceCallback<3>(false, ""));
+      .WillOnce(RunOnceCallback<4>(false, ""));
 
   EXPECT_CALL(executor_callback_, Run(_));
   executor_->Run(executor_callback_.Get());
@@ -650,14 +652,14 @@
   SetupInterrupt("interrupt", "interrupt_trigger");
 
   EXPECT_CALL(mock_web_controller_,
-              OnElementCheck(_, Eq(Selector({"element"})), _))
-      .WillRepeatedly(RunOnceCallback<2>(true));
+              OnElementCheck(Eq(Selector({"element"})), _))
+      .WillRepeatedly(RunOnceCallback<1>(true));
   EXPECT_CALL(mock_web_controller_,
-              OnElementCheck(_, Eq(Selector({"interrupt_trigger"})), _))
-      .WillRepeatedly(RunOnceCallback<2>(false));
+              OnElementCheck(Eq(Selector({"interrupt_trigger"})), _))
+      .WillRepeatedly(RunOnceCallback<1>(false));
 
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _))
-      .WillRepeatedly(RunOnceCallback<3>(true, ""));
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+      .WillRepeatedly(RunOnceCallback<4>(true, ""));
 
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
@@ -672,7 +674,7 @@
   // The main script has a wait_for_dom, but it is not interruptible.
   ActionsResponseProto interruptible;
   auto* wait_action = interruptible.add_actions()->mutable_wait_for_dom();
-  wait_action->add_selectors("element");
+  wait_action->mutable_wait_until()->add_selectors("element");
   // allow_interrupt is not set
   EXPECT_CALL(mock_service_, OnGetActions(StrEq(kScriptPath), _, _, _, _, _))
       .WillOnce(RunOnceCallback<5>(true, Serialize(interruptible)));
@@ -681,8 +683,8 @@
   // given an opportunity to.
   SetupInterrupt("interrupt", "interrupt_trigger");
 
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _))
-      .WillRepeatedly(RunOnceCallback<3>(true, ""));
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+      .WillRepeatedly(RunOnceCallback<4>(true, ""));
 
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
@@ -699,19 +701,20 @@
   SetupInterrupt("interrupt", "interrupt_trigger");
 
   // The interrupt fails.
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, "payload for interrupt", _, _))
-      .WillOnce(RunOnceCallback<3>(false, ""));
+  EXPECT_CALL(mock_service_,
+              OnGetNextActions(_, _, "payload for interrupt", _, _))
+      .WillOnce(RunOnceCallback<4>(false, ""));
 
   // The main script gets a report of the failure from the interrupt, and fails
   // in turn.
   EXPECT_CALL(
       mock_service_,
       OnGetNextActions(
-          _, "main script payload",
+          _, _, "main script payload",
           ElementsAre(Property(&ProcessedActionProto::status,
                                ProcessedActionStatusProto::INTERRUPT_FAILED)),
           _))
-      .WillOnce(RunOnceCallback<3>(false, ""));
+      .WillOnce(RunOnceCallback<4>(false, ""));
 
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, false)));
@@ -738,9 +741,9 @@
 
   // We expect to get result of interrupt action, then result of the main script
   // action.
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _))
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
       .Times(2)
-      .WillRepeatedly(RunOnceCallback<3>(true, ""));
+      .WillRepeatedly(RunOnceCallback<4>(true, ""));
 
   EXPECT_CALL(executor_callback_,
               Run(AllOf(Field(&ScriptExecutor::Result::success, true),
@@ -773,9 +776,9 @@
   presentation->set_name("name");
   presentation->mutable_precondition();
 
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _))
-      .WillOnce(RunOnceCallback<3>(true, Serialize(next_actions_response)))
-      .WillOnce(RunOnceCallback<3>(true, ""));
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+      .WillOnce(RunOnceCallback<4>(true, Serialize(next_actions_response)))
+      .WillOnce(RunOnceCallback<4>(true, ""));
 
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
@@ -805,9 +808,9 @@
       .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
 
   script->set_path("path2");
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _))
-      .WillOnce(RunOnceCallback<3>(true, Serialize(actions_response)))
-      .WillOnce(RunOnceCallback<3>(true, ""));
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+      .WillOnce(RunOnceCallback<4>(true, Serialize(actions_response)))
+      .WillOnce(RunOnceCallback<4>(true, ""));
 
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
@@ -842,10 +845,10 @@
   // We expect a call from the interrupt which will update the script list and a
   // second call from the interrupt to terminate. Then a call from the main
   // script which will finish without running any actions.
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _))
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
       .Times(3)
-      .WillOnce(RunOnceCallback<3>(true, Serialize(interrupt_actions)))
-      .WillRepeatedly(RunOnceCallback<3>(true, ""));
+      .WillOnce(RunOnceCallback<4>(true, Serialize(interrupt_actions)))
+      .WillRepeatedly(RunOnceCallback<4>(true, ""));
 
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
@@ -868,7 +871,7 @@
   interruptible.add_actions()->mutable_tell()->set_message(
       "pre-interrupt status");
   auto* wait_action = interruptible.add_actions()->mutable_wait_for_dom();
-  wait_action->add_selectors("element");
+  wait_action->mutable_wait_until()->add_selectors("element");
   wait_action->set_allow_interrupt(true);
   EXPECT_CALL(mock_service_, OnGetActions(kScriptPath, _, _, _, _, _))
       .WillRepeatedly(RunOnceCallback<5>(true, Serialize(interruptible)));
@@ -880,8 +883,8 @@
   EXPECT_CALL(mock_service_, OnGetActions(StrEq("interrupt"), _, _, _, _, _))
       .WillRepeatedly(RunOnceCallback<5>(true, Serialize(interrupt_actions)));
 
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _))
-      .WillRepeatedly(RunOnceCallback<3>(true, ""));
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+      .WillRepeatedly(RunOnceCallback<4>(true, ""));
 
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
@@ -896,13 +899,13 @@
   interruptible.add_actions()->mutable_tell()->set_message(
       "pre-interrupt status");
   auto* wait_action = interruptible.add_actions()->mutable_wait_for_dom();
-  wait_action->add_selectors("element");
+  wait_action->mutable_wait_until()->add_selectors("element");
   wait_action->set_allow_interrupt(true);
   EXPECT_CALL(mock_service_, OnGetActions(kScriptPath, _, _, _, _, _))
       .WillRepeatedly(RunOnceCallback<5>(true, Serialize(interruptible)));
 
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _))
-      .WillRepeatedly(RunOnceCallback<3>(true, ""));
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+      .WillRepeatedly(RunOnceCallback<4>(true, ""));
 
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
diff --git a/components/autofill_assistant/browser/script_precondition_unittest.cc b/components/autofill_assistant/browser/script_precondition_unittest.cc
index e4280cf..4802b9e 100644
--- a/components/autofill_assistant/browser/script_precondition_unittest.cc
+++ b/components/autofill_assistant/browser/script_precondition_unittest.cc
@@ -55,13 +55,11 @@
 class ScriptPreconditionTest : public testing::Test {
  public:
   void SetUp() override {
+    ON_CALL(mock_web_controller_, OnElementCheck(Eq(Selector({"exists"})), _))
+        .WillByDefault(RunOnceCallback<1>(true));
     ON_CALL(mock_web_controller_,
-            OnElementCheck(kExistenceCheck, Eq(Selector({"exists"})), _))
-        .WillByDefault(RunOnceCallback<2>(true));
-    ON_CALL(
-        mock_web_controller_,
-        OnElementCheck(kExistenceCheck, Eq(Selector({"does_not_exist"})), _))
-        .WillByDefault(RunOnceCallback<2>(false));
+            OnElementCheck(Eq(Selector({"does_not_exist"})), _))
+        .WillByDefault(RunOnceCallback<1>(false));
 
     SetUrl("http://www.example.com/path");
   }
@@ -174,9 +172,8 @@
 }
 
 TEST_F(ScriptPreconditionTest, IgnoreEmptyElementsExist) {
-  EXPECT_CALL(mock_web_controller_,
-              OnElementCheck(kExistenceCheck, Eq(Selector({"exists"})), _))
-      .WillOnce(RunOnceCallback<2>(true));
+  EXPECT_CALL(mock_web_controller_, OnElementCheck(Eq(Selector({"exists"})), _))
+      .WillOnce(RunOnceCallback<1>(true));
 
   ScriptPreconditionProto proto;
   proto.add_elements_exist()->add_selectors("exists");
diff --git a/components/autofill_assistant/browser/script_tracker.cc b/components/autofill_assistant/browser/script_tracker.cc
index 211729a..afb97ec 100644
--- a/components/autofill_assistant/browser/script_tracker.cc
+++ b/components/autofill_assistant/browser/script_tracker.cc
@@ -11,6 +11,7 @@
 #include "base/bind.h"
 #include "components/autofill_assistant/browser/script.h"
 #include "components/autofill_assistant/browser/script_executor.h"
+#include "components/autofill_assistant/browser/trigger_context.h"
 
 namespace autofill_assistant {
 
@@ -80,8 +81,8 @@
       continue;
 
     script->precondition->Check(
-        url, batch_element_checker_.get(), delegate_->GetParameters(),
-        scripts_state_,
+        url, batch_element_checker_.get(),
+        delegate_->GetTriggerContext()->script_parameters, scripts_state_,
         base::BindOnce(&ScriptTracker::OnPreconditionCheck,
                        weak_ptr_factory_.GetWeakPtr(), script));
   }
diff --git a/components/autofill_assistant/browser/script_tracker_unittest.cc b/components/autofill_assistant/browser/script_tracker_unittest.cc
index 17ae136..3aae6dfc 100644
--- a/components/autofill_assistant/browser/script_tracker_unittest.cc
+++ b/components/autofill_assistant/browser/script_tracker_unittest.cc
@@ -35,13 +35,11 @@
   void SetUp() override {
     delegate_.SetCurrentURL(GURL("http://www.example.com/"));
 
+    ON_CALL(mock_web_controller_, OnElementCheck(Eq(Selector({"exists"})), _))
+        .WillByDefault(RunOnceCallback<1>(true));
     ON_CALL(mock_web_controller_,
-            OnElementCheck(kExistenceCheck, Eq(Selector({"exists"})), _))
-        .WillByDefault(RunOnceCallback<2>(true));
-    ON_CALL(
-        mock_web_controller_,
-        OnElementCheck(kExistenceCheck, Eq(Selector({"does_not_exist"})), _))
-        .WillByDefault(RunOnceCallback<2>(false));
+            OnElementCheck(Eq(Selector({"does_not_exist"})), _))
+        .WillByDefault(RunOnceCallback<1>(false));
 
     // Scripts run, but have no actions.
     ON_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
@@ -278,10 +276,9 @@
 }
 
 TEST_F(ScriptTrackerTest, CheckScriptsAfterDOMChange) {
-  EXPECT_CALL(
-      mock_web_controller_,
-      OnElementCheck(kExistenceCheck, Eq(Selector({"maybe_exists"})), _))
-      .WillOnce(RunOnceCallback<2>(false));
+  EXPECT_CALL(mock_web_controller_,
+              OnElementCheck(Eq(Selector({"maybe_exists"})), _))
+      .WillOnce(RunOnceCallback<1>(false));
 
   AddScript("script name", "script path", "maybe_exists");
   SetAndCheckScripts();
@@ -290,10 +287,9 @@
   EXPECT_THAT(runnable_scripts(), IsEmpty());
 
   // DOM has changed; OnElementExists now returns true.
-  EXPECT_CALL(
-      mock_web_controller_,
-      OnElementCheck(kExistenceCheck, Eq(Selector({"maybe_exists"})), _))
-      .WillOnce(RunOnceCallback<2>(true));
+  EXPECT_CALL(mock_web_controller_,
+              OnElementCheck(Eq(Selector({"maybe_exists"})), _))
+      .WillOnce(RunOnceCallback<1>(true));
   tracker_.CheckScripts();
 
   // The script can now run
@@ -322,8 +318,8 @@
   EXPECT_CALL(mock_service_,
               OnGetActions(StrEq("runnable name"), _, _, _, _, _))
       .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _))
-      .WillOnce(RunOnceCallback<3>(true, ""));
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+      .WillOnce(RunOnceCallback<4>(true, ""));
 
   base::MockCallback<ScriptExecutor::RunScriptCallback> execute_callback;
   EXPECT_CALL(execute_callback,
@@ -364,8 +360,8 @@
   EXPECT_CALL(mock_service_,
               OnGetActions(StrEq("runnable name"), _, _, _, _, _))
       .WillOnce(RunOnceCallback<5>(true, Serialize(actions_response)));
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _))
-      .WillOnce(RunOnceCallback<3>(true, ""));
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _))
+      .WillOnce(RunOnceCallback<4>(true, ""));
 
   base::MockCallback<ScriptExecutor::RunScriptCallback> execute_callback;
   EXPECT_CALL(execute_callback,
diff --git a/components/autofill_assistant/browser/selector.cc b/components/autofill_assistant/browser/selector.cc
index b60f5d3e3..bb273c9 100644
--- a/components/autofill_assistant/browser/selector.cc
+++ b/components/autofill_assistant/browser/selector.cc
@@ -8,14 +8,15 @@
 
 namespace autofill_assistant {
 
-Selector::Selector() : pseudo_type(PseudoType::UNDEFINED) {}
+Selector::Selector() {}
 
-Selector::Selector(const ElementReferenceProto& element) {
-  for (const auto& selector : element.selectors()) {
+Selector::Selector(const ElementReferenceProto& proto) {
+  for (const auto& selector : proto.selectors()) {
     selectors.emplace_back(selector);
   }
-  inner_text_pattern = element.inner_text_pattern();
-  pseudo_type = element.pseudo_type();
+  must_be_visible = proto.visibility_requirement() == MUST_BE_VISIBLE;
+  inner_text_pattern = proto.inner_text_pattern();
+  pseudo_type = proto.pseudo_type();
 }
 
 Selector::Selector(std::vector<std::string> s)
@@ -30,25 +31,16 @@
 Selector& Selector::operator=(Selector&& other) = default;
 
 bool Selector::operator<(const Selector& other) const {
-  if (selectors < other.selectors)
-    return true;
-
-  if (selectors != other.selectors)
-    return false;
-
-  if (inner_text_pattern < other.inner_text_pattern)
-    return true;
-
-  if (inner_text_pattern != other.inner_text_pattern)
-    return false;
-
-  return pseudo_type < other.pseudo_type;
+  return std::tie(selectors, inner_text_pattern, must_be_visible, pseudo_type) <
+         std::tie(other.selectors, other.inner_text_pattern,
+                  other.must_be_visible, other.pseudo_type);
 }
 
 bool Selector::operator==(const Selector& other) const {
-  return this->selectors == other.selectors &&
-         this->inner_text_pattern == other.inner_text_pattern &&
-         this->pseudo_type == other.pseudo_type;
+  return selectors == other.selectors &&
+         inner_text_pattern == other.inner_text_pattern &&
+         must_be_visible == other.must_be_visible &&
+         pseudo_type == other.pseudo_type;
 }
 
 bool Selector::empty() const {
@@ -126,6 +118,9 @@
     out << selector.inner_text_pattern;
     out << "/";
   }
+  if (selector.must_be_visible) {
+    out << " must_be_visible";
+  }
   if (selector.pseudo_type != PseudoType::UNDEFINED) {
     out << "::" << selector.pseudo_type;
   }
diff --git a/components/autofill_assistant/browser/selector.h b/components/autofill_assistant/browser/selector.h
index 835b232..2c6552cd 100644
--- a/components/autofill_assistant/browser/selector.h
+++ b/components/autofill_assistant/browser/selector.h
@@ -21,6 +21,11 @@
   // document.
   std::vector<std::string> selectors;
 
+  // If true, only match visible elements. Visible elements are elements that
+  // have a box model. The box model is not checked at all, so an element with a
+  // zero size bounding box is considered visible.
+  bool must_be_visible = false;
+
   // If non-empty, this must be a regular expression that matches the inner text
   // of the element(s) matching selectors.
   std::string inner_text_pattern;
@@ -28,7 +33,7 @@
   // An optional pseudo type. This pseudo type is associated to the final
   // element matched by |selectors|, which means that we currently don't handle
   // matching an element inside a pseudo element.
-  PseudoType pseudo_type;
+  PseudoType pseudo_type = PseudoType::UNDEFINED;
 
   Selector();
   explicit Selector(const ElementReferenceProto& element);
@@ -44,6 +49,12 @@
   bool operator<(const Selector& other) const;
   bool operator==(const Selector& other) const;
 
+  // Convenience function to update the visible field in a fluent style.
+  Selector& MustBeVisible() {
+    must_be_visible = true;
+    return *this;
+  }
+
   // The output operator. The actual selectors are only available in debug
   // builds.
   friend std::ostream& operator<<(std::ostream& out, const Selector& selector);
diff --git a/components/autofill_assistant/browser/selector_unittest.cc b/components/autofill_assistant/browser/selector_unittest.cc
index 94a4346..c5f64d2 100644
--- a/components/autofill_assistant/browser/selector_unittest.cc
+++ b/components/autofill_assistant/browser/selector_unittest.cc
@@ -16,10 +16,12 @@
   proto.add_selectors("a");
   proto.add_selectors("b");
   proto.set_inner_text_pattern("c");
+  proto.set_visibility_requirement(MUST_BE_VISIBLE);
   proto.set_pseudo_type(PseudoType::BEFORE);
 
   Selector selector(proto);
   EXPECT_THAT(selector.selectors, testing::ElementsAre("a", "b"));
+  EXPECT_TRUE(selector.must_be_visible);
   EXPECT_EQ("c", selector.inner_text_pattern);
   EXPECT_EQ(PseudoType::BEFORE, selector.pseudo_type);
 }
@@ -37,6 +39,11 @@
   EXPECT_TRUE(Selector({"a"}, PseudoType::BEFORE) ==
               Selector({"a"}, PseudoType::BEFORE));
 
+  EXPECT_FALSE(Selector({"a"}) == Selector({"a"}).MustBeVisible());
+  EXPECT_LT(Selector({"a"}), Selector({"a"}).MustBeVisible());
+  EXPECT_TRUE(Selector({"a"}).MustBeVisible() ==
+              Selector({"a"}).MustBeVisible());
+
   EXPECT_FALSE(Selector({"a"}).MatchingInnerText("a") ==
                Selector({"a"}).MatchingInnerText("b"));
   EXPECT_LT(Selector({"a"}).MatchingInnerText("a"),
diff --git a/components/autofill_assistant/browser/service.cc b/components/autofill_assistant/browser/service.cc
index fa867267..80a9c11 100644
--- a/components/autofill_assistant/browser/service.cc
+++ b/components/autofill_assistant/browser/service.cc
@@ -15,6 +15,7 @@
 #include "base/strings/stringprintf.h"
 #include "components/autofill_assistant/browser/client.h"
 #include "components/autofill_assistant/browser/protocol_utils.h"
+#include "components/autofill_assistant/browser/trigger_context.h"
 #include "components/version_info/version_info.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/storage_partition.h"
@@ -96,21 +97,20 @@
 
 Service::~Service() {}
 
-void Service::GetScriptsForUrl(
-    const GURL& url,
-    const std::map<std::string, std::string>& parameters,
-    ResponseCallback callback) {
+void Service::GetScriptsForUrl(const GURL& url,
+                               const TriggerContext* trigger_context,
+                               ResponseCallback callback) {
   DCHECK(url.is_valid());
 
-  SendRequest(AddLoader(
-      script_server_url_,
-      ProtocolUtils::CreateGetScriptsRequest(url, parameters, client_context_),
-      std::move(callback)));
+  SendRequest(AddLoader(script_server_url_,
+                        ProtocolUtils::CreateGetScriptsRequest(
+                            url, *trigger_context, client_context_),
+                        std::move(callback)));
 }
 
 void Service::GetActions(const std::string& script_path,
                          const GURL& url,
-                         const std::map<std::string, std::string>& parameters,
+                         const TriggerContext* trigger_context,
                          const std::string& global_payload,
                          const std::string& script_payload,
                          ResponseCallback callback) {
@@ -118,21 +118,23 @@
 
   SendRequest(AddLoader(script_action_server_url_,
                         ProtocolUtils::CreateInitialScriptActionsRequest(
-                            script_path, url, parameters, global_payload,
+                            script_path, url, *trigger_context, global_payload,
                             script_payload, client_context_),
                         std::move(callback)));
 }
 
 void Service::GetNextActions(
+    const TriggerContext* trigger_context,
     const std::string& previous_global_payload,
     const std::string& previous_script_payload,
     const std::vector<ProcessedActionProto>& processed_actions,
     ResponseCallback callback) {
-  SendRequest(AddLoader(script_action_server_url_,
-                        ProtocolUtils::CreateNextScriptActionsRequest(
-                            previous_global_payload, previous_script_payload,
-                            processed_actions, client_context_),
-                        std::move(callback)));
+  SendRequest(AddLoader(
+      script_action_server_url_,
+      ProtocolUtils::CreateNextScriptActionsRequest(
+          *trigger_context, previous_global_payload, previous_script_payload,
+          processed_actions, client_context_),
+      std::move(callback)));
 }
 
 void Service::SendRequest(Loader* loader) {
diff --git a/components/autofill_assistant/browser/service.h b/components/autofill_assistant/browser/service.h
index 29f45d7..2a98643 100644
--- a/components/autofill_assistant/browser/service.h
+++ b/components/autofill_assistant/browser/service.h
@@ -25,6 +25,7 @@
 
 namespace autofill_assistant {
 class Client;
+struct TriggerContext;
 
 // Autofill assistant service to communicate with the server to get scripts and
 // client actions.
@@ -48,15 +49,14 @@
   using ResponseCallback =
       base::OnceCallback<void(bool result, const std::string&)>;
   // Get scripts for a given |url|, which should be a valid URL.
-  virtual void GetScriptsForUrl(
-      const GURL& url,
-      const std::map<std::string, std::string>& parameters,
-      ResponseCallback callback);
+  virtual void GetScriptsForUrl(const GURL& url,
+                                const TriggerContext* trigger_context,
+                                ResponseCallback callback);
 
   // Get actions.
   virtual void GetActions(const std::string& script_path,
                           const GURL& url,
-                          const std::map<std::string, std::string>& parameters,
+                          const TriggerContext* trigger_context,
                           const std::string& global_payload,
                           const std::string& script_payload,
                           ResponseCallback callback);
@@ -64,6 +64,7 @@
   // Get next sequence of actions according to server payloads in previous
   // response.
   virtual void GetNextActions(
+      const TriggerContext* trigger_context,
       const std::string& previous_global_payload,
       const std::string& previous_script_payload,
       const std::vector<ProcessedActionProto>& processed_actions,
diff --git a/components/autofill_assistant/browser/service.proto b/components/autofill_assistant/browser/service.proto
index 587db658..267e145c 100644
--- a/components/autofill_assistant/browser/service.proto
+++ b/components/autofill_assistant/browser/service.proto
@@ -34,6 +34,9 @@
   // country should be a country code as defined by ISO 3166-1-alpha-2.
   // The intent is to communicate the client's location to the server.
   optional string country = 6;
+
+  // Experiment ids string provided by the 'caller'.
+  optional string experiment_ids = 7;
 }
 
 // Get the list of scripts that can potentially be run on a url.
@@ -463,15 +466,18 @@
   // Failed to get a stable position for the element, usually to click on it.
   ELEMENT_UNSTABLE = 14;
 
+  // A selector included into the current action is invalid.
+  INVALID_SELECTOR = 15;
+
   // The value passed to the select option action does not exist in the element.
   // This is usually a scripting error.
-  OPTION_VALUE_NOT_FOUND = 15;
+  OPTION_VALUE_NOT_FOUND = 16;
 
   // The client got an unexpected error from a JavaScript snippet executed
   // through devtools. This means that there's a bug in the client code.
   //
   // ProcessedActionProto.UnexpectedErrorInfoProto contains more details.
-  UNEXPECTED_JS_ERROR = 16;
+  UNEXPECTED_JS_ERROR = 17;
 }
 
 // The pseudo type values come from
@@ -512,12 +518,30 @@
   // trying to get the pseudo_type, if any was set.
   optional string inner_text_pattern = 4;
 
+  // Specifies whether the matched element(s) must be visible.
+  //
+  // Visibility applies to the element matched in selectors; the pseudo type is
+  // checked afterwards.
+  optional VisibilityRequirement visibility_requirement = 5;
+
   // An optional pseudo type. This pseudo type is associated to the final
   // element matched, which means that we currently don't handle matching an
   // element inside a pseudo element.
   optional PseudoType pseudo_type = 3;
 }
 
+enum VisibilityRequirement {
+  UNSPECIFIED_VISIBILITY = 0;
+
+  // Element must be visible. Visible elements are elements that have a box
+  // model. The box model is not checked at all, so an element with a zero size
+  // bounding box is considered visible.
+  MUST_BE_VISIBLE = 1;
+
+  // It's enough for the element to exist in the DOM tree for it to match.
+  MUST_EXIST = 2;
+}
+
 // Contain all arguments to perform a click.
 message ClickProto {
   optional ElementReferenceProto element_to_click = 1;
@@ -631,13 +655,15 @@
   // Fail after waiting this amount of time.
   optional int32 timeout_ms = 1;
 
-  // The element to wait for.
-  // TODO(crbug.com/806868): Use ElementReferenceProto instead.
-  repeated string selectors = 2;
+  // Wait until there exists at least one element that matches the given
+  // selector.
+  optional ElementReferenceProto wait_until = 5;
 
   // If true, run scripts flagged with 'interrupt=true' as soon as their
   // preconditions match.
   optional bool allow_interrupt = 3;
+
+  reserved 4;
 }
 
 // Volatile upload of a portion of the dom for backend analysis, does not store
diff --git a/components/autofill_assistant/browser/trigger_context.cc b/components/autofill_assistant/browser/trigger_context.cc
new file mode 100644
index 0000000..961d56f
--- /dev/null
+++ b/components/autofill_assistant/browser/trigger_context.cc
@@ -0,0 +1,17 @@
+// 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 "components/autofill_assistant/browser/trigger_context.h"
+
+namespace autofill_assistant {
+
+TriggerContext::TriggerContext(std::map<std::string, std::string> params,
+                               std::string exp)
+    : script_parameters(std::move(params)), experiment_ids(std::move(exp)) {}
+
+TriggerContext::TriggerContext() = default;
+TriggerContext::TriggerContext(const TriggerContext& context) = default;
+TriggerContext::~TriggerContext() = default;
+
+}  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/trigger_context.h b/components/autofill_assistant/browser/trigger_context.h
new file mode 100644
index 0000000..fb0697e
--- /dev/null
+++ b/components/autofill_assistant/browser/trigger_context.h
@@ -0,0 +1,33 @@
+// 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 COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_TRIGGER_CONTEXT_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_TRIGGER_CONTEXT_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+
+namespace autofill_assistant {
+
+// A trigger context for data provided by callers.
+struct TriggerContext {
+  // Script parameters provided by the caller.
+  std::map<std::string, std::string> script_parameters;
+
+  // Experiment ids to be passed to the backend in requests. They may also be
+  // used to change client behavior.
+  std::string experiment_ids;
+
+  TriggerContext();
+  TriggerContext(std::map<std::string, std::string> params, std::string exp);
+  TriggerContext(const TriggerContext& context);
+  ~TriggerContext();
+};
+
+}  // namespace autofill_assistant
+
+#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_TRIGGER_CONTEXT_H_
diff --git a/components/autofill_assistant/browser/web_controller.cc b/components/autofill_assistant/browser/web_controller.cc
index acc4d4e..f20400e 100644
--- a/components/autofill_assistant/browser/web_controller.cc
+++ b/components/autofill_assistant/browser/web_controller.cc
@@ -469,7 +469,6 @@
   ElementFinder(content::WebContents* web_contents_,
                 DevtoolsClient* devtools_client,
                 const Selector& selector,
-                ElementCheckType check_type,
                 bool strict);
   ~ElementFinder() override;
 
@@ -500,7 +499,6 @@
   content::WebContents* const web_contents_;
   DevtoolsClient* const devtools_client_;
   const Selector selector_;
-  const ElementCheckType check_type_;
   const bool strict_;
   FindElementCallback callback_;
   std::unique_ptr<FindElementResult> element_result_;
@@ -511,12 +509,10 @@
 WebController::ElementFinder::ElementFinder(content::WebContents* web_contents,
                                             DevtoolsClient* devtools_client,
                                             const Selector& selector,
-                                            ElementCheckType check_type,
                                             bool strict)
     : web_contents_(web_contents),
       devtools_client_(devtools_client),
       selector_(selector),
-      check_type_(check_type),
       strict_(strict),
       element_result_(std::make_unique<FindElementResult>()),
       weak_ptr_factory_(this) {}
@@ -572,13 +568,12 @@
           .Build());
   std::string function;
   if (index == (selector_.selectors.size() - 1)) {
-    bool visible = check_type_ == kVisibilityCheck;
-    if (visible || !selector_.inner_text_pattern.empty()) {
+    if (selector_.must_be_visible || !selector_.inner_text_pattern.empty()) {
       function.assign(kQuerySelectorWithConditions);
-      argument.emplace_back(
-          runtime::CallArgument::Builder()
-              .SetValue(base::Value::ToUniquePtrValue(base::Value(visible)))
-              .Build());
+      argument.emplace_back(runtime::CallArgument::Builder()
+                                .SetValue(base::Value::ToUniquePtrValue(
+                                    base::Value(selector_.must_be_visible)))
+                                .Build());
       argument.emplace_back(runtime::CallArgument::Builder()
                                 .SetValue(base::Value::ToUniquePtrValue(
                                     base::Value(selector_.inner_text_pattern)))
@@ -826,7 +821,7 @@
     const Selector& selector,
     base::OnceCallback<void(const ClientStatus&)> callback) {
   DCHECK(!selector.empty());
-  FindElement(selector, kVisibilityCheck,
+  FindElement(selector,
               /* strict_mode= */ true,
               base::BindOnce(&WebController::OnFindElementForClickOrTap,
                              weak_ptr_factory_.GetWeakPtr(),
@@ -837,7 +832,7 @@
     const Selector& selector,
     base::OnceCallback<void(const ClientStatus&)> callback) {
   DCHECK(!selector.empty());
-  FindElement(selector, kVisibilityCheck,
+  FindElement(selector,
               /* strict_mode= */ true,
               base::BindOnce(&WebController::OnFindElementForClickOrTap,
                              weak_ptr_factory_.GetWeakPtr(),
@@ -1024,13 +1019,12 @@
   std::move(callback).Run(OkClientStatus());
 }
 
-void WebController::ElementCheck(ElementCheckType check_type,
-                                 const Selector& selector,
+void WebController::ElementCheck(const Selector& selector,
                                  bool strict,
                                  base::OnceCallback<void(bool)> callback) {
   DCHECK(!selector.empty());
   FindElement(
-      selector, check_type, strict,
+      selector, strict,
       base::BindOnce(&WebController::OnFindElementForCheck,
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
 }
@@ -1043,11 +1037,10 @@
 }
 
 void WebController::FindElement(const Selector& selector,
-                                ElementCheckType check_type,
                                 bool strict_mode,
                                 FindElementCallback callback) {
   auto finder = std::make_unique<ElementFinder>(
-      web_contents_, devtools_client_.get(), selector, check_type, strict_mode);
+      web_contents_, devtools_client_.get(), selector, strict_mode);
   ElementFinder* ptr = finder.get();
   pending_workers_[ptr] = std::move(finder);
   ptr->Start(base::BindOnce(&WebController::OnFindElementResult,
@@ -1128,7 +1121,7 @@
   auto data_to_autofill = std::make_unique<FillFormInputData>();
   data_to_autofill->profile =
       std::make_unique<autofill::AutofillProfile>(*profile);
-  FindElement(selector, kExistenceCheck,
+  FindElement(selector,
               /* strict_mode= */ true,
               base::BindOnce(&WebController::OnFindElementForFillingForm,
                              weak_ptr_factory_.GetWeakPtr(),
@@ -1205,7 +1198,7 @@
   auto data_to_autofill = std::make_unique<FillFormInputData>();
   data_to_autofill->card = std::move(card);
   data_to_autofill->cvc = cvc;
-  FindElement(selector, kExistenceCheck,
+  FindElement(selector,
               /* strict_mode= */ true,
               base::BindOnce(&WebController::OnFindElementForFillingForm,
                              weak_ptr_factory_.GetWeakPtr(),
@@ -1218,7 +1211,7 @@
     const std::string& selected_option,
     base::OnceCallback<void(const ClientStatus&)> callback) {
   DVLOG(3) << __func__ << " " << selector << ", option=" << selected_option;
-  FindElement(selector, kExistenceCheck,
+  FindElement(selector,
               /* strict_mode= */ true,
               base::BindOnce(&WebController::OnFindElementForSelectOption,
                              weak_ptr_factory_.GetWeakPtr(), selected_option,
@@ -1273,7 +1266,7 @@
     base::OnceCallback<void(const ClientStatus&)> callback) {
   DVLOG(3) << __func__ << " " << selector;
   FindElement(
-      selector, kVisibilityCheck,
+      selector,
       /* strict_mode= */ true,
       base::BindOnce(&WebController::OnFindElementForHighlightElement,
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
@@ -1326,7 +1319,7 @@
   DVLOG(3) << __func__ << " " << selector;
   DCHECK(!selector.empty());
   FindElement(
-      selector, kVisibilityCheck,
+      selector,
       /* strict_mode= */ false,
       base::BindOnce(&WebController::OnFindElementForFocusElement,
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
@@ -1336,7 +1329,7 @@
     const Selector& selector,
     base::OnceCallback<void(bool, const std::string&)> callback) {
   FindElement(
-      selector, kExistenceCheck,
+      selector,
       /* strict_mode= */ true,
       base::BindOnce(&WebController::OnFindElementForGetFieldValue,
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
@@ -1401,7 +1394,7 @@
     const Selector& selector,
     const std::string& value,
     base::OnceCallback<void(const ClientStatus&)> callback) {
-  FindElement(selector, kExistenceCheck,
+  FindElement(selector,
               /* strict_mode= */ true,
               base::BindOnce(&WebController::OnFindElementForSetFieldValue,
                              weak_ptr_factory_.GetWeakPtr(), value,
@@ -1534,7 +1527,7 @@
 
   DCHECK(!selector.empty());
   DCHECK_GT(attribute.size(), 0u);
-  FindElement(selector, kExistenceCheck,
+  FindElement(selector,
               /* strict_mode= */ true,
               base::BindOnce(&WebController::OnFindElementForSetAttribute,
                              weak_ptr_factory_.GetWeakPtr(), attribute, value,
@@ -1601,7 +1594,7 @@
   }
 
   DCHECK(!selector.empty());
-  FindElement(selector, kVisibilityCheck,
+  FindElement(selector,
               /* strict_mode= */ true,
               base::BindOnce(&WebController::OnFindElementForSendKeyboardInput,
                              weak_ptr_factory_.GetWeakPtr(), selector,
@@ -1630,7 +1623,7 @@
         callback) {
   DVLOG(3) << __func__ << " " << selector;
   FindElement(
-      selector, kExistenceCheck,
+      selector,
       /* strict_mode= */ true,
       base::BindOnce(&WebController::OnFindElementForGetOuterHtml,
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
@@ -1640,7 +1633,7 @@
     const Selector& selector,
     base::OnceCallback<void(bool, const RectF&)> callback) {
   FindElement(
-      selector, kVisibilityCheck, /* strict_mode= */ true,
+      selector, /* strict_mode= */ true,
       base::BindOnce(&WebController::OnFindElementForPosition,
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
 }
diff --git a/components/autofill_assistant/browser/web_controller.h b/components/autofill_assistant/browser/web_controller.h
index 368cc72..94ce15dfa 100644
--- a/components/autofill_assistant/browser/web_controller.h
+++ b/components/autofill_assistant/browser/web_controller.h
@@ -162,19 +162,13 @@
   virtual void HasCookie(base::OnceCallback<void(bool)> callback);
   virtual void ClearCookie();
 
-  // Checks an element for:
+  // Checks whether an element matches the given selector.
   //
-  // kExistenceCheck: Checks whether at least one element given by |selector|
-  // exists on the web page.
-  //
-  // kVisibilityCheck: Checks whether at least on element given by |selector|
-  // is visible on the web page.
-  //
-  // If strict, there must be exactly one element.
+  // If strict, there must be exactly one matching element for the check to
+  // pass. Otherwise, there must be at least one.
   //
   // To check multiple elements, use a BatchElementChecker.
-  virtual void ElementCheck(ElementCheckType type,
-                            const Selector& selector,
+  virtual void ElementCheck(const Selector& selector,
                             bool strict,
                             base::OnceCallback<void(bool)> callback);
 
@@ -295,7 +289,6 @@
   // |selector| and if |strict_mode| is false, return the first one that is
   // found. Otherwise if |strict-mode| is true, do not return any.
   void FindElement(const Selector& selector,
-                   ElementCheckType check_type,
                    bool strict_mode,
                    FindElementCallback callback);
   void OnFindElementResult(ElementFinder* finder_to_release,
diff --git a/components/autofill_assistant/browser/web_controller_browsertest.cc b/components/autofill_assistant/browser/web_controller_browsertest.cc
index 26cd2e6..f52d0ab 100644
--- a/components/autofill_assistant/browser/web_controller_browsertest.cc
+++ b/components/autofill_assistant/browser/web_controller_browsertest.cc
@@ -21,10 +21,6 @@
 
 const char* kTargetWebsitePath = "/autofill_assistant_target_website.html";
 
-std::ostream& operator<<(std::ostream& out, ElementCheckType check_type) {
-  return out << (check_type == kVisibilityCheck ? "visibility" : "existence");
-}
-
 class WebControllerBrowserTest : public content::ContentBrowserTest,
                                  public content::WebContentsObserver {
  public:
@@ -74,29 +70,21 @@
     } while (page_is_loading || paint_occurred_during_last_loop_);
   }
 
-  void RunStrictElementCheck(ElementCheckType check_type,
-                             const Selector& selector,
-                             bool result) {
-    RunElementCheck(check_type, /* strict= */ true, selector, result);
+  void RunStrictElementCheck(const Selector& selector, bool result) {
+    RunElementCheck(/* strict= */ true, selector, result);
   }
 
-  void RunLaxElementCheck(ElementCheckType check_type,
-                          const Selector& selector,
-                          bool result) {
-    RunElementCheck(check_type, /* strict= */ false, selector, result);
+  void RunLaxElementCheck(const Selector& selector, bool result) {
+    RunElementCheck(/* strict= */ false, selector, result);
   }
 
-  void RunElementCheck(ElementCheckType check_type,
-                       bool strict,
-                       const Selector& selector,
-                       bool result) {
+  void RunElementCheck(bool strict, const Selector& selector, bool result) {
     std::vector<Selector> selectors{selector};
     std::vector<bool> results{result};
-    RunElementChecks(check_type, strict, selectors, results);
+    RunElementChecks(strict, selectors, results);
   }
 
-  void RunElementChecks(ElementCheckType check_type,
-                        bool strict,
+  void RunElementChecks(bool strict,
                         const std::vector<Selector>& selectors,
                         const std::vector<bool> results) {
     base::RunLoop run_loop;
@@ -104,23 +92,20 @@
     size_t pending_number_of_checks = selectors.size();
     for (size_t i = 0; i < selectors.size(); i++) {
       web_controller_->ElementCheck(
-          check_type, selectors[i], strict,
+          selectors[i], strict,
           base::BindOnce(&WebControllerBrowserTest::CheckElementVisibleCallback,
                          base::Unretained(this), run_loop.QuitClosure(),
-                         selectors[i], check_type, &pending_number_of_checks,
-                         results[i]));
+                         selectors[i], &pending_number_of_checks, results[i]));
     }
     run_loop.Run();
   }
 
   void CheckElementVisibleCallback(const base::Closure& done_callback,
                                    const Selector& selector,
-                                   ElementCheckType check_type,
                                    size_t* pending_number_of_checks_output,
                                    bool expected_result,
                                    bool result) {
-    EXPECT_EQ(expected_result, result)
-        << "selector: " << selector << " " << check_type;
+    EXPECT_EQ(expected_result, result) << "selector: " << selector;
     *pending_number_of_checks_output -= 1;
     if (*pending_number_of_checks_output == 0) {
       done_callback.Run();
@@ -159,7 +144,7 @@
   void WaitForElementRemove(const Selector& selector) {
     base::RunLoop run_loop;
     web_controller_->ElementCheck(
-        kExistenceCheck, selector, /* strict= */ false,
+        selector, /* strict= */ false,
         base::BindOnce(&WebControllerBrowserTest::OnWaitForElementRemove,
                        base::Unretained(this), run_loop.QuitClosure(),
                        selector));
@@ -251,13 +236,12 @@
     done_callback.Run();
   }
 
-  void FindElement(ElementCheckType check_type,
-                   const Selector& selector,
+  void FindElement(const Selector& selector,
                    ClientStatus* status_out,
                    WebController::FindElementResult* result_out) {
     base::RunLoop run_loop;
     web_controller_->FindElement(
-        selector, check_type, /* strict_mode= */ true,
+        selector, /* strict_mode= */ true,
         base::BindOnce(&WebControllerBrowserTest::OnFindElement,
                        base::Unretained(this), run_loop.QuitClosure(),
                        base::Unretained(status_out),
@@ -279,24 +263,22 @@
       *result_out = *result;
   }
 
-  void FindElementAndCheck(ElementCheckType check_type,
-                           const Selector& selector,
+  void FindElementAndCheck(const Selector& selector,
                            size_t expected_index,
                            bool is_main_frame) {
-    SCOPED_TRACE(::testing::Message() << selector << " strict, " << check_type);
+    SCOPED_TRACE(::testing::Message() << selector << " strict");
     ClientStatus status;
     WebController::FindElementResult result;
-    FindElement(check_type, selector, &status, &result);
+    FindElement(selector, &status, &result);
     EXPECT_EQ(ACTION_APPLIED, status.proto_status());
     CheckFindElementResult(result, expected_index, is_main_frame);
   }
 
-  void FindElementExpectEmptyResult(ElementCheckType check_type,
-                                    const Selector& selector) {
-    SCOPED_TRACE(::testing::Message() << selector << " strict, " << check_type);
+  void FindElementExpectEmptyResult(const Selector& selector) {
+    SCOPED_TRACE(::testing::Message() << selector << " strict");
     ClientStatus status;
     WebController::FindElementResult result;
-    FindElement(check_type, selector, &status, &result);
+    FindElement(selector, &status, &result);
     EXPECT_EQ(ELEMENT_RESOLUTION_FAILED, status.proto_status());
     EXPECT_THAT(result.object_id, IsEmpty());
   }
@@ -447,105 +429,114 @@
 
 IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, ElementExistenceCheck) {
   // A visible element
-  RunLaxElementCheck(kExistenceCheck, Selector({"#button"}), true);
+  RunLaxElementCheck(Selector({"#button"}), true);
 
   // A hidden element.
-  RunLaxElementCheck(kExistenceCheck, Selector({"#hidden"}), true);
+  RunLaxElementCheck(Selector({"#hidden"}), true);
 
   // A nonexistent element.
-  RunLaxElementCheck(kExistenceCheck, Selector({"#doesnotexist"}), false);
+  RunLaxElementCheck(Selector({"#doesnotexist"}), false);
 
   // A pseudo-element
-  RunLaxElementCheck(kExistenceCheck,
-                     Selector({"#terms-and-conditions"}, BEFORE), true);
+  RunLaxElementCheck(Selector({"#terms-and-conditions"}, BEFORE), true);
 
   // An invisible pseudo-element
   //
   // TODO(b/129461999): This is wrong; it should exist. Fix it.
-  RunLaxElementCheck(kExistenceCheck, Selector({"#button"}, BEFORE), false);
+  RunLaxElementCheck(Selector({"#button"}, BEFORE), false);
 
   // A non-existent pseudo-element
-  RunLaxElementCheck(kExistenceCheck, Selector({"#button"}, AFTER), false);
+  RunLaxElementCheck(Selector({"#button"}, AFTER), false);
 }
 
-IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, ElementVisibilityCheck) {
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, VisibilityRequirementCheck) {
   // A visible element
-  RunLaxElementCheck(kVisibilityCheck, Selector({"#button"}), true);
+  RunLaxElementCheck(Selector({"#button"}).MustBeVisible(), true);
 
   // A hidden element.
-  RunLaxElementCheck(kVisibilityCheck, Selector({"#hidden"}), false);
+  RunLaxElementCheck(Selector({"#hidden"}).MustBeVisible(), false);
 
   // A non-existent element
-  RunLaxElementCheck(kVisibilityCheck, Selector({"#doesnotexist"}), false);
+  RunLaxElementCheck(Selector({"#doesnotexist"}).MustBeVisible(), false);
 
   // A pseudo-element
-  RunLaxElementCheck(kVisibilityCheck,
-                     Selector({"#terms-and-conditions"}, BEFORE), true);
+  RunLaxElementCheck(
+      Selector({"#terms-and-conditions"}, BEFORE).MustBeVisible(), true);
 
   // An invisible pseudo-element
-  RunLaxElementCheck(kVisibilityCheck, Selector({"#button"}, BEFORE), false);
+  RunLaxElementCheck(Selector({"#button"}, BEFORE).MustBeVisible(), false);
 
   // A non-existent pseudo-element
-  RunLaxElementCheck(kVisibilityCheck, Selector({"#button"}, AFTER), false);
+  RunLaxElementCheck(Selector({"#button"}, AFTER).MustBeVisible(), false);
 }
 
 IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, MultipleVisibleElementCheck) {
   // both visible
-  RunLaxElementCheck(kVisibilityCheck, Selector({"#button,#select"}), true);
-  RunStrictElementCheck(kVisibilityCheck, Selector({"#button,#select"}), false);
+  RunLaxElementCheck(Selector({"#button,#select"}).MustBeVisible(), true);
+  RunStrictElementCheck(Selector({"#button,#select"}).MustBeVisible(), false);
 
   // one visible (first non-visible)
-  RunLaxElementCheck(kVisibilityCheck, Selector({"#hidden,#select"}), true);
-  RunStrictElementCheck(kVisibilityCheck, Selector({"#hidden,#select"}), true);
+  RunLaxElementCheck(Selector({"#hidden,#select"}).MustBeVisible(), true);
+  RunStrictElementCheck(Selector({"#hidden,#select"}).MustBeVisible(), true);
 
   // one visible (first visible)
-  RunLaxElementCheck(kVisibilityCheck, Selector({"#button,#hidden"}), true);
-  RunStrictElementCheck(kVisibilityCheck, Selector({"#hidden,#select"}), true);
+  RunLaxElementCheck(Selector({"#button,#hidden"}).MustBeVisible(), true);
+  RunStrictElementCheck(Selector({"#hidden,#select"}).MustBeVisible(), true);
 
   // one invisible, one non-existent
-  RunLaxElementCheck(kVisibilityCheck, Selector({"#doesnotexist,#hidden"}),
+  RunLaxElementCheck(Selector({"#doesnotexist,#hidden"}).MustBeVisible(),
                      false);
-  RunStrictElementCheck(kVisibilityCheck, Selector({"#doesnotexist,#hidden"}),
+  RunStrictElementCheck(Selector({"#doesnotexist,#hidden"}).MustBeVisible(),
                         false);
 }
 
 IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, InnerTextCondition) {
   Selector selector({"#with_inner_text span"});
-  RunLaxElementCheck(kVisibilityCheck, selector, true);
-  RunStrictElementCheck(kVisibilityCheck, selector, false);
+  selector.must_be_visible = true;
+  RunLaxElementCheck(selector, true);
+  RunStrictElementCheck(selector.MustBeVisible(), false);
 
   // No matches
   selector.inner_text_pattern = "no match";
-  RunLaxElementCheck(kExistenceCheck, selector, false);
-  RunLaxElementCheck(kVisibilityCheck, selector, false);
+  selector.must_be_visible = false;
+  RunLaxElementCheck(selector, false);
+  selector.must_be_visible = true;
+  RunLaxElementCheck(selector, false);
 
   // Matches exactly one visible element.
   selector.inner_text_pattern = "hello, world";
-  RunLaxElementCheck(kExistenceCheck, selector, true);
-  RunStrictElementCheck(kExistenceCheck, selector, true);
-  RunLaxElementCheck(kVisibilityCheck, selector, true);
-  RunStrictElementCheck(kVisibilityCheck, selector, true);
+  selector.must_be_visible = false;
+  RunLaxElementCheck(selector, true);
+  RunStrictElementCheck(selector, true);
+  selector.must_be_visible = true;
+  RunLaxElementCheck(selector, true);
+  RunStrictElementCheck(selector, true);
 
   // Matches two visible elements
   selector.inner_text_pattern = "^hello";
-  RunLaxElementCheck(kExistenceCheck, selector, true);
-  RunStrictElementCheck(kExistenceCheck, selector, false);
-  RunLaxElementCheck(kVisibilityCheck, selector, true);
-  RunStrictElementCheck(kVisibilityCheck, selector, false);
+  selector.must_be_visible = false;
+  RunLaxElementCheck(selector, true);
+  RunStrictElementCheck(selector, false);
+  selector.must_be_visible = true;
+  RunLaxElementCheck(selector, true);
+  RunStrictElementCheck(selector, false);
 
   // Matches one visible, one invisible element
   selector.inner_text_pattern = "world$";
-  RunLaxElementCheck(kExistenceCheck, selector, true);
-  RunStrictElementCheck(kExistenceCheck, selector, false);
-  RunLaxElementCheck(kVisibilityCheck, selector, true);
-  RunStrictElementCheck(kVisibilityCheck, selector, true);
+  selector.must_be_visible = false;
+  RunLaxElementCheck(selector, true);
+  RunStrictElementCheck(selector, false);
+  selector.must_be_visible = true;
+  RunLaxElementCheck(selector, true);
+  RunStrictElementCheck(selector, true);
 
   // Inner text conditions are applied before looking for the pseudo-type.
   selector.pseudo_type = PseudoType::BEFORE;
   selector.inner_text_pattern = "world";
-  RunLaxElementCheck(kExistenceCheck, selector, true);
+  selector.must_be_visible = false;
+  RunLaxElementCheck(selector, true);
   selector.inner_text_pattern = "before";  // matches :before content
-  RunLaxElementCheck(kExistenceCheck, selector, false);
+  RunLaxElementCheck(selector, false);
 }
 
 IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest,
@@ -554,6 +545,7 @@
   std::vector<bool> results;
 
   Selector a_selector;
+  a_selector.must_be_visible = true;
   a_selector.selectors.emplace_back("#button");
   selectors.emplace_back(a_selector);
   results.emplace_back(true);
@@ -609,7 +601,7 @@
   selectors.emplace_back(a_selector);
   results.emplace_back(false);
 
-  RunElementChecks(kVisibilityCheck, /* strict= */ false, selectors, results);
+  RunElementChecks(/* strict= */ false, selectors, results);
 }
 
 IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, ClickElement) {
@@ -689,38 +681,44 @@
 IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, FindElement) {
   Selector selector;
   selector.selectors.emplace_back("#button");
-  FindElementAndCheck(kExistenceCheck, selector, 0, true);
-  FindElementAndCheck(kVisibilityCheck, selector, 0, true);
+  FindElementAndCheck(selector, 0, true);
+  selector.must_be_visible = true;
+  FindElementAndCheck(selector, 0, true);
 
   // IFrame.
   selector.selectors.clear();
   selector.selectors.emplace_back("#iframe");
   selector.selectors.emplace_back("#button");
-  FindElementAndCheck(kExistenceCheck, selector, 0, false);
-  FindElementAndCheck(kVisibilityCheck, selector, 0, false);
+  selector.must_be_visible = false;
+  FindElementAndCheck(selector, 0, false);
+  selector.must_be_visible = true;
+  FindElementAndCheck(selector, 0, false);
 
   selector.selectors.clear();
   selector.selectors.emplace_back("#iframe");
   selector.selectors.emplace_back("[name=name]");
-  FindElementAndCheck(kExistenceCheck, selector, 0, false);
-  FindElementAndCheck(kVisibilityCheck, selector, 0, false);
+  selector.must_be_visible = false;
+  FindElementAndCheck(selector, 0, false);
+  selector.must_be_visible = true;
+  FindElementAndCheck(selector, 0, false);
 
   // IFrame inside IFrame.
   selector.selectors.clear();
   selector.selectors.emplace_back("#iframe");
   selector.selectors.emplace_back("#iframe");
   selector.selectors.emplace_back("#button");
-  FindElementAndCheck(kExistenceCheck, selector, 1, false);
-  FindElementAndCheck(kVisibilityCheck, selector, 1, false);
+  selector.must_be_visible = false;
+  FindElementAndCheck(selector, 1, false);
+  selector.must_be_visible = true;
+  FindElementAndCheck(selector, 1, false);
 }
 
 IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, FindElementNotFound) {
-  FindElementExpectEmptyResult(kExistenceCheck, Selector({"#notfound"}));
-  FindElementExpectEmptyResult(kVisibilityCheck, Selector({"#hidden"}));
-  FindElementExpectEmptyResult(kExistenceCheck,
-                               Selector({"#iframe", "#iframe", "#notfound"}));
-  FindElementExpectEmptyResult(kVisibilityCheck,
-                               Selector({"#iframe", "#iframe", "#hidden"}));
+  FindElementExpectEmptyResult(Selector({"#notfound"}));
+  FindElementExpectEmptyResult(Selector({"#hidden"}).MustBeVisible());
+  FindElementExpectEmptyResult(Selector({"#iframe", "#iframe", "#notfound"}));
+  FindElementExpectEmptyResult(
+      Selector({"#iframe", "#iframe", "#hidden"}).MustBeVisible());
 }
 
 IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, FocusElement) {
diff --git a/components/browser_sync/abstract_profile_sync_service_test.cc b/components/browser_sync/abstract_profile_sync_service_test.cc
index 8b39f65..f500983c 100644
--- a/components/browser_sync/abstract_profile_sync_service_test.cc
+++ b/components/browser_sync/abstract_profile_sync_service_test.cc
@@ -80,7 +80,7 @@
           std::move(callback_),
           network::TestNetworkConnectionTracker::GetInstance());
   params.credentials.email = "testuser@gmail.com";
-  params.credentials.sync_token = "token";
+  params.credentials.access_token = "token";
   params.restored_key_for_bootstrapping.clear();
 
   // It'd be nice if we avoided creating the EngineComponentsFactory in the
diff --git a/components/domain_reliability/dispatcher.cc b/components/domain_reliability/dispatcher.cc
index 0dd1c17..8f69718 100644
--- a/components/domain_reliability/dispatcher.cc
+++ b/components/domain_reliability/dispatcher.cc
@@ -4,7 +4,6 @@
 
 #include "components/domain_reliability/dispatcher.h"
 
-#include <algorithm>
 #include <memory>
 #include <utility>
 
@@ -124,11 +123,7 @@
   if (task->eligible)
     eligible_tasks_.erase(task);
 
-  auto it = std::find_if(tasks_.begin(), tasks_.end(),
-                         [task](const std::unique_ptr<Task>& task_ptr) {
-                           return task_ptr.get() == task;
-                         });
-
+  auto it = tasks_.find(task);
   DCHECK(it != tasks_.end());
   tasks_.erase(it);
 }
diff --git a/components/domain_reliability/dispatcher.h b/components/domain_reliability/dispatcher.h
index b65d404..cd7d750 100644
--- a/components/domain_reliability/dispatcher.h
+++ b/components/domain_reliability/dispatcher.h
@@ -9,6 +9,7 @@
 #include <set>
 
 #include "base/callback_forward.h"
+#include "base/containers/unique_ptr_adapters.h"
 #include "base/macros.h"
 #include "base/time/time.h"
 #include "components/domain_reliability/domain_reliability_export.h"
@@ -58,7 +59,7 @@
   void RunAndDeleteTask(Task* task);
 
   MockableTime* time_;
-  std::set<std::unique_ptr<Task>> tasks_;
+  std::set<std::unique_ptr<Task>, base::UniquePtrComparator> tasks_;
   std::set<Task*> eligible_tasks_;
 
   DISALLOW_COPY_AND_ASSIGN(DomainReliabilityDispatcher);
diff --git a/components/drive/chromeos/directory_loader.cc b/components/drive/chromeos/directory_loader.cc
index df83a1d..d7090f3f 100644
--- a/components/drive/chromeos/directory_loader.cc
+++ b/components/drive/chromeos/directory_loader.cc
@@ -6,7 +6,6 @@
 
 #include <stddef.h>
 
-#include <algorithm>
 #include <utility>
 
 #include "base/bind.h"
@@ -611,11 +610,7 @@
   DCHECK(!directory_fetch_info.empty());
 
   // Delete the fetcher.
-  auto it = std::find_if(fast_fetch_feed_fetcher_set_.begin(),
-                         fast_fetch_feed_fetcher_set_.end(),
-                         [fetcher](const std::unique_ptr<FeedFetcher>& ptr) {
-                           return ptr.get() == fetcher;
-                         });
+  auto it = fast_fetch_feed_fetcher_set_.find(fetcher);
   fast_fetch_feed_fetcher_set_.erase(it);
 
   logger_->Log(logging::LOG_INFO,
diff --git a/components/drive/chromeos/directory_loader.h b/components/drive/chromeos/directory_loader.h
index 06e075f9..3e612ca 100644
--- a/components/drive/chromeos/directory_loader.h
+++ b/components/drive/chromeos/directory_loader.h
@@ -14,6 +14,7 @@
 #include <vector>
 
 #include "base/callback.h"
+#include "base/containers/unique_ptr_adapters.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/observer_list.h"
@@ -152,7 +153,8 @@
   LoadCallbackMap pending_load_callback_;
 
   // Set of the running feed fetcher for the fast fetch.
-  std::set<std::unique_ptr<FeedFetcher>> fast_fetch_feed_fetcher_set_;
+  std::set<std::unique_ptr<FeedFetcher>, base::UniquePtrComparator>
+      fast_fetch_feed_fetcher_set_;
 
   // The root entry path for changes being loaded by this directory loader.
   // Can be a team drive root entry or for the users default corpus will be the
diff --git a/components/history/core/browser/sync/typed_url_sync_metadata_database.cc b/components/history/core/browser/sync/typed_url_sync_metadata_database.cc
index 9b95fbbe..1f76bce86 100644
--- a/components/history/core/browser/sync/typed_url_sync_metadata_database.cc
+++ b/components/history/core/browser/sync/typed_url_sync_metadata_database.cc
@@ -4,6 +4,8 @@
 
 #include "components/history/core/browser/sync/typed_url_sync_metadata_database.h"
 
+#include <memory>
+
 #include "base/big_endian.h"
 #include "base/logging.h"
 #include "sql/meta_table.h"
@@ -170,9 +172,9 @@
     std::string storage_key(sizeof(URLID), 0);
     base::WriteBigEndian<URLID>(&storage_key[0], s.ColumnInt64(0));
     std::string serialized_metadata = s.ColumnString(1);
-    sync_pb::EntityMetadata entity_metadata;
-    if (entity_metadata.ParseFromString(serialized_metadata)) {
-      metadata_batch->AddMetadata(storage_key, entity_metadata);
+    auto entity_metadata = std::make_unique<sync_pb::EntityMetadata>();
+    if (entity_metadata->ParseFromString(serialized_metadata)) {
+      metadata_batch->AddMetadata(storage_key, std::move(entity_metadata));
     } else {
       DLOG(WARNING) << "Failed to deserialize TYPED_URLS model type "
                        "sync_pb::EntityMetadata.";
diff --git a/components/invalidation/impl/sync_system_resources.cc b/components/invalidation/impl/sync_system_resources.cc
index 17931cc0..153946a 100644
--- a/components/invalidation/impl/sync_system_resources.cc
+++ b/components/invalidation/impl/sync_system_resources.cc
@@ -4,7 +4,6 @@
 
 #include "components/invalidation/impl/sync_system_resources.h"
 
-#include <algorithm>
 #include <cstdlib>
 #include <cstring>
 #include <memory>
@@ -133,11 +132,7 @@
 void SyncInvalidationScheduler::RunPostedTask(invalidation::Closure* task) {
   CHECK(IsRunningOnThread());
   task->Run();
-  auto it =
-      std::find_if(posted_tasks_.begin(), posted_tasks_.end(),
-                   [task](const std::unique_ptr<invalidation::Closure>& ptr) {
-                     return ptr.get() == task;
-                   });
+  auto it = posted_tasks_.find(task);
   posted_tasks_.erase(it);
 }
 
diff --git a/components/invalidation/impl/sync_system_resources.h b/components/invalidation/impl/sync_system_resources.h
index 722006a..6e517f1c 100644
--- a/components/invalidation/impl/sync_system_resources.h
+++ b/components/invalidation/impl/sync_system_resources.h
@@ -14,6 +14,7 @@
 #include <vector>
 
 #include "base/compiler_specific.h"
+#include "base/containers/unique_ptr_adapters.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/single_thread_task_runner.h"
@@ -74,7 +75,8 @@
   void RunPostedTask(invalidation::Closure* task);
 
   // Holds all posted tasks that have not yet been run.
-  std::set<std::unique_ptr<invalidation::Closure>> posted_tasks_;
+  std::set<std::unique_ptr<invalidation::Closure>, base::UniquePtrComparator>
+      posted_tasks_;
 
   scoped_refptr<base::SingleThreadTaskRunner> const created_on_task_runner_;
   bool is_started_;
diff --git a/components/password_manager/core/browser/login_database.cc b/components/password_manager/core/browser/login_database.cc
index 7cdb34d4..28a627d 100644
--- a/components/password_manager/core/browser/login_database.cc
+++ b/components/password_manager/core/browser/login_database.cc
@@ -1699,9 +1699,9 @@
       return nullptr;
     }
 
-    sync_pb::EntityMetadata entity_metadata;
-    if (entity_metadata.ParseFromString(decrypted_serialized_metadata)) {
-      metadata_batch->AddMetadata(storage_key, entity_metadata);
+    auto entity_metadata = std::make_unique<sync_pb::EntityMetadata>();
+    if (entity_metadata->ParseFromString(decrypted_serialized_metadata)) {
+      metadata_batch->AddMetadata(storage_key, std::move(entity_metadata));
     } else {
       DLOG(WARNING) << "Failed to deserialize PASSWORD model type "
                        "sync_pb::EntityMetadata.";
diff --git a/components/password_manager/core/browser/password_store.cc b/components/password_manager/core/browser/password_store.cc
index 1494ae963..0860219 100644
--- a/components/password_manager/core/browser/password_store.cc
+++ b/components/password_manager/core/browser/password_store.cc
@@ -119,7 +119,6 @@
 
 PasswordStore::PasswordStore()
     : observers_(new base::ObserverListThreadSafe<Observer>()),
-      is_propagating_password_changes_to_web_credentials_enabled_(false),
       shutdown_called_(false),
       init_status_(InitStatus::kUnknown) {}
 
@@ -872,10 +871,8 @@
 
 void PasswordStore::FindAndUpdateAffiliatedWebLogins(
     const PasswordForm& added_or_updated_android_form) {
-  if (!affiliated_match_helper_ ||
-      !is_propagating_password_changes_to_web_credentials_enabled_) {
+  if (!affiliated_match_helper_)
     return;
-  }
   affiliated_match_helper_->GetAffiliatedWebRealms(
       PasswordStore::FormDigest(added_or_updated_android_form),
       base::Bind(&PasswordStore::ScheduleUpdateAffiliatedWebLoginsImpl, this,
diff --git a/components/password_manager/core/browser/password_store.h b/components/password_manager/core/browser/password_store.h
index 4a937b16..92bbb85 100644
--- a/components/password_manager/core/browser/password_store.h
+++ b/components/password_manager/core/browser/password_store.h
@@ -122,12 +122,6 @@
     return affiliated_match_helper_.get();
   }
 
-  // Toggles whether or not to propagate password changes in Android credentials
-  // to the affiliated Web credentials.
-  void enable_propagating_password_changes_to_web_credentials(bool enabled) {
-    is_propagating_password_changes_to_web_credentials_enabled_ = enabled;
-  }
-
   // Adds the given PasswordForm to the secure password store asynchronously.
   virtual void AddLogin(const autofill::PasswordForm& form);
 
@@ -657,8 +651,6 @@
   HashPasswordManager hash_password_manager_;
 #endif
 
-  bool is_propagating_password_changes_to_web_credentials_enabled_;
-
   bool shutdown_called_;
 
   InitStatus init_status_;
diff --git a/components/password_manager/core/browser/password_store_factory_util.cc b/components/password_manager/core/browser/password_store_factory_util.cc
index be597ff..cc26face 100644
--- a/components/password_manager/core/browser/password_store_factory_util.cc
+++ b/components/password_manager/core/browser/password_store_factory_util.cc
@@ -12,7 +12,6 @@
 #include "components/password_manager/core/browser/android_affiliation/affiliation_service.h"
 #include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h"
 #include "components/password_manager/core/browser/password_manager_constants.h"
-#include "components/password_manager/core/common/password_manager_features.h"
 #include "components/sync/driver/sync_service.h"
 #include "components/sync/driver/sync_user_settings.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
@@ -22,8 +21,7 @@
 namespace {
 
 bool ShouldAffiliationBasedMatchingBeActive(syncer::SyncService* sync_service) {
-  return base::FeatureList::IsEnabled(features::kAffiliationBasedMatching) &&
-         sync_service && sync_service->IsSyncFeatureActive() &&
+  return sync_service && sync_service->IsSyncFeatureActive() &&
          sync_service->GetUserSettings()->GetChosenDataTypes().Has(
              syncer::PASSWORDS) &&
          !sync_service->GetUserSettings()->IsUsingSecondaryPassphrase();
@@ -56,9 +54,6 @@
                                 std::move(affiliation_service)));
   affiliated_match_helper->Initialize();
   password_store->SetAffiliatedMatchHelper(std::move(affiliated_match_helper));
-
-  password_store->enable_propagating_password_changes_to_web_credentials(
-      base::FeatureList::IsEnabled(features::kAffiliationBasedMatching));
 }
 
 base::FilePath GetAffiliationDatabasePath(const base::FilePath& profile_path) {
diff --git a/components/password_manager/core/browser/password_store_unittest.cc b/components/password_manager/core/browser/password_store_unittest.cc
index e344680..03a8017d 100644
--- a/components/password_manager/core/browser/password_store_unittest.cc
+++ b/components/password_manager/core/browser/password_store_unittest.cc
@@ -640,104 +640,88 @@
   const size_t kExpectedNumberOfPropagatedUpdates = 2u;
 
   const bool kFalseTrue[] = {false, true};
-  for (bool propagation_enabled : kFalseTrue) {
-    for (bool test_remove_and_add_login : kFalseTrue) {
-      SCOPED_TRACE(testing::Message("propagation_enabled: ")
-                   << propagation_enabled);
-      SCOPED_TRACE(testing::Message("test_remove_and_add_login: ")
-                   << test_remove_and_add_login);
+  for (bool test_remove_and_add_login : kFalseTrue) {
+    SCOPED_TRACE(testing::Message("test_remove_and_add_login: ")
+                 << test_remove_and_add_login);
 
-      scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
-          std::make_unique<LoginDatabase>(test_login_db_file_path())));
-      store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
-      store->RemoveLoginsCreatedBetween(base::Time(), base::Time::Max(),
-                                        base::Closure());
+    scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
+        std::make_unique<LoginDatabase>(test_login_db_file_path())));
+    store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
+    store->RemoveLoginsCreatedBetween(base::Time(), base::Time::Max(),
+                                      base::Closure());
 
-      // Set up the initial test data set.
-      std::vector<std::unique_ptr<PasswordForm>> all_credentials;
-      for (size_t i = 0; i < base::size(kTestCredentials); ++i) {
-        all_credentials.push_back(
-            FillPasswordFormWithData(kTestCredentials[i]));
-        all_credentials.back()->date_synced =
-            all_credentials.back()->date_created;
-        store->AddLogin(*all_credentials.back());
-      }
-      WaitForPasswordStore();
-
-      // The helper must be injected after the initial test data is set up,
-      // otherwise it will already start propagating updates as new Android
-      // credentials are added.
-      store->enable_propagating_password_changes_to_web_credentials(
-          propagation_enabled);
-
-      // Calculate how the correctly updated test data set should look like.
-      size_t expected_number_of_propageted_updates =
-          propagation_enabled ? kExpectedNumberOfPropagatedUpdates : 0u;
-      std::vector<std::unique_ptr<PasswordForm>>
-          expected_credentials_after_update;
-      for (size_t i = 0; i < all_credentials.size(); ++i) {
-        expected_credentials_after_update.push_back(
-            std::make_unique<PasswordForm>(*all_credentials[i]));
-        if (i < 1 + expected_number_of_propageted_updates) {
-          expected_credentials_after_update.back()->password_value =
-              base::WideToUTF16(kTestNewPassword);
-        }
-      }
-
-      if (propagation_enabled) {
-        std::vector<std::string> affiliated_web_realms;
-        affiliated_web_realms.push_back(kTestWebRealm1);
-        affiliated_web_realms.push_back(kTestWebRealm2);
-        affiliated_web_realms.push_back(kTestWebRealm3);
-        affiliated_web_realms.push_back(kTestWebRealm5);
-
-        auto mock_helper = std::make_unique<MockAffiliatedMatchHelper>();
-        mock_helper->ExpectCallToGetAffiliatedWebRealms(
-            PasswordStore::FormDigest(*expected_credentials_after_update[0]),
-            affiliated_web_realms);
-        store->SetAffiliatedMatchHelper(std::move(mock_helper));
-      }
-
-      // Explicitly update the Android credential, wait until things calm down,
-      // then query all passwords and expect that:
-      //   1.) The positive samples in |kTestCredentials| have the new password,
-      //       but the negative samples do not.
-      //   2.) Change notifications are sent about the updates. Note that as the
-      //       test interacts with the (Update|Add)LoginSync methods, only the
-      //       derived changes should trigger notifications, the first one would
-      //       normally be trigger by Sync.
-      MockPasswordStoreObserver mock_observer;
-      store->AddObserver(&mock_observer);
-      if (propagation_enabled) {
-        EXPECT_CALL(mock_observer, OnLoginsChanged(testing::SizeIs(
-                                       expected_number_of_propageted_updates)));
-      }
-      if (test_remove_and_add_login) {
-        store->ScheduleTask(
-            base::BindOnce(IgnoreResult(&PasswordStore::RemoveLoginSync), store,
-                           *all_credentials[0]));
-        store->ScheduleTask(
-            base::BindOnce(IgnoreResult(&PasswordStore::AddLoginSync), store,
-                           *expected_credentials_after_update[0]));
-      } else {
-        store->ScheduleTask(
-            base::BindOnce(IgnoreResult(&PasswordStore::UpdateLoginSync), store,
-                           *expected_credentials_after_update[0]));
-      }
-      WaitForPasswordStore();
-      store->RemoveObserver(&mock_observer);
-
-      MockPasswordStoreConsumer mock_consumer;
-      EXPECT_CALL(mock_consumer, OnGetPasswordStoreResultsConstRef(
-                                     UnorderedPasswordFormElementsAre(
-                                         &expected_credentials_after_update)));
-      store->GetAutofillableLogins(&mock_consumer);
-      WaitForPasswordStore();
-      store->ShutdownOnUIThread();
-      store = nullptr;
-      // Finish processing so that the database isn't locked next iteration.
-      WaitForPasswordStore();
+    // Set up the initial test data set.
+    std::vector<std::unique_ptr<PasswordForm>> all_credentials;
+    for (size_t i = 0; i < base::size(kTestCredentials); ++i) {
+      all_credentials.push_back(
+          FillPasswordFormWithData(kTestCredentials[i]));
+      all_credentials.back()->date_synced =
+          all_credentials.back()->date_created;
+      store->AddLogin(*all_credentials.back());
     }
+    WaitForPasswordStore();
+
+    // Calculate how the correctly updated test data set should look like.
+    std::vector<std::unique_ptr<PasswordForm>>
+        expected_credentials_after_update;
+    for (size_t i = 0; i < all_credentials.size(); ++i) {
+      expected_credentials_after_update.push_back(
+          std::make_unique<PasswordForm>(*all_credentials[i]));
+      if (i < 1 + kExpectedNumberOfPropagatedUpdates) {
+        expected_credentials_after_update.back()->password_value =
+            base::WideToUTF16(kTestNewPassword);
+      }
+    }
+
+    std::vector<std::string> affiliated_web_realms;
+    affiliated_web_realms.push_back(kTestWebRealm1);
+    affiliated_web_realms.push_back(kTestWebRealm2);
+    affiliated_web_realms.push_back(kTestWebRealm3);
+    affiliated_web_realms.push_back(kTestWebRealm5);
+
+    auto mock_helper = std::make_unique<MockAffiliatedMatchHelper>();
+    mock_helper->ExpectCallToGetAffiliatedWebRealms(
+        PasswordStore::FormDigest(*expected_credentials_after_update[0]),
+        affiliated_web_realms);
+    store->SetAffiliatedMatchHelper(std::move(mock_helper));
+
+    // Explicitly update the Android credential, wait until things calm down,
+    // then query all passwords and expect that:
+    //   1.) The positive samples in |kTestCredentials| have the new password,
+    //       but the negative samples do not.
+    //   2.) Change notifications are sent about the updates. Note that as the
+    //       test interacts with the (Update|Add)LoginSync methods, only the
+    //       derived changes should trigger notifications, the first one would
+    //       normally be trigger by Sync.
+    MockPasswordStoreObserver mock_observer;
+    store->AddObserver(&mock_observer);
+    EXPECT_CALL(mock_observer, OnLoginsChanged(testing::SizeIs(
+                                   kExpectedNumberOfPropagatedUpdates)));
+    if (test_remove_and_add_login) {
+      store->ScheduleTask(
+          base::BindOnce(IgnoreResult(&PasswordStore::RemoveLoginSync), store,
+                         *all_credentials[0]));
+      store->ScheduleTask(
+          base::BindOnce(IgnoreResult(&PasswordStore::AddLoginSync), store,
+                         *expected_credentials_after_update[0]));
+    } else {
+      store->ScheduleTask(
+          base::BindOnce(IgnoreResult(&PasswordStore::UpdateLoginSync), store,
+                         *expected_credentials_after_update[0]));
+    }
+    WaitForPasswordStore();
+    store->RemoveObserver(&mock_observer);
+
+    MockPasswordStoreConsumer mock_consumer;
+    EXPECT_CALL(mock_consumer, OnGetPasswordStoreResultsConstRef(
+                                   UnorderedPasswordFormElementsAre(
+                                       &expected_credentials_after_update)));
+    store->GetAutofillableLogins(&mock_consumer);
+    WaitForPasswordStore();
+    store->ShutdownOnUIThread();
+    store = nullptr;
+    // Finish processing so that the database isn't locked next iteration.
+    WaitForPasswordStore();
   }
 }
 
diff --git a/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc b/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc
index 8d50725..959b5e5 100644
--- a/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc
+++ b/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc
@@ -710,7 +710,8 @@
         model_type_state.set_initial_sync_done(true);
         auto metadata_batch = std::make_unique<syncer::MetadataBatch>();
         metadata_batch->SetModelTypeState(model_type_state);
-        metadata_batch->AddMetadata("storage_key", sync_pb::EntityMetadata());
+        metadata_batch->AddMetadata(
+            "storage_key", std::make_unique<sync_pb::EntityMetadata>());
         return metadata_batch;
       });
 
diff --git a/components/password_manager/core/common/password_manager_features.cc b/components/password_manager/core/common/password_manager_features.cc
index 70386e5..ae0c0622 100644
--- a/components/password_manager/core/common/password_manager_features.cc
+++ b/components/password_manager/core/common/password_manager_features.cc
@@ -10,12 +10,6 @@
 //       names, e.g. "MyGreatFeature".
 namespace features {
 
-// Enable affiliation based matching, so that credentials stored for an Android
-// application will also be considered matches for, and be filled into
-// corresponding Web applications.
-const base::Feature kAffiliationBasedMatching = {
-    "AffiliationBasedMatching", base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Enables the editing of passwords in chrome://settings/passwords, i.e. the
 // Desktop passwords settings page.
 const base::Feature kEditPasswordsInDesktopSettings = {
diff --git a/components/password_manager/core/common/password_manager_features.h b/components/password_manager/core/common/password_manager_features.h
index 5b0ecc6..6d21b498 100644
--- a/components/password_manager/core/common/password_manager_features.h
+++ b/components/password_manager/core/common/password_manager_features.h
@@ -17,7 +17,6 @@
 // All features in alphabetical order. The features should be documented
 // alongside the definition of their values in the .cc file.
 
-extern const base::Feature kAffiliationBasedMatching;
 extern const base::Feature kEditPasswordsInDesktopSettings;
 extern const base::Feature kDeleteCorruptedPasswords;
 extern const base::Feature kPasswordGenerationRequirementsDomainOverrides;
diff --git a/components/payments/content/payment_request.cc b/components/payments/content/payment_request.cc
index b37be61a..3ae1a62 100644
--- a/components/payments/content/payment_request.cc
+++ b/components/payments/content/payment_request.cc
@@ -164,7 +164,7 @@
           spec_->url_payment_method_identifiers().end());
 }
 
-void PaymentRequest::Show(bool is_user_gesture, bool wait_for_updated_details) {
+void PaymentRequest::Show(bool is_user_gesture) {
   if (!IsInitialized()) {
     log_.Error("Attempted show without initialization");
     OnConnectionTerminated();
@@ -207,14 +207,8 @@
 
   is_show_user_gesture_ = is_user_gesture;
 
-  if (wait_for_updated_details) {
-    // Put |spec_| into uninitialized state, so the UI knows to show a spinner.
-    // This method does not block.
-    spec_->StartWaitingForUpdateWith(
-        PaymentRequestSpec::UpdateReason::INITIAL_PAYMENT_DETAILS);
-  }
-
   display_handle_->Show(this);
+
   state_->AreRequestedMethodsSupported(
       base::BindOnce(&PaymentRequest::AreRequestedMethodsSupportedCallback,
                      weak_ptr_factory_.GetWeakPtr()));
@@ -259,13 +253,6 @@
     return;
   }
 
-  bool is_resolving_promise_passed_into_show_method = !spec_->IsInitialized();
-  if (is_resolving_promise_passed_into_show_method && !details->total) {
-    log_.Error("Missing total");
-    OnConnectionTerminated();
-    return;
-  }
-
   std::string error;
   if (!ValidatePaymentDetails(ConvertPaymentDetails(details), &error)) {
     log_.Error(error);
@@ -282,15 +269,6 @@
   }
 
   spec_->UpdateWith(std::move(details));
-
-  if (is_resolving_promise_passed_into_show_method) {
-    if (SatisfiesSkipUIConstraints()) {
-      skipped_payment_request_ui_ = true;
-      Pay();
-    } else if (spec_->request_shipping()) {
-      state_->SelectDefaultShippingAddressAndNotifyObservers();
-    }
-  }
 }
 
 void PaymentRequest::NoUpdatedPaymentDetails() {
@@ -447,17 +425,16 @@
 }
 
 bool PaymentRequest::SatisfiesSkipUIConstraints() const {
-  // Only allowing URL base payment apps to skip the payment sheet.
-  return (spec()->url_payment_method_identifiers().size() == 1 ||
-          skip_ui_for_non_url_payment_method_identifiers_for_test_) &&
-         base::FeatureList::IsEnabled(features::kWebPaymentsSingleAppUiSkip) &&
+  return base::FeatureList::IsEnabled(features::kWebPaymentsSingleAppUiSkip) &&
          base::FeatureList::IsEnabled(::features::kServiceWorkerPaymentApps) &&
-         is_show_user_gesture_ && state()->IsInitialized() &&
-         spec()->IsInitialized() &&
+         is_show_user_gesture_ && state()->is_get_all_instruments_finished() &&
          state()->available_instruments().size() == 1 &&
          spec()->stringified_method_data().size() == 1 &&
          !spec()->request_shipping() && !spec()->request_payer_name() &&
-         !spec()->request_payer_phone() && !spec()->request_payer_email();
+         !spec()->request_payer_phone() &&
+         !spec()->request_payer_email()
+         // Only allowing URL base payment apps to skip the payment sheet.
+         && spec()->url_payment_method_identifiers().size() == 1;
 }
 
 void PaymentRequest::OnPaymentResponseAvailable(
diff --git a/components/payments/content/payment_request.h b/components/payments/content/payment_request.h
index 4394b82..ef4236b 100644
--- a/components/payments/content/payment_request.h
+++ b/components/payments/content/payment_request.h
@@ -68,7 +68,7 @@
             std::vector<mojom::PaymentMethodDataPtr> method_data,
             mojom::PaymentDetailsPtr details,
             mojom::PaymentOptionsPtr options) override;
-  void Show(bool is_user_gesture, bool wait_for_updated_details) override;
+  void Show(bool is_user_gesture) override;
   void Retry(mojom::PaymentValidationErrorsPtr errors) override;
   void UpdateWith(mojom::PaymentDetailsPtr details) override;
   void NoUpdatedPaymentDetails() override;
@@ -122,12 +122,6 @@
   PaymentRequestSpec* spec() const { return spec_.get(); }
   PaymentRequestState* state() const { return state_.get(); }
 
-  // Allow to skip UI into payment handlers for such payment methods as
-  // "basic-card". Used only in tests.
-  void set_skip_ui_for_non_url_payment_method_identifiers_for_test() {
-    skip_ui_for_non_url_payment_method_identifiers_for_test_ = true;
-  }
-
  private:
   // Returns true after init() has been called and the mojo connection has been
   // established. If the mojo connection gets later disconnected, this will
@@ -211,11 +205,6 @@
   // Whether PaymentRequest.show() has been called.
   bool is_show_called_ = false;
 
-  // Whether payment instruments for such payment methods as "basic-card" can
-  // skip UI for testing of the skip-UI flow. This is always false in
-  // production.
-  bool skip_ui_for_non_url_payment_method_identifiers_for_test_ = false;
-
   base::WeakPtrFactory<PaymentRequest> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(PaymentRequest);
diff --git a/components/payments/content/payment_request_spec.cc b/components/payments/content/payment_request_spec.cc
index 3c083ba..00e8ff7 100644
--- a/components/payments/content/payment_request_spec.cc
+++ b/components/payments/content/payment_request_spec.cc
@@ -100,7 +100,6 @@
 
 void PaymentRequestSpec::UpdateWith(mojom::PaymentDetailsPtr details) {
   DCHECK(details_);
-  DCHECK(details_->total || details->total);
   if (details->total)
     details_->total = std::move(details->total);
   if (!details->display_items.empty())
@@ -215,15 +214,9 @@
 
 void PaymentRequestSpec::RecomputeSpecForDetails() {
   // Reparse the |details_| and update the observers.
-  bool is_initialization =
-      current_update_reason_ == UpdateReason::INITIAL_PAYMENT_DETAILS;
-  UpdateSelectedShippingOption(/*after_update=*/!is_initialization);
+  UpdateSelectedShippingOption(/*after_update=*/true);
 
   NotifyOnSpecUpdated();
-
-  if (is_initialization)
-    NotifyInitialized();
-
   current_update_reason_ = UpdateReason::NONE;
 }
 
@@ -236,10 +229,6 @@
   observers_.RemoveObserver(observer);
 }
 
-bool PaymentRequestSpec::IsInitialized() const {
-  return current_update_reason_ != UpdateReason::INITIAL_PAYMENT_DETAILS;
-}
-
 bool PaymentRequestSpec::request_shipping() const {
   return options_->request_shipping;
 }
@@ -376,7 +365,7 @@
   selected_shipping_option_ = nullptr;
   selected_shipping_option_error_.clear();
   if (details_->shipping_options->empty() || !details_->error.empty()) {
-    // The merchant provided either no shipping options or an error message.
+    // No options are provided by the merchant.
     if (after_update) {
       // This is after an update, which means that the selected address is not
       // supported. The merchant may have customized the error string, or a
diff --git a/components/payments/content/payment_request_spec.h b/components/payments/content/payment_request_spec.h
index a81d0ce..1ebea6c 100644
--- a/components/payments/content/payment_request_spec.h
+++ b/components/payments/content/payment_request_spec.h
@@ -15,7 +15,6 @@
 #include "base/strings/string16.h"
 #include "components/autofill/core/browser/credit_card.h"
 #include "components/autofill/core/browser/field_types.h"
-#include "components/payments/content/initialization_task.h"
 #include "components/payments/core/currency_formatter.h"
 #include "components/payments/core/payment_options_provider.h"
 #include "third_party/blink/public/mojom/payments/payment_request.mojom.h"
@@ -34,22 +33,12 @@
 // The spec contains all the options that the merchant has specified about this
 // Payment Request. It's a (mostly) read-only view, which can be updated in
 // certain occasions by the merchant (see API).
-//
-// The spec starts out completely initialized when a PaymentRequest object is
-// created, but can be placed into uninitialized state if PaymentRequest.show()
-// was called with a promise. This allows for asynchronous calculation of the
-// shopping cart contents, the total, the shipping options, and the modifiers.
-//
-// The initialization state is observed by PaymentRequestDialogView for showing
-// a "Loading..." spinner.
-class PaymentRequestSpec : public PaymentOptionsProvider,
-                           public InitializationTask {
+class PaymentRequestSpec : public PaymentOptionsProvider {
  public:
   // This enum represents which bit of information was changed to trigger an
   // update roundtrip with the website.
   enum class UpdateReason {
     NONE,
-    INITIAL_PAYMENT_DETAILS,
     SHIPPING_OPTION,
     SHIPPING_ADDRESS,
     RETRY,
@@ -115,9 +104,6 @@
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* observer);
 
-  // InitializationTask:
-  bool IsInitialized() const override;
-
   // PaymentOptionsProvider:
   bool request_shipping() const override;
   bool request_payer_name() const override;
@@ -172,11 +158,7 @@
     return selected_shipping_option_error_;
   }
 
-  // Notifies observers that spec is going to be updated due to |reason|. This
-  // shows a spinner in UI that goes away when merchant calls updateWith() or
-  // ignores the shipping*change event.
   void StartWaitingForUpdateWith(UpdateReason reason);
-
   bool IsMixedCurrency() const;
 
   UpdateReason current_update_reason() const { return current_update_reason_; }
@@ -206,9 +188,8 @@
 
   // Updates the |selected_shipping_option| based on the data passed to this
   // payment request by the website. This will set selected_shipping_option_ to
-  // the last option marked selected in the options array. If merchants provides
-  // no options or an error message this method is called |after_update| (after
-  // user changed their shipping address selection), it means the merchant
+  // the last option marked selected in the options array. If no options are
+  // provided and this method is called |after_update|, it means the merchant
   // doesn't ship to this location. In this case,
   // |selected_shipping_option_error_| will be set.
   void UpdateSelectedShippingOption(bool after_update);
diff --git a/components/payments/content/payment_request_spec_unittest.cc b/components/payments/content/payment_request_spec_unittest.cc
index 58a9dd1..609e7d2 100644
--- a/components/payments/content/payment_request_spec_unittest.cc
+++ b/components/payments/content/payment_request_spec_unittest.cc
@@ -32,8 +32,6 @@
 
   void RecreateSpecWithOptionsAndDetails(mojom::PaymentOptionsPtr options,
                                          mojom::PaymentDetailsPtr details) {
-    if (!details->total)
-      details->total = mojom::PaymentItem::New();
     spec_ = std::make_unique<PaymentRequestSpec>(
         std::move(options), std::move(details),
         std::vector<mojom::PaymentMethodDataPtr>(), this, "en-US");
diff --git a/components/payments/content/payment_request_state.cc b/components/payments/content/payment_request_state.cc
index 93a39e0..c86818e9 100644
--- a/components/payments/content/payment_request_state.cc
+++ b/components/payments/content/payment_request_state.cc
@@ -147,7 +147,6 @@
   get_all_instruments_finished_ = true;
   are_requested_methods_supported_ |= !available_instruments_.empty();
   NotifyOnGetAllPaymentInstrumentsFinished();
-  NotifyInitialized();
 
   // Fulfill the pending CanMakePayment call.
   if (can_make_payment_callback_) {
@@ -458,18 +457,6 @@
   return get_all_instruments_finished_;
 }
 
-void PaymentRequestState::SelectDefaultShippingAddressAndNotifyObservers() {
-  // Only pre-select an address if the merchant provided at least one selected
-  // shipping option, and the top profile is complete. Assumes that profiles
-  // have already been sorted for completeness and frecency.
-  if (!shipping_profiles().empty() && spec_->selected_shipping_option() &&
-      profile_comparator()->IsShippingComplete(shipping_profiles_[0])) {
-    selected_shipping_profile_ = shipping_profiles()[0];
-  }
-
-  UpdateIsReadyToPayAndNotifyObservers();
-}
-
 void PaymentRequestState::PopulateProfileCache() {
   std::vector<autofill::AutofillProfile*> profiles =
       personal_data_manager_->GetProfilesToSuggest();
@@ -524,6 +511,14 @@
 }
 
 void PaymentRequestState::SetDefaultProfileSelections() {
+  // Only pre-select an address if the merchant provided at least one selected
+  // shipping option, and the top profile is complete. Assumes that profiles
+  // have already been sorted for completeness and frecency.
+  if (!shipping_profiles().empty() && spec_->selected_shipping_option() &&
+      profile_comparator()->IsShippingComplete(shipping_profiles_[0])) {
+    selected_shipping_profile_ = shipping_profiles()[0];
+  }
+
   // Contact profiles were ordered by completeness in addition to frecency;
   // the first one is the best default selection.
   if (!contact_profiles().empty() &&
@@ -544,8 +539,7 @@
   selected_instrument_ = first_complete_instrument == instruments.end()
                              ? nullptr
                              : first_complete_instrument->get();
-
-  SelectDefaultShippingAddressAndNotifyObservers();
+  UpdateIsReadyToPayAndNotifyObservers();
 
   bool has_complete_instrument =
       available_instruments().empty()
@@ -566,6 +560,7 @@
 void PaymentRequestState::NotifyOnGetAllPaymentInstrumentsFinished() {
   for (auto& observer : observers_)
     observer.OnGetAllPaymentInstrumentsFinished();
+  NotifyInitialized();
 }
 
 void PaymentRequestState::NotifyOnSelectedInformationChanged() {
diff --git a/components/payments/content/payment_request_state.h b/components/payments/content/payment_request_state.h
index 60c83e81..cc9dadfb 100644
--- a/components/payments/content/payment_request_state.h
+++ b/components/payments/content/payment_request_state.h
@@ -39,9 +39,6 @@
 // user is ready to pay. Uses information from the PaymentRequestSpec, which is
 // what the merchant has specified, as input into the "is ready to pay"
 // computation.
-//
-// The initialization state is observed by PaymentRequestDialogView for showing
-// a "Loading..." spinner.
 class PaymentRequestState : public PaymentResponseHelper::Delegate,
                             public PaymentRequestSpec::Observer,
                             public InitializationTask {
@@ -227,9 +224,6 @@
   // InitializationTask:
   bool IsInitialized() const override;
 
-  // Selects the default shipping address.
-  void SelectDefaultShippingAddressAndNotifyObservers();
-
  private:
   // Fetches the Autofill Profiles for this user from the PersonalDataManager,
   // and stores copies of them, owned by this PaymentRequestState, in
diff --git a/components/payments/content/payment_request_state_unittest.cc b/components/payments/content/payment_request_state_unittest.cc
index 99c24be..e53508b 100644
--- a/components/payments/content/payment_request_state_unittest.cc
+++ b/components/payments/content/payment_request_state_unittest.cc
@@ -68,8 +68,6 @@
       mojom::PaymentOptionsPtr options,
       mojom::PaymentDetailsPtr details,
       std::vector<mojom::PaymentMethodDataPtr> method_data) {
-    if (!details->total)
-      details->total = mojom::PaymentItem::New();
     // The spec will be based on the |options| and |details| passed in.
     spec_ = std::make_unique<PaymentRequestSpec>(
         std::move(options), std::move(details), std::move(method_data),
diff --git a/components/quirks/quirks_manager.cc b/components/quirks/quirks_manager.cc
index ff4c2c4..e013ce80 100644
--- a/components/quirks/quirks_manager.cc
+++ b/components/quirks/quirks_manager.cc
@@ -143,10 +143,7 @@
 void QuirksManager::ClientFinished(QuirksClient* client) {
   DCHECK(thread_checker_.CalledOnValidThread());
   SetLastServerCheck(client->product_id(), base::Time::Now());
-  auto it = std::find_if(clients_.begin(), clients_.end(),
-                         [client](const std::unique_ptr<QuirksClient>& c) {
-                           return c.get() == client;
-                         });
+  auto it = clients_.find(client);
   CHECK(it != clients_.end());
   clients_.erase(it);
 }
diff --git a/components/quirks/quirks_manager.h b/components/quirks/quirks_manager.h
index aafd3f4..551888be 100644
--- a/components/quirks/quirks_manager.h
+++ b/components/quirks/quirks_manager.h
@@ -9,6 +9,7 @@
 #include <set>
 
 #include "base/callback.h"
+#include "base/containers/unique_ptr_adapters.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
@@ -120,7 +121,7 @@
   void SetLastServerCheck(int64_t product_id, const base::Time& last_check);
 
   // Set of active clients, each created to download a different Quirks file.
-  std::set<std::unique_ptr<QuirksClient>> clients_;
+  std::set<std::unique_ptr<QuirksClient>, base::UniquePtrComparator> clients_;
 
   // Don't start downloads before first session login.
   bool waiting_for_login_;
diff --git a/components/safe_browsing/ping_manager.cc b/components/safe_browsing/ping_manager.cc
index 80c81740..61191af 100644
--- a/components/safe_browsing/ping_manager.cc
+++ b/components/safe_browsing/ping_manager.cc
@@ -92,11 +92,7 @@
 void PingManager::OnURLLoaderComplete(
     network::SimpleURLLoader* source,
     std::unique_ptr<std::string> response_body) {
-  auto it = std::find_if(
-      safebrowsing_reports_.begin(), safebrowsing_reports_.end(),
-      [source](const std::unique_ptr<network::SimpleURLLoader>& ptr) {
-        return ptr.get() == source;
-      });
+  auto it = safebrowsing_reports_.find(source);
   DCHECK(it != safebrowsing_reports_.end());
   safebrowsing_reports_.erase(it);
 }
diff --git a/components/safe_browsing/ping_manager.h b/components/safe_browsing/ping_manager.h
index f9c5202..b3c87a47 100644
--- a/components/safe_browsing/ping_manager.h
+++ b/components/safe_browsing/ping_manager.h
@@ -12,6 +12,7 @@
 #include <string>
 #include <vector>
 
+#include "base/containers/unique_ptr_adapters.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -63,7 +64,8 @@
 
   const V4ProtocolConfig config_;
 
-  typedef std::set<std::unique_ptr<network::SimpleURLLoader>> Reports;
+  using Reports = std::set<std::unique_ptr<network::SimpleURLLoader>,
+                           base::UniquePtrComparator>;
 
   // Generates URL for reporting safe browsing hits.
   GURL SafeBrowsingHitUrl(const safe_browsing::HitReport& hit_report) const;
diff --git a/components/signin/core/browser/signin_manager.h b/components/signin/core/browser/signin_manager.h
index d4a0b78..5efd7f4 100644
--- a/components/signin/core/browser/signin_manager.h
+++ b/components/signin/core/browser/signin_manager.h
@@ -112,9 +112,11 @@
   // up the corresponding account_id and gaia_id for this email.
   void SignIn(const std::string& username);
 
-  // Returns whether sign-in is allowed.
-  // TODO(crbug.com/806778): Remove method in super-class.
-  bool IsSigninAllowed() const override;
+  // Returns true if a signin to Chrome is allowed (by policy or pref).
+  // TODO(crbug.com/806778): this method should not be used externally,
+  // instead the value of the kSigninAllowed preference should be checked.
+  // Once all external code has been modified, this method will be removed.
+  bool IsSigninAllowed() const;
 
   // Sets whether sign-in is allowed or not.
   void SetSigninAllowed(bool allowed);
diff --git a/components/signin/core/browser/signin_manager_base.cc b/components/signin/core/browser/signin_manager_base.cc
index b3210dea..e4af936 100644
--- a/components/signin/core/browser/signin_manager_base.cc
+++ b/components/signin/core/browser/signin_manager_base.cc
@@ -160,10 +160,6 @@
   return initialized_;
 }
 
-bool SigninManagerBase::IsSigninAllowed() const {
-  return client_->GetPrefs()->GetBoolean(prefs::kSigninAllowed);
-}
-
 AccountInfo SigninManagerBase::GetAuthenticatedAccountInfo() const {
   return account_tracker_service_->GetAccountInfo(GetAuthenticatedAccountId());
 }
diff --git a/components/signin/core/browser/signin_manager_base.h b/components/signin/core/browser/signin_manager_base.h
index 234d1de..6d04878c 100644
--- a/components/signin/core/browser/signin_manager_base.h
+++ b/components/signin/core/browser/signin_manager_base.h
@@ -90,12 +90,6 @@
   void Initialize(PrefService* local_state);
   bool IsInitialized() const;
 
-  // Returns true if a signin to Chrome is allowed (by policy or pref).
-  // TODO(crbug.com/806778): this method should not be used externally,
-  // instead the value of the kSigninAllowed preference should be checked.
-  // Once all external code has been modified, this method will be removed.
-  virtual bool IsSigninAllowed() const;
-
   // If a user has previously signed in (and has not signed out), this returns
   // the know information of the account. Otherwise, it returns an empty struct.
   AccountInfo GetAuthenticatedAccountInfo() const;
diff --git a/components/sync/base/pref_names.cc b/components/sync/base/pref_names.cc
index 647b3c47..2cfb8ad 100644
--- a/components/sync/base/pref_names.cc
+++ b/components/sync/base/pref_names.cc
@@ -88,12 +88,6 @@
 const char kSyncKeystoreEncryptionBootstrapToken[] =
     "sync.keystore_encryption_bootstrap_token";
 
-#if defined(OS_CHROMEOS)
-// A string that is used to store first-time sync startup after once sync is
-// disabled. This will be refreshed every sign-in.
-const char kSyncSpareBootstrapToken[] = "sync.spare_bootstrap_token";
-#endif  // defined(OS_CHROMEOS)
-
 const char kSyncCacheGuid[] = "sync.cache_guid";
 const char kSyncBirthday[] = "sync.birthday";
 const char kSyncBagOfChips[] = "sync.bag_of_chips";
diff --git a/components/sync/base/pref_names.h b/components/sync/base/pref_names.h
index 838c5b7..ebd8c299 100644
--- a/components/sync/base/pref_names.h
+++ b/components/sync/base/pref_names.h
@@ -67,10 +67,6 @@
 extern const char kSyncBirthday[];
 extern const char kSyncBagOfChips[];
 
-#if defined(OS_CHROMEOS)
-extern const char kSyncSpareBootstrapToken[];
-#endif  // defined(OS_CHROMEOS)
-
 extern const char kSyncPassphrasePrompted[];
 
 extern const char kSyncMemoryPressureWarningCount[];
diff --git a/components/sync/base/sync_prefs.cc b/components/sync/base/sync_prefs.cc
index 3d1d6df1..d74fe83 100644
--- a/components/sync/base/sync_prefs.cc
+++ b/components/sync/base/sync_prefs.cc
@@ -36,6 +36,11 @@
 // Obsolete pref that used to store long poll intervals received by the server.
 const char kSyncLongPollIntervalSeconds[] = "sync.long_poll_interval";
 
+#if defined(OS_CHROMEOS)
+// Obsolete pref.
+const char kSyncSpareBootstrapToken[] = "sync.spare_bootstrap_token";
+#endif  // defined(OS_CHROMEOS)
+
 // Groups of prefs that always have the same value as a "master" pref.
 // For example, the APPS group has {APP_LIST, APP_SETTINGS}
 // (as well as APPS, but that is implied), so
@@ -166,10 +171,6 @@
                                std::string());
   registry->RegisterStringPref(prefs::kSyncKeystoreEncryptionBootstrapToken,
                                std::string());
-#if defined(OS_CHROMEOS)
-  // TODO(crbug.com/938869): Remove this pref.
-  registry->RegisterStringPref(prefs::kSyncSpareBootstrapToken, "");
-#endif
   registry->RegisterBooleanPref(prefs::kSyncPassphrasePrompted, false);
   registry->RegisterIntegerPref(prefs::kSyncMemoryPressureWarningCount, -1);
   registry->RegisterBooleanPref(prefs::kSyncShutdownCleanly, false);
@@ -187,6 +188,9 @@
   registry->RegisterBooleanPref(kSyncHasAuthError, false);
   registry->RegisterInt64Pref(kSyncFirstSyncTime, 0);
   registry->RegisterInt64Pref(kSyncLongPollIntervalSeconds, 0);
+#if defined(OS_CHROMEOS)
+  registry->RegisterStringPref(kSyncSpareBootstrapToken, "");
+#endif
 }
 
 void SyncPrefs::AddSyncPrefObserver(SyncPrefObserver* sync_pref_observer) {
@@ -436,18 +440,6 @@
   return nullptr;
 }
 
-#if defined(OS_CHROMEOS)
-std::string SyncPrefs::GetSpareBootstrapToken() const {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  return pref_service_->GetString(prefs::kSyncSpareBootstrapToken);
-}
-
-void SyncPrefs::SetSpareBootstrapToken(const std::string& token) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  pref_service_->SetString(prefs::kSyncSpareBootstrapToken, token);
-}
-#endif
-
 void SyncPrefs::OnSyncManagedPrefChanged() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   for (SyncPrefObserver& observer : sync_pref_observers_)
@@ -643,4 +635,10 @@
   pref_service->ClearPref(kSyncLongPollIntervalSeconds);
 }
 
+#if defined(OS_CHROMEOS)
+void ClearObsoleteSyncSpareBootstrapToken(PrefService* pref_service) {
+  pref_service->ClearPref(kSyncSpareBootstrapToken);
+}
+#endif  // defined(OS_CHROMEOS)
+
 }  // namespace syncer
diff --git a/components/sync/base/sync_prefs.h b/components/sync/base/sync_prefs.h
index 0207cee..b3c5d05 100644
--- a/components/sync/base/sync_prefs.h
+++ b/components/sync/base/sync_prefs.h
@@ -142,13 +142,6 @@
   // Maps |type| to its corresponding preference name.
   static const char* GetPrefNameForDataType(ModelType type);
 
-#if defined(OS_CHROMEOS)
-  // Use this spare bootstrap token only when setting up sync for the first
-  // time.
-  std::string GetSpareBootstrapToken() const;
-  void SetSpareBootstrapToken(const std::string& token);
-#endif
-
   // Copy of various fields historically owned and persisted by the Directory.
   // This is a future-proof approach to ultimately replace the Directory once
   // most users have populated prefs and the Directory is about to be removed.
@@ -238,6 +231,9 @@
 void ClearObsoleteAuthErrorPrefs(PrefService* pref_service);
 void ClearObsoleteFirstSyncTime(PrefService* pref_service);
 void ClearObsoleteSyncLongPollIntervalSeconds(PrefService* pref_service);
+#if defined(OS_CHROMEOS)
+void ClearObsoleteSyncSpareBootstrapToken(PrefService* pref_service);
+#endif  // defined(OS_CHROMEOS)
 
 }  // namespace syncer
 
diff --git a/components/sync/driver/glue/sync_engine_impl_unittest.cc b/components/sync/driver/glue/sync_engine_impl_unittest.cc
index 3bc151977..94758fac 100644
--- a/components/sync/driver/glue/sync_engine_impl_unittest.cc
+++ b/components/sync/driver/glue/sync_engine_impl_unittest.cc
@@ -207,7 +207,7 @@
         temp_dir_.GetPath().Append(base::FilePath(kTestSyncDir)));
     credentials_.account_id = "user@example.com";
     credentials_.email = "user@example.com";
-    credentials_.sync_token = "sync_token";
+    credentials_.access_token = "access_token";
 
     fake_manager_factory_ = std::make_unique<FakeSyncManagerFactory>(
         &fake_manager_, network::TestNetworkConnectionTracker::GetInstance());
diff --git a/components/sync/driver/profile_sync_service.cc b/components/sync/driver/profile_sync_service.cc
index 12ec1095..9395e0a8 100644
--- a/components/sync/driver/profile_sync_service.cc
+++ b/components/sync/driver/profile_sync_service.cc
@@ -208,14 +208,6 @@
   if (identity_manager_)
     identity_manager_->AddObserver(this);
 
-#if defined(OS_CHROMEOS)
-  std::string bootstrap_token = sync_prefs_.GetEncryptionBootstrapToken();
-  if (bootstrap_token.empty()) {
-    sync_prefs_.SetEncryptionBootstrapToken(
-        sync_prefs_.GetSpareBootstrapToken());
-  }
-#endif
-
   memory_pressure_listener_ = std::make_unique<base::MemoryPressureListener>(
       base::BindRepeating(&ProfileSyncService::OnMemoryPressure,
                           sync_enabled_weak_factory_.GetWeakPtr()));
@@ -359,7 +351,7 @@
   } else {
     // If the engine already exists, just propagate the new credentials.
     SyncCredentials credentials = auth_manager_->GetCredentials();
-    if (credentials.sync_token.empty()) {
+    if (credentials.access_token.empty()) {
       engine_->InvalidateCredentials();
     } else {
       engine_->UpdateCredentials(credentials);
diff --git a/components/sync/driver/profile_sync_service_unittest.cc b/components/sync/driver/profile_sync_service_unittest.cc
index f6511b6..5cfe535 100644
--- a/components/sync/driver/profile_sync_service_unittest.cc
+++ b/components/sync/driver/profile_sync_service_unittest.cc
@@ -605,7 +605,7 @@
   // Make sure the expected credentials (correct account_id, empty access token)
   // were passed to the SyncEngine.
   ASSERT_EQ(primary_account_id, init_credentials.account_id);
-  ASSERT_TRUE(init_credentials.sync_token.empty());
+  ASSERT_TRUE(init_credentials.access_token.empty());
 
   // At this point, the real SyncEngine would try to connect to the server, fail
   // (because it has no access token), and eventually call
@@ -653,7 +653,7 @@
   // Make sure the expected credentials (correct account_id, empty access token)
   // were passed to the SyncEngine.
   ASSERT_EQ(primary_account_id, init_credentials.account_id);
-  ASSERT_TRUE(init_credentials.sync_token.empty());
+  ASSERT_TRUE(init_credentials.access_token.empty());
 
   // At this point, the real SyncEngine would try to connect to the server, fail
   // (because it has no access token), and eventually call
@@ -719,7 +719,7 @@
   // Make sure the expected credentials (correct account_id, empty access token)
   // were passed to the SyncEngine.
   ASSERT_EQ(primary_account_id, init_credentials.account_id);
-  ASSERT_TRUE(init_credentials.sync_token.empty());
+  ASSERT_TRUE(init_credentials.access_token.empty());
 
   // At this point, the real SyncEngine would try to connect to the server, fail
   // (because it has no access token), and eventually call
@@ -776,7 +776,7 @@
   // Make sure the expected credentials (correct account_id, empty access token)
   // were passed to the SyncEngine.
   ASSERT_EQ(primary_account_id, init_credentials.account_id);
-  ASSERT_TRUE(init_credentials.sync_token.empty());
+  ASSERT_TRUE(init_credentials.access_token.empty());
 
   // At this point, the real SyncEngine would try to connect to the server, fail
   // (because it has no access token), and eventually call
@@ -871,7 +871,7 @@
   // Make sure the expected credentials (correct account_id, empty access token)
   // were passed to the SyncEngine.
   ASSERT_EQ(primary_account_id, init_credentials.account_id);
-  ASSERT_TRUE(init_credentials.sync_token.empty());
+  ASSERT_TRUE(init_credentials.access_token.empty());
 
   TestSyncServiceObserver observer;
   service()->AddObserver(&observer);
@@ -934,7 +934,7 @@
   // Make sure the expected credentials (correct account_id, empty access token)
   // were passed to the SyncEngine.
   ASSERT_EQ(primary_account_id, init_credentials.account_id);
-  ASSERT_TRUE(init_credentials.sync_token.empty());
+  ASSERT_TRUE(init_credentials.access_token.empty());
 
   TestSyncServiceObserver observer;
   service()->AddObserver(&observer);
diff --git a/components/sync/driver/sync_auth_manager.cc b/components/sync/driver/sync_auth_manager.cc
index 2580b1a0..f7542b8 100644
--- a/components/sync/driver/sync_auth_manager.cc
+++ b/components/sync/driver/sync_auth_manager.cc
@@ -128,7 +128,7 @@
   syncer::SyncCredentials credentials;
   credentials.account_id = account_info.account_id;
   credentials.email = account_info.email;
-  credentials.sync_token = access_token_;
+  credentials.access_token = access_token_;
 
   return credentials;
 }
diff --git a/components/sync/driver/sync_auth_manager_unittest.cc b/components/sync/driver/sync_auth_manager_unittest.cc
index fc564a35..504e3be2 100644
--- a/components/sync/driver/sync_auth_manager_unittest.cc
+++ b/components/sync/driver/sync_auth_manager_unittest.cc
@@ -65,7 +65,7 @@
   syncer::SyncCredentials credentials = auth_manager->GetCredentials();
   EXPECT_TRUE(credentials.account_id.empty());
   EXPECT_TRUE(credentials.email.empty());
-  EXPECT_TRUE(credentials.sync_token.empty());
+  EXPECT_TRUE(credentials.access_token.empty());
   EXPECT_TRUE(auth_manager->access_token().empty());
   // Note: Calling RegisterForAuthNotifications is illegal in local Sync mode,
   // so we don't test that.
@@ -219,25 +219,25 @@
   EXPECT_CALL(credentials_changed, Run());
   identity_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
       "access_token", base::Time::Now() + base::TimeDelta::FromHours(1));
-  ASSERT_EQ(auth_manager->GetCredentials().sync_token, "access_token");
+  ASSERT_EQ(auth_manager->GetCredentials().access_token, "access_token");
 
   // Now the refresh token gets updated. The access token will get dropped, so
   // this should cause another notification.
   EXPECT_CALL(credentials_changed, Run());
   identity_env()->SetRefreshTokenForPrimaryAccount();
-  ASSERT_TRUE(auth_manager->GetCredentials().sync_token.empty());
+  ASSERT_TRUE(auth_manager->GetCredentials().access_token.empty());
 
   // Once a new token is available, there's another notification.
   EXPECT_CALL(credentials_changed, Run());
   identity_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
       "access_token_2", base::Time::Now() + base::TimeDelta::FromHours(1));
-  ASSERT_EQ(auth_manager->GetCredentials().sync_token, "access_token_2");
+  ASSERT_EQ(auth_manager->GetCredentials().access_token, "access_token_2");
 
   // Revoking the refresh token should also cause the access token to get
   // dropped.
   EXPECT_CALL(credentials_changed, Run());
   identity_env()->RemoveRefreshTokenForPrimaryAccount();
-  EXPECT_TRUE(auth_manager->GetCredentials().sync_token.empty());
+  EXPECT_TRUE(auth_manager->GetCredentials().access_token.empty());
 }
 
 TEST_F(SyncAuthManagerTest, RequestsAccessTokenOnSyncStartup) {
@@ -257,7 +257,7 @@
   identity_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
       "access_token", base::Time::Now() + base::TimeDelta::FromHours(1));
 
-  EXPECT_EQ(auth_manager->GetCredentials().sync_token, "access_token");
+  EXPECT_EQ(auth_manager->GetCredentials().access_token, "access_token");
 }
 
 TEST_F(SyncAuthManagerTest,
@@ -326,7 +326,7 @@
   auth_manager->ConnectionStatusChanged(syncer::CONNECTION_AUTH_ERROR);
   identity_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
       "access_token", base::Time::Now() + base::TimeDelta::FromHours(1));
-  ASSERT_EQ(auth_manager->GetCredentials().sync_token, "access_token");
+  ASSERT_EQ(auth_manager->GetCredentials().access_token, "access_token");
 
   // But now the server is still returning AUTH_ERROR - maybe something's wrong
   // with the token.
@@ -354,7 +354,7 @@
   auth_manager->ConnectionStatusChanged(syncer::CONNECTION_AUTH_ERROR);
   identity_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
       "access_token", base::Time::Now() + base::TimeDelta::FromHours(1));
-  ASSERT_EQ(auth_manager->GetCredentials().sync_token, "access_token");
+  ASSERT_EQ(auth_manager->GetCredentials().access_token, "access_token");
 
   // Now a server error happens.
   auth_manager->ConnectionStatusChanged(syncer::CONNECTION_SERVER_ERROR);
@@ -364,7 +364,7 @@
             GoogleServiceAuthError::AuthErrorNone());
   // But the access token should still be there - this might just be some
   // non-auth-related problem with the server.
-  EXPECT_EQ(auth_manager->GetCredentials().sync_token, "access_token");
+  EXPECT_EQ(auth_manager->GetCredentials().access_token, "access_token");
 }
 
 TEST_F(SyncAuthManagerTest, ClearsServerErrorOnSyncDisable) {
@@ -382,7 +382,7 @@
   auth_manager->ConnectionStatusChanged(syncer::CONNECTION_AUTH_ERROR);
   identity_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
       "access_token", base::Time::Now() + base::TimeDelta::FromHours(1));
-  ASSERT_EQ(auth_manager->GetCredentials().sync_token, "access_token");
+  ASSERT_EQ(auth_manager->GetCredentials().access_token, "access_token");
 
   // A server error happens.
   auth_manager->ConnectionStatusChanged(syncer::CONNECTION_SERVER_ERROR);
@@ -413,11 +413,11 @@
   auth_manager->ConnectionStatusChanged(syncer::CONNECTION_AUTH_ERROR);
   identity_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
       "access_token", base::Time::Now() + base::TimeDelta::FromHours(1));
-  ASSERT_EQ(auth_manager->GetCredentials().sync_token, "access_token");
+  ASSERT_EQ(auth_manager->GetCredentials().access_token, "access_token");
 
   // Now everything is okay for a while.
   auth_manager->ConnectionStatusChanged(syncer::CONNECTION_OK);
-  ASSERT_EQ(auth_manager->GetCredentials().sync_token, "access_token");
+  ASSERT_EQ(auth_manager->GetCredentials().access_token, "access_token");
   ASSERT_EQ(auth_manager->GetLastAuthError(),
             GoogleServiceAuthError::AuthErrorNone());
 
@@ -425,11 +425,11 @@
   auth_manager->ConnectionStatusChanged(syncer::CONNECTION_AUTH_ERROR);
 
   // Should immediately drop the access token and fetch a new one (no backoff).
-  EXPECT_TRUE(auth_manager->GetCredentials().sync_token.empty());
+  EXPECT_TRUE(auth_manager->GetCredentials().access_token.empty());
 
   identity_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
       "access_token_2", base::Time::Now() + base::TimeDelta::FromHours(1));
-  EXPECT_EQ(auth_manager->GetCredentials().sync_token, "access_token_2");
+  EXPECT_EQ(auth_manager->GetCredentials().access_token, "access_token_2");
 }
 
 TEST_F(SyncAuthManagerTest, RequestsNewAccessTokenOnRefreshTokenUpdate) {
@@ -447,11 +447,11 @@
   auth_manager->ConnectionStatusChanged(syncer::CONNECTION_AUTH_ERROR);
   identity_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
       "access_token", base::Time::Now() + base::TimeDelta::FromHours(1));
-  ASSERT_EQ(auth_manager->GetCredentials().sync_token, "access_token");
+  ASSERT_EQ(auth_manager->GetCredentials().access_token, "access_token");
 
   // Now everything is okay for a while.
   auth_manager->ConnectionStatusChanged(syncer::CONNECTION_OK);
-  ASSERT_EQ(auth_manager->GetCredentials().sync_token, "access_token");
+  ASSERT_EQ(auth_manager->GetCredentials().access_token, "access_token");
   ASSERT_EQ(auth_manager->GetLastAuthError(),
             GoogleServiceAuthError::AuthErrorNone());
 
@@ -459,11 +459,11 @@
   identity_env()->SetRefreshTokenForPrimaryAccount();
 
   // Should immediately drop the access token and fetch a new one (no backoff).
-  EXPECT_TRUE(auth_manager->GetCredentials().sync_token.empty());
+  EXPECT_TRUE(auth_manager->GetCredentials().access_token.empty());
 
   identity_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
       "access_token_2", base::Time::Now() + base::TimeDelta::FromHours(1));
-  EXPECT_EQ(auth_manager->GetCredentials().sync_token, "access_token_2");
+  EXPECT_EQ(auth_manager->GetCredentials().access_token, "access_token_2");
 }
 
 TEST_F(SyncAuthManagerTest, DoesNotRequestAccessTokenAutonomously) {
@@ -490,7 +490,7 @@
   // posted tasks, we have to spin the message loop.
   base::RunLoop().RunUntilIdle();
 
-  EXPECT_TRUE(auth_manager->GetCredentials().sync_token.empty());
+  EXPECT_TRUE(auth_manager->GetCredentials().access_token.empty());
 }
 
 TEST_F(SyncAuthManagerTest, ClearsCredentialsOnRefreshTokenRemoval) {
@@ -508,11 +508,11 @@
   auth_manager->ConnectionStatusChanged(syncer::CONNECTION_AUTH_ERROR);
   identity_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
       "access_token", base::Time::Now() + base::TimeDelta::FromHours(1));
-  ASSERT_EQ(auth_manager->GetCredentials().sync_token, "access_token");
+  ASSERT_EQ(auth_manager->GetCredentials().access_token, "access_token");
 
   // Now everything is okay for a while.
   auth_manager->ConnectionStatusChanged(syncer::CONNECTION_OK);
-  ASSERT_EQ(auth_manager->GetCredentials().sync_token, "access_token");
+  ASSERT_EQ(auth_manager->GetCredentials().access_token, "access_token");
   ASSERT_EQ(auth_manager->GetLastAuthError(),
             GoogleServiceAuthError::AuthErrorNone());
 
@@ -525,7 +525,7 @@
   identity_env()->RemoveRefreshTokenForPrimaryAccount();
 
   // Should immediately drop the access token and expose an auth error.
-  EXPECT_TRUE(auth_manager->GetCredentials().sync_token.empty());
+  EXPECT_TRUE(auth_manager->GetCredentials().access_token.empty());
   EXPECT_NE(auth_manager->GetLastAuthError(),
             GoogleServiceAuthError::AuthErrorNone());
 
@@ -549,11 +549,11 @@
   auth_manager->ConnectionStatusChanged(syncer::CONNECTION_AUTH_ERROR);
   identity_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
       "access_token", base::Time::Now() + base::TimeDelta::FromHours(1));
-  ASSERT_EQ(auth_manager->GetCredentials().sync_token, "access_token");
+  ASSERT_EQ(auth_manager->GetCredentials().access_token, "access_token");
 
   // Now everything is okay for a while.
   auth_manager->ConnectionStatusChanged(syncer::CONNECTION_OK);
-  ASSERT_EQ(auth_manager->GetCredentials().sync_token, "access_token");
+  ASSERT_EQ(auth_manager->GetCredentials().access_token, "access_token");
   ASSERT_EQ(auth_manager->GetLastAuthError(),
             GoogleServiceAuthError::AuthErrorNone());
 
@@ -566,7 +566,7 @@
   identity_env()->SetInvalidRefreshTokenForPrimaryAccount();
 
   // Should immediately drop the access token and expose a special auth error.
-  EXPECT_TRUE(auth_manager->GetCredentials().sync_token.empty());
+  EXPECT_TRUE(auth_manager->GetCredentials().access_token.empty());
   GoogleServiceAuthError invalid_token_error =
       GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
           GoogleServiceAuthError::InvalidGaiaCredentialsReason::
diff --git a/components/sync/engine/sync_credentials.h b/components/sync/engine/sync_credentials.h
index 16b2672..2ab1830 100644
--- a/components/sync/engine/sync_credentials.h
+++ b/components/sync/engine/sync_credentials.h
@@ -21,8 +21,8 @@
   // The email associated with this account.
   std::string email;
 
-  // The raw authentication token's bytes.
-  std::string sync_token;
+  // The OAuth2 access token.
+  std::string access_token;
 };
 
 }  // namespace syncer
diff --git a/components/sync/engine_impl/sync_manager_impl.cc b/components/sync/engine_impl/sync_manager_impl.cc
index 093e6ae..174b8f19 100644
--- a/components/sync/engine_impl/sync_manager_impl.cc
+++ b/components/sync/engine_impl/sync_manager_impl.cc
@@ -308,8 +308,8 @@
   share_.sync_credentials = args->credentials;
 
   // UserShare is accessible to a lot of code that doesn't need access to the
-  // sync token so clear sync_token from the UserShare.
-  share_.sync_credentials.sync_token = "";
+  // access token, so clear it from the UserShare.
+  share_.sync_credentials.access_token = "";
 
   DVLOG(1) << "Username: " << args->credentials.email;
   DVLOG(1) << "AccountId: " << args->credentials.account_id;
@@ -538,7 +538,7 @@
   cycle_context_->set_account_name(credentials.email);
 
   observing_network_connectivity_changes_ = true;
-  if (!connection_manager_->SetAuthToken(credentials.sync_token))
+  if (!connection_manager_->SetAuthToken(credentials.access_token))
     return;  // Auth token is known to be invalid, so exit early.
 
   scheduler_->OnCredentialsUpdated();
diff --git a/components/sync/engine_impl/sync_manager_impl_unittest.cc b/components/sync/engine_impl/sync_manager_impl_unittest.cc
index 3938634..4ab7522d 100644
--- a/components/sync/engine_impl/sync_manager_impl_unittest.cc
+++ b/components/sync/engine_impl/sync_manager_impl_unittest.cc
@@ -936,7 +936,7 @@
     SyncCredentials credentials;
     credentials.account_id = "foo@bar.com";
     credentials.email = "foo@bar.com";
-    credentials.sync_token = "sometoken";
+    credentials.access_token = "sometoken";
 
     sync_manager_.AddObserver(&manager_observer_);
     EXPECT_CALL(manager_observer_, OnInitializationComplete(_, _, _, _))
diff --git a/components/sync/model/fake_model_type_sync_bridge.cc b/components/sync/model/fake_model_type_sync_bridge.cc
index 860a127..a96c6a61 100644
--- a/components/sync/model/fake_model_type_sync_bridge.cc
+++ b/components/sync/model/fake_model_type_sync_bridge.cc
@@ -146,10 +146,11 @@
 
 std::unique_ptr<MetadataBatch>
 FakeModelTypeSyncBridge::Store::CreateMetadataBatch() const {
-  std::unique_ptr<MetadataBatch> metadata_batch(new MetadataBatch());
+  auto metadata_batch = std::make_unique<MetadataBatch>();
   metadata_batch->SetModelTypeState(model_type_state_);
   for (const auto& kv : metadata_store_) {
-    metadata_batch->AddMetadata(kv.first, kv.second);
+    metadata_batch->AddMetadata(
+        kv.first, std::make_unique<sync_pb::EntityMetadata>(kv.second));
   }
   return metadata_batch;
 }
@@ -380,7 +381,7 @@
 
 std::unique_ptr<EntityData> FakeModelTypeSyncBridge::CopyEntityData(
     const EntityData& old_data) {
-  std::unique_ptr<EntityData> new_data(new EntityData());
+  auto new_data = std::make_unique<EntityData>();
   new_data->id = old_data.id;
   new_data->client_tag_hash = old_data.client_tag_hash;
   new_data->non_unique_name = old_data.non_unique_name;
diff --git a/components/sync/model/metadata_batch.cc b/components/sync/model/metadata_batch.cc
index 35c6b9b..7645723b 100644
--- a/components/sync/model/metadata_batch.cc
+++ b/components/sync/model/metadata_batch.cc
@@ -4,6 +4,7 @@
 
 #include "components/sync/model/metadata_batch.h"
 
+#include <memory>
 #include <utility>
 
 namespace syncer {
@@ -25,10 +26,12 @@
   return std::move(metadata_map_);
 }
 
-void MetadataBatch::AddMetadata(const std::string& storage_key,
-                                const sync_pb::EntityMetadata& metadata) {
-  // TODO(crbug.com/914396): protos are movable. avoid unnecessary copy here.
-  metadata_map_.insert(std::make_pair(storage_key, metadata));
+void MetadataBatch::AddMetadata(
+    const std::string& storage_key,
+    std::unique_ptr<sync_pb::EntityMetadata> metadata) {
+  // TODO(crbug.com/914396): change metadata_map_ type to avoid unnecessary copy
+  // here.
+  metadata_map_.insert(std::make_pair(storage_key, *metadata));
 }
 
 const sync_pb::ModelTypeState& MetadataBatch::GetModelTypeState() const {
diff --git a/components/sync/model/metadata_batch.h b/components/sync/model/metadata_batch.h
index 8e8c2f0..ee6a650 100644
--- a/components/sync/model/metadata_batch.h
+++ b/components/sync/model/metadata_batch.h
@@ -6,6 +6,7 @@
 #define COMPONENTS_SYNC_MODEL_METADATA_BATCH_H_
 
 #include <map>
+#include <memory>
 #include <string>
 
 #include "components/sync/protocol/entity_metadata.pb.h"
@@ -35,7 +36,7 @@
 
   // Add |metadata| for |storage_key| to the batch.
   void AddMetadata(const std::string& storage_key,
-                   const sync_pb::EntityMetadata& metadata);
+                   std::unique_ptr<sync_pb::EntityMetadata> metadata);
 
   // Get the ModelTypeState for this batch.
   const sync_pb::ModelTypeState& GetModelTypeState() const;
diff --git a/components/sync/model_impl/blocking_model_type_store_impl.cc b/components/sync/model_impl/blocking_model_type_store_impl.cc
index 5bc511c8..32ddbd78 100644
--- a/components/sync/model_impl/blocking_model_type_store_impl.cc
+++ b/components/sync/model_impl/blocking_model_type_store_impl.cc
@@ -217,11 +217,11 @@
   }
 
   for (const Record& r : metadata_records) {
-    sync_pb::EntityMetadata entity_metadata;
-    if (!entity_metadata.ParseFromString(r.value)) {
+    auto entity_metadata = std::make_unique<sync_pb::EntityMetadata>();
+    if (!entity_metadata->ParseFromString(r.value)) {
       return ModelError(FROM_HERE, "Failed to deserialize entity metadata.");
     }
-    metadata_batch->AddMetadata(r.id, entity_metadata);
+    metadata_batch->AddMetadata(r.id, std::move(entity_metadata));
   }
 
   return base::nullopt;
diff --git a/components/test/data/payments/show_promise/app.js b/components/test/data/payments/show_promise/app.js
deleted file mode 100644
index cec6d41..0000000
--- a/components/test/data/payments/show_promise/app.js
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * 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.
- */
-
-self.addEventListener('paymentrequest', (evt) => {
-  evt.respondWith({methodName: 'basic-card', details: evt.total});
-});
diff --git a/components/test/data/payments/show_promise/app_installer.js b/components/test/data/payments/show_promise/app_installer.js
deleted file mode 100644
index ae296caf..0000000
--- a/components/test/data/payments/show_promise/app_installer.js
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * 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.
- */
-
-/**
- * Prints output.
- * @param {String} src - Where the message is coming from.
- * @param {String} txt - The text to print.
- */
-function output(src, txt) {
-  // Handle DOMException:
-  if (txt.message) {
-    txt = txt.message;
-  }
-  txt = src + ': ' + txt;
-  if (window.domAutomationController) {
-    window.domAutomationController.send(txt);
-  } else {
-    txt += ' window.domAutomationController not found.';
-  }
-  console.log(txt);
-}
-
-/**
- * Installs the payment handler.
- */
-function install() {  // eslint-disable-line no-unused-vars
-  if (!navigator.serviceWorker) {
-    output('install()', 'ServiceWorker API not found.');
-    return;
-  }
-
-  navigator.serviceWorker.getRegistration('app.js')
-      .then((registration) => {
-        if (registration) {
-          output(
-              'serviceWorker.getRegistration()',
-              'The ServiceWorker is already installed.');
-          return;
-        }
-        navigator.serviceWorker.register('app.js')
-            .then(() => {
-              return navigator.serviceWorker.ready;
-            })
-            .then((registration) => {
-              if (!registration.paymentManager) {
-                output(
-                    'serviceWorker.register()',
-                    'PaymentManager API not found.');
-                return;
-              }
-
-              registration.paymentManager.instruments
-                  .set('123456', {name: 'Echo Pay', method: 'basic-card'})
-                  .then(() => {
-                    output(
-                        'instruments.set()',
-                        'Payment handler installed.');
-                  })
-                  .catch((error) => {
-                    output('instruments.set()', error);
-                  });
-            })
-            .catch((error) => {
-              output('serviceWorker.register()', error);
-            });
-      })
-      .catch((error) => {
-        output('serviceWorker.getRegistration()', error);
-      });
-}
diff --git a/components/test/data/payments/show_promise/digital_goods.html b/components/test/data/payments/show_promise/digital_goods.html
deleted file mode 100644
index 4c79a59..0000000
--- a/components/test/data/payments/show_promise/digital_goods.html
+++ /dev/null
@@ -1,22 +0,0 @@
-<!doctype html>
-<!--
-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.
--->
-<html lang="en">
-<head>
-  <meta charset="utf-8">
-  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1"> 
-  <title>Show Promise Test For Digital Goods</title>
-  <link rel="stylesheet" type="text/css" href="../style.css">
-</head>
-<body>
-  <div><button onclick="create()" id="create">Create</button></div>
-  <div><button onclick="buy()" id="buy">Buy</button></div>
-  <pre id="result"></pre>
-  <script src="../util.js"></script>
-  <script src="app_installer.js"></script>
-  <script src="digital_goods.js"></script>
-</body>
-</html>
\ No newline at end of file
diff --git a/components/test/data/payments/show_promise/digital_goods.js b/components/test/data/payments/show_promise/digital_goods.js
deleted file mode 100644
index d5e76bd5..0000000
--- a/components/test/data/payments/show_promise/digital_goods.js
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.
- */
-
-var request = null;
-
-/**
- * Create an instance of PaymentRequest.
- */
-function create() {  // eslint-disable-line no-unused-vars
-  try {
-    request = new PaymentRequest([{supportedMethods: 'basic-card'}], {
-      total:
-          {label: 'PENDING TOTAL', amount: {currency: 'USD', value: '99.99'}},
-    });
-  } catch (error) {
-    print(error.message);
-  }
-}
-
-/**
- * Launch PaymentRequest with a show promise for digital goods.
- */
-function buy() {  // eslint-disable-line no-unused-vars
-  try {
-    request
-        .show(new Promise(function(resolve) {
-          resolve({
-            total: {label: 'Total', amount: {currency: 'USD', value: '1.00'}},
-          });
-        }))
-        .then(function(result) {
-          print(JSON.stringify(result.details));
-          return result.complete('success');
-        })
-        .catch(function(error) {
-          print(error);
-        });
-  } catch (error) {
-    print(error);
-  }
-}
diff --git a/components/test/data/payments/show_promise/invalid_details.html b/components/test/data/payments/show_promise/invalid_details.html
deleted file mode 100644
index beaaf898..0000000
--- a/components/test/data/payments/show_promise/invalid_details.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!doctype html>
-<!--
-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.
--->
-<html lang="en">
-<head>
-  <meta charset="utf-8">
-  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1"> 
-  <title>Test for Show Promise with Invalid Details</title>
-  <link rel="stylesheet" type="text/css" href="../style.css">
-</head>
-<body>
-  <div><button onclick="buy()" id="buy">Buy</button></div>
-  <pre id="result"></pre>
-  <script src="../util.js"></script>
-  <script src="invalid_details.js"></script>
-</body>
-</html>
\ No newline at end of file
diff --git a/components/test/data/payments/show_promise/invalid_details.js b/components/test/data/payments/show_promise/invalid_details.js
deleted file mode 100644
index f760a258..0000000
--- a/components/test/data/payments/show_promise/invalid_details.js
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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.
- */
-
-/**
- * Launch PaymentRequest with a show promise that resolve with invalid details.
- */
-function buy() {  // eslint-disable-line no-unused-vars
-  try {
-    new PaymentRequest([{supportedMethods: 'basic-card'}], {
-      total: {
-        label: 'PENDING TOTAL',
-        amount: {currency: 'USD', value: '99.99'},
-      },
-    })
-        .show(new Promise(function(resolve) {
-          resolve({
-            total: {
-              label: 'Total',
-              amount: {currency: 'USD', value: '-1.00'},
-            },
-          });
-        }))
-        .catch(function(error) {
-          print(error);
-        });
-  } catch (error) {
-    print(error.message);
-  }
-}
diff --git a/components/test/data/payments/show_promise/reject.html b/components/test/data/payments/show_promise/reject.html
deleted file mode 100644
index 82b1343..0000000
--- a/components/test/data/payments/show_promise/reject.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!doctype html>
-<!--
-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.
--->
-<html lang="en">
-<head>
-  <meta charset="utf-8">
-  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1"> 
-  <title>Test for Rejecting the Show Promise</title>
-  <link rel="stylesheet" type="text/css" href="../style.css">
-</head>
-<body>
-  <div><button onclick="buy()" id="buy">Buy</button></div>
-  <pre id="result"></pre>
-  <script src="../util.js"></script>
-  <script src="reject.js"></script>
-</body>
-</html>
\ No newline at end of file
diff --git a/components/test/data/payments/show_promise/reject.js b/components/test/data/payments/show_promise/reject.js
deleted file mode 100644
index 8630c7fc..0000000
--- a/components/test/data/payments/show_promise/reject.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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.
- */
-
-/**
- * Launch PaymentRequest with a show promise and reject that promise.
- */
-function buy() {  // eslint-disable-line no-unused-vars
-  try {
-    new PaymentRequest(
-        [{supportedMethods: 'basic-card'}],
-        {total: {label: 'Total', amount: {currency: 'USD', value: '1.00'}}})
-        .show(new Promise(function(resolve, reject) {
-          reject();
-        }))
-        .catch(function(error) {
-          print(error);
-        });
-  } catch (error) {
-    print(error);
-  }
-}
diff --git a/components/test/data/payments/show_promise/single_option_shipping.html b/components/test/data/payments/show_promise/single_option_shipping.html
deleted file mode 100644
index 17e1736c..0000000
--- a/components/test/data/payments/show_promise/single_option_shipping.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!doctype html>
-<!--
-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.
--->
-<html lang="en">
-<head>
-  <meta charset="utf-8">
-  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1"> 
-  <title>Show Promise Test For Single-Option Shipping</title>
-  <link rel="stylesheet" type="text/css" href="../style.css">
-</head>
-<body>
-  <div><button onclick="buy()" id="buy">Buy</button></div>
-  <pre id="result"></pre>
-  <script src="../util.js"></script>
-  <script src="app_installer.js"></script>
-  <script src="single_option_shipping.js"></script>
-</body>
-</html>
\ No newline at end of file
diff --git a/components/test/data/payments/show_promise/single_option_shipping.js b/components/test/data/payments/show_promise/single_option_shipping.js
deleted file mode 100644
index b29a9238..0000000
--- a/components/test/data/payments/show_promise/single_option_shipping.js
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.
- */
-
-/**
- * Launch PaymentRequest with a show promise and a single pre-selected option
- * for shipping worldwide.
- */
-function buy() {  // eslint-disable-line no-unused-vars
-  try {
-    new PaymentRequest(
-        [{supportedMethods: 'basic-card'}], {
-          total: {
-            label: 'PENDING TOTAL',
-            amount: {currency: 'USD', value: '99.99'},
-          },
-          shippingOptions: [{
-            id: '1',
-            label: 'PENDING SHIPPING',
-            amount: {currency: 'USD', value: '99.99'},
-            selected: true,
-          }],
-        },
-        {requestShipping: true})
-        .show(new Promise(function(resolve) {
-          resolve({
-            total: {label: 'Total', amount: {currency: 'USD', value: '1.00'}},
-            shippingOptions: [{
-              id: '1',
-              label: 'Free shipping',
-              amount: {currency: 'USD', value: '0.00'},
-              selected: true,
-            }],
-          });
-        }))
-        .then(function(result) {
-          print(JSON.stringify(result.details));
-          return result.complete('success');
-        })
-        .catch(function(error) {
-          print(error);
-        });
-  } catch (error) {
-    print(error.message);
-  }
-}
diff --git a/components/test/data/payments/show_promise/single_option_shipping_with_update.html b/components/test/data/payments/show_promise/single_option_shipping_with_update.html
deleted file mode 100644
index c1a1e64..0000000
--- a/components/test/data/payments/show_promise/single_option_shipping_with_update.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!doctype html>
-<!--
-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.
--->
-<html lang="en">
-<head>
-  <meta charset="utf-8">
-  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1"> 
-  <title>Show Promise Test For Single-Option Shipping With Update</title>
-  <link rel="stylesheet" type="text/css" href="../style.css">
-</head>
-<body>
-  <div><button onclick="buy()" id="buy">Buy</button></div>
-  <pre id="result"></pre>
-  <script src="../util.js"></script>
-  <script src="app_installer.js"></script>
-  <script src="single_option_shipping_with_update.js"></script>
-</body>
-</html>
\ No newline at end of file
diff --git a/components/test/data/payments/show_promise/single_option_shipping_with_update.js b/components/test/data/payments/show_promise/single_option_shipping_with_update.js
deleted file mode 100644
index a3c1be0..0000000
--- a/components/test/data/payments/show_promise/single_option_shipping_with_update.js
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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.
- */
-
-/**
- * Launch PaymentRequest with a show promise and a single pre-selected option
- * for shipping worldwide and a handler for shipping address change events that
- * does not change anything.
- */
-function buy() {  // eslint-disable-line no-unused-vars
-  var finalizedDetails = {
-    total: {label: 'Total', amount: {currency: 'USD', value: '1.00'}},
-    shippingOptions: [{
-      id: '1',
-      label: 'Free shipping',
-      amount: {currency: 'USD', value: '0.00'},
-      selected: true,
-    }],
-  };
-
-  try {
-    var request = new PaymentRequest(
-        [{supportedMethods: 'basic-card'}], {
-          total: {
-            label: 'PENDING TOTAL',
-            amount: {currency: 'USD', value: '99.99'},
-          },
-          shippingOptions: [{
-            id: '1',
-            label: 'PENDING SHIPPING',
-            amount: {currency: 'USD', value: '99.99'},
-            selected: true,
-          }],
-        },
-        {requestShipping: true});
-
-    request.addEventListener('shippingaddresschange', function(evt) {
-      evt.updateWith(finalizedDetails);
-    });
-
-    request
-        .show(new Promise(function(resolve) {
-          resolve(finalizedDetails);
-        }))
-        .then(function(result) {
-          print(JSON.stringify(result.details));
-          return result.complete('success');
-        })
-        .catch(function(error) {
-          print(error);
-        });
-  } catch (error) {
-    print(error.message);
-  }
-}
diff --git a/components/test/data/payments/show_promise/timeout.html b/components/test/data/payments/show_promise/timeout.html
deleted file mode 100644
index 7f29206..0000000
--- a/components/test/data/payments/show_promise/timeout.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!doctype html>
-<!--
-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.
--->
-<html lang="en">
-<head>
-  <meta charset="utf-8">
-  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1"> 
-  <title>Test for Timing Out the Show Promise</title>
-  <link rel="stylesheet" type="text/css" href="../style.css">
-</head>
-<body>
-  <div><button onclick="buy()" id="buy">Buy</button></div>
-  <pre id="result"></pre>
-  <script src="../util.js"></script>
-  <script src="timeout.js"></script>
-</body>
-</html>
\ No newline at end of file
diff --git a/components/test/data/payments/show_promise/timeout.js b/components/test/data/payments/show_promise/timeout.js
deleted file mode 100644
index 3bb80fe..0000000
--- a/components/test/data/payments/show_promise/timeout.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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.
- */
-
-/**
- * Launch PaymentRequest with a show promise and don't resolve or reject it.
- */
-function buy() {  // eslint-disable-line no-unused-vars
-  try {
-    new PaymentRequest(
-        [{supportedMethods: 'basic-card'}],
-        {total: {label: 'Total', amount: {currency: 'USD', value: '1.00'}}})
-        .show(new Promise(function(resolve) { /* Intentionally empty. */ }))
-        .catch(function(error) {
-          print(error);
-        });
-  } catch (error) {
-    print(error);
-  }
-}
diff --git a/components/test/data/payments/show_promise/unsupported.html b/components/test/data/payments/show_promise/unsupported.html
deleted file mode 100644
index e3b00fe9..0000000
--- a/components/test/data/payments/show_promise/unsupported.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!doctype html>
-<!--
-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.
--->
-<html lang="en">
-<head>
-  <meta charset="utf-8">
-  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1"> 
-  <title>Test for Show Promise with Unsupported Payment Method Identifier</title>
-  <link rel="stylesheet" type="text/css" href="../style.css">
-</head>
-<body>
-  <div><button onclick="buy()" id="buy">Buy</button></div>
-  <pre id="result"></pre>
-  <script src="../util.js"></script>
-  <script src="unsupported.js"></script>
-</body>
-</html>
\ No newline at end of file
diff --git a/components/test/data/payments/show_promise/unsupported.js b/components/test/data/payments/show_promise/unsupported.js
deleted file mode 100644
index 6196ee22..0000000
--- a/components/test/data/payments/show_promise/unsupported.js
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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.
- */
-
-/**
- * Launch PaymentRequest with a show promise and an unsupported payment method
- * identifier.
- */
-function buy() {  // eslint-disable-line no-unused-vars
-  try {
-    new PaymentRequest([{supportedMethods: 'foo'}], {
-      total:
-          {label: 'PENDING TOTAL', amount: {currency: 'USD', value: '99.99'}},
-    })
-        .show(new Promise(function(resolve) {
-          resolve({
-            total: {
-              label: 'Total',
-              amount: {currency: 'USD', value: '1.00'},
-            },
-          });
-        }))
-        .catch(function(error) {
-          print(error);
-        });
-  } catch (error) {
-    print(error);
-  }
-}
diff --git a/components/test/data/payments/show_promise/us_only_shipping.html b/components/test/data/payments/show_promise/us_only_shipping.html
deleted file mode 100644
index d5af7ae..0000000
--- a/components/test/data/payments/show_promise/us_only_shipping.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!doctype html>
-<!--
-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.
--->
-<html lang="en">
-<head>
-  <meta charset="utf-8">
-  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1"> 
-  <title>Show Promise Test For US-Only Shipping</title>
-  <link rel="stylesheet" type="text/css" href="../style.css">
-</head>
-<body>
-  <div><button onclick="buy()" id="buy">Buy</button></div>
-  <pre id="result"></pre>
-  <script src="../util.js"></script>
-  <script src="app_installer.js"></script>
-  <script src="us_only_shipping.js"></script>
-</body>
-</html>
\ No newline at end of file
diff --git a/components/test/data/payments/show_promise/us_only_shipping.js b/components/test/data/payments/show_promise/us_only_shipping.js
deleted file mode 100644
index af8480f..0000000
--- a/components/test/data/payments/show_promise/us_only_shipping.js
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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.
- */
-
-/**
- * Launch PaymentRequest with a show promise and US-only shipping.
- */
-function buy() {  // eslint-disable-line no-unused-vars
-  var detailsForUSAddress = {
-    shippingOptions: [{
-      id: '1',
-      label: 'Free shipping',
-      amount: {currency: 'USD', value: '0.00'},
-      selected: true,
-    }],
-  };
-
-  var detailsForNonUSAddress = {error: 'Cannot ship outside of US.'};
-
-  try {
-    var request = new PaymentRequest(
-        [{supportedMethods: 'basic-card'}], {
-          total: {
-            label: 'PENDING TOTAL',
-            amount: {currency: 'USD', value: '99.99'},
-          },
-        },
-        {requestShipping: true});
-
-    request.addEventListener('shippingaddresschange', function(evt) {
-      if (request.shippingAddress.country === 'US') {
-        evt.updateWith(detailsForUSAddress);
-      } else {
-        evt.updateWith(detailsForNonUSAddress);
-      }
-    });
-
-    request
-        .show(new Promise(function(resolve) {
-          resolve({
-            total: {label: 'Total', amount: {currency: 'USD', value: '1.00'}},
-          });
-        }))
-        .then(function(result) {
-          print(JSON.stringify(result.details));
-          return result.complete('success');
-        })
-        .catch(function(error) {
-          print(error);
-        });
-  } catch (error) {
-    print(error.message);
-  }
-}
diff --git a/content/browser/renderer_host/frame_connector_delegate.cc b/content/browser/renderer_host/frame_connector_delegate.cc
index c0d82a9..39f910a 100644
--- a/content/browser/renderer_host/frame_connector_delegate.cc
+++ b/content/browser/renderer_host/frame_connector_delegate.cc
@@ -48,9 +48,7 @@
   render_widget_host->SetAutoResize(visual_properties.auto_resize_enabled,
                                     visual_properties.min_size_for_auto_resize,
                                     visual_properties.max_size_for_auto_resize);
-  render_widget_host->SetPageScaleState(
-      visual_properties.page_scale_factor,
-      visual_properties.is_pinch_gesture_active);
+  render_widget_host->SetPageScaleFactor(visual_properties.page_scale_factor);
 
   render_widget_host->SynchronizeVisualProperties();
 }
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index edfc500c..c9a555e7 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -422,7 +422,6 @@
       visual_properties_ack_pending_(false),
       auto_resize_enabled_(false),
       page_scale_factor_(1.f),
-      is_pinch_gesture_active_(false),
       waiting_for_screen_rects_ack_(false),
       is_unresponsive_(false),
       in_flight_event_count_(0),
@@ -899,7 +898,6 @@
   visual_properties->max_size_for_auto_resize = max_size_for_auto_resize_;
 
   visual_properties->page_scale_factor = page_scale_factor_;
-  visual_properties->is_pinch_gesture_active = is_pinch_gesture_active_;
 
   if (view_) {
     visual_properties->new_size = view_->GetRequestedRendererSize();
@@ -986,9 +984,7 @@
       old_visual_properties_->capture_sequence_number !=
           visual_properties->capture_sequence_number ||
       old_visual_properties_->page_scale_factor !=
-          visual_properties->page_scale_factor ||
-      old_visual_properties_->is_pinch_gesture_active !=
-          visual_properties->is_pinch_gesture_active;
+          visual_properties->page_scale_factor;
 
   // We should throttle sending updated VisualProperties to the renderer to
   // the rate of commit. This ensures we don't overwhelm the renderer with
@@ -2169,10 +2165,8 @@
   max_size_for_auto_resize_ = max_size;
 }
 
-void RenderWidgetHostImpl::SetPageScaleState(float page_scale_factor,
-                                             bool is_pinch_gesture_active) {
+void RenderWidgetHostImpl::SetPageScaleFactor(float page_scale_factor) {
   page_scale_factor_ = page_scale_factor;
-  is_pinch_gesture_active_ = is_pinch_gesture_active;
 }
 
 void RenderWidgetHostImpl::Destroy(bool also_delete) {
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index 02e16b3f..5264464 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -562,8 +562,8 @@
                      const gfx::Size& min_size,
                      const gfx::Size& max_size);
 
-  // Allows the main frame's page scale state to be tracked.
-  void SetPageScaleState(float page_scale_factor, bool is_pinch_gesture_active);
+  // Allows the main frame's page scale factor to be tracked.
+  void SetPageScaleFactor(float page_scale_factor);
 
   // Fills in the |visual_properties| struct.
   // Returns |false| if the update is redundant, |true| otherwise.
@@ -1018,8 +1018,6 @@
 
   // The page-scale factor of the main-frame.
   float page_scale_factor_;
-  // True when the renderer is currently undergoing a pinch-zoom gesture.
-  bool is_pinch_gesture_active_;
 
   bool waiting_for_screen_rects_ack_;
   gfx::Rect last_view_screen_rect_;
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index bbc5c8d..e870f17 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -10880,17 +10880,6 @@
   RenderFrameSubmissionObserver observer_c(child_c);
   RenderFrameSubmissionObserver observer_d(child_d);
 
-  // Monitor visual sync messages coming from the mainframe to make sure
-  // |is_pinch_gesture_active| goes true during the pinch gesture.
-  scoped_refptr<SynchronizeVisualPropertiesMessageFilter> filter_mainframe =
-      new SynchronizeVisualPropertiesMessageFilter();
-  root->current_frame_host()->GetProcess()->AddFilter(filter_mainframe.get());
-  // Monitor frame sync messages coming from child_b as it will need to
-  // relay them to child_d.
-  scoped_refptr<SynchronizeVisualPropertiesMessageFilter> filter_child_b =
-      new SynchronizeVisualPropertiesMessageFilter();
-  child_b->current_frame_host()->GetProcess()->AddFilter(filter_child_b.get());
-
   // We need to observe a root frame submission to pick up the initial page
   // scale factor.
   observer_a.WaitForAnyFrameSubmission();
@@ -10934,17 +10923,6 @@
   observer_b.WaitForExternalPageScaleFactor(target_page_scale, kScaleTolerance);
   observer_c.WaitForExternalPageScaleFactor(target_page_scale, kScaleTolerance);
   observer_d.WaitForExternalPageScaleFactor(target_page_scale, kScaleTolerance);
-
-  // The change in |is_pinch_gesture_active| that signals the end of the pinch
-  // gesture will occur sometime after the ack for GesturePinchEnd, so we need
-  // to wait for it from each renderer. If it's never seen, the test fails by
-  // timing out.
-  filter_mainframe->WaitForPinchGestureEnd();
-  EXPECT_TRUE(filter_mainframe->pinch_gesture_active_set());
-  EXPECT_TRUE(filter_mainframe->pinch_gesture_active_cleared());
-  filter_child_b->WaitForPinchGestureEnd();
-  EXPECT_TRUE(filter_child_b->pinch_gesture_active_set());
-  EXPECT_TRUE(filter_child_b->pinch_gesture_active_cleared());
 }
 
 // Verify that sandbox flags specified by a CSP header are properly inherited by
diff --git a/content/browser/speech/speech_recognizer_impl.cc b/content/browser/speech/speech_recognizer_impl.cc
index e915ff1..1801ff9 100644
--- a/content/browser/speech/speech_recognizer_impl.cc
+++ b/content/browser/speech/speech_recognizer_impl.cc
@@ -109,12 +109,6 @@
 
 }  // namespace
 
-const int SpeechRecognizerImpl::kAudioSampleRate = 16000;
-const ChannelLayout SpeechRecognizerImpl::kChannelLayout =
-    media::CHANNEL_LAYOUT_MONO;
-const int SpeechRecognizerImpl::kNumBitsPerAudioSample = 16;
-const int SpeechRecognizerImpl::kNoSpeechTimeoutMs = 8000;
-const int SpeechRecognizerImpl::kEndpointerEstimationTimeMs = 300;
 media::AudioSystem* SpeechRecognizerImpl::audio_system_for_tests_ = nullptr;
 media::AudioCapturerSource*
     SpeechRecognizerImpl::audio_capturer_source_for_tests_ = nullptr;
diff --git a/content/browser/speech/speech_recognizer_impl.h b/content/browser/speech/speech_recognizer_impl.h
index 5636b18c..b802895 100644
--- a/content/browser/speech/speech_recognizer_impl.h
+++ b/content/browser/speech/speech_recognizer_impl.h
@@ -35,11 +35,12 @@
       public media::AudioCapturerSource::CaptureCallback,
       public SpeechRecognitionEngine::Delegate {
  public:
-  static const int kAudioSampleRate;
-  static const media::ChannelLayout kChannelLayout;
-  static const int kNumBitsPerAudioSample;
-  static const int kNoSpeechTimeoutMs;
-  static const int kEndpointerEstimationTimeMs;
+  static constexpr int kAudioSampleRate = 16000;
+  static constexpr media::ChannelLayout kChannelLayout =
+      media::CHANNEL_LAYOUT_MONO;
+  static constexpr int kNumBitsPerAudioSample = 16;
+  static constexpr int kNoSpeechTimeoutMs = 8000;
+  static constexpr int kEndpointerEstimationTimeMs = 300;
 
   static void SetAudioEnvironmentForTesting(
       media::AudioSystem* audio_system,
diff --git a/content/browser/speech/speech_recognizer_impl_unittest.cc b/content/browser/speech/speech_recognizer_impl_unittest.cc
index 240146c3..89a1ca0d 100644
--- a/content/browser/speech/speech_recognizer_impl_unittest.cc
+++ b/content/browser/speech/speech_recognizer_impl_unittest.cc
@@ -116,8 +116,8 @@
 
     const int channels =
         ChannelLayoutToChannelCount(SpeechRecognizerImpl::kChannelLayout);
-    bytes_per_sample_ = SpeechRecognizerImpl::kNumBitsPerAudioSample / 8;
-    const int frames = audio_packet_length_bytes / channels / bytes_per_sample_;
+    int bytes_per_sample = SpeechRecognizerImpl::kNumBitsPerAudioSample / 8;
+    const int frames = audio_packet_length_bytes / channels / bytes_per_sample;
     audio_bus_ = media::AudioBus::Create(channels, frames);
     audio_bus_->Zero();
   }
@@ -226,9 +226,11 @@
   }
 
   void CopyPacketToAudioBus() {
+    static_assert(SpeechRecognizerImpl::kNumBitsPerAudioSample == 16,
+                  "FromInterleaved expects 2 bytes.");
     // Copy the created signal into an audio bus in a deinterleaved format.
-    audio_bus_->FromInterleaved(
-        &audio_packet_[0], audio_bus_->frames(), bytes_per_sample_);
+    audio_bus_->FromInterleaved<media::SignedInt16SampleTypeTraits>(
+        reinterpret_cast<int16_t*>(audio_packet_.data()), audio_bus_->frames());
   }
 
   void FillPacketWithTestWaveform() {
@@ -289,7 +291,6 @@
   blink::mojom::SpeechRecognitionErrorCode error_;
   std::vector<uint8_t> audio_packet_;
   std::unique_ptr<media::AudioBus> audio_bus_;
-  int bytes_per_sample_;
   float volume_;
   float noise_volume_;
 };
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index 48b2fe1..4784e99 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -265,7 +265,6 @@
   IPC_STRUCT_TRAITS_MEMBER(capture_sequence_number)
   IPC_STRUCT_TRAITS_MEMBER(zoom_level)
   IPC_STRUCT_TRAITS_MEMBER(page_scale_factor)
-  IPC_STRUCT_TRAITS_MEMBER(is_pinch_gesture_active)
   IPC_STRUCT_TRAITS_MEMBER(local_surface_id_allocation)
 IPC_STRUCT_TRAITS_END()
 
diff --git a/content/common/frame_visual_properties.h b/content/common/frame_visual_properties.h
index c897b9b..b93180d 100644
--- a/content/common/frame_visual_properties.h
+++ b/content/common/frame_visual_properties.h
@@ -44,10 +44,7 @@
   // (0 is the default value which results in 1.0 zoom factor.)
   double zoom_level = 0;
 
-  // Tracks the page-scale factor and whether the frame is currently in an
-  // active pinch-zoom gesture.
   float page_scale_factor = 1.f;
-  bool is_pinch_gesture_active = false;
 
   // The time at which the viz::LocalSurfaceId used to submit this was
   // allocated.
diff --git a/content/common/visual_properties.h b/content/common/visual_properties.h
index dcccf0b..ed6f914 100644
--- a/content/common/visual_properties.h
+++ b/content/common/visual_properties.h
@@ -83,10 +83,6 @@
   // This represents the page's scale factor, which changes during pinch zoom.
   // It needs to be shared with subframes.
   float page_scale_factor = 1.f;
-
-  // Indicates whether a pinch gesture is currently active. Originates in the
-  // main frame's renderer, and needs to be shared with subframes.
-  bool is_pinch_gesture_active = false;
 };
 
 }  // namespace content
diff --git a/content/common/widget_messages.h b/content/common/widget_messages.h
index fcda7ced..84f6662a 100644
--- a/content/common/widget_messages.h
+++ b/content/common/widget_messages.h
@@ -63,7 +63,6 @@
   IPC_STRUCT_TRAITS_MEMBER(capture_sequence_number)
   IPC_STRUCT_TRAITS_MEMBER(zoom_level)
   IPC_STRUCT_TRAITS_MEMBER(page_scale_factor)
-  IPC_STRUCT_TRAITS_MEMBER(is_pinch_gesture_active)
 IPC_STRUCT_TRAITS_END()
 
 // Traits for WebDeviceEmulationParams.
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index b6de992..74a2c98 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -3155,20 +3155,6 @@
 void SynchronizeVisualPropertiesMessageFilter::OnSynchronizeVisualProperties(
     const viz::FrameSinkId& frame_sink_id,
     const FrameVisualProperties& visual_properties) {
-  // Monitor |is_pinch_gesture_active| to determine when pinch gestures begin
-  // and end.
-  if (visual_properties.is_pinch_gesture_active &&
-      !last_pinch_gesture_active_) {
-    pinch_gesture_active_set_ = true;
-  }
-  if (!visual_properties.is_pinch_gesture_active &&
-      last_pinch_gesture_active_) {
-    pinch_gesture_active_cleared_ = true;
-    if (pinch_end_run_loop_)
-      pinch_end_run_loop_->Quit();
-  }
-  last_pinch_gesture_active_ = visual_properties.is_pinch_gesture_active;
-
   gfx::Rect screen_space_rect_in_dip = visual_properties.screen_space_rect;
   if (IsUseZoomForDSFEnabled()) {
     screen_space_rect_in_dip =
@@ -3250,14 +3236,6 @@
   return false;
 }
 
-void SynchronizeVisualPropertiesMessageFilter::WaitForPinchGestureEnd() {
-  if (pinch_gesture_active_cleared_)
-    return;
-  DCHECK(!pinch_end_run_loop_);
-  pinch_end_run_loop_ = std::make_unique<base::RunLoop>();
-  pinch_end_run_loop_->Run();
-}
-
 RenderWidgetHostMouseEventMonitor::RenderWidgetHostMouseEventMonitor(
     RenderWidgetHost* host)
     : host_(host), event_received_(false) {
diff --git a/content/public/test/browser_test_utils.h b/content/public/test/browser_test_utils.h
index 69c48d88..7c11f9c 100644
--- a/content/public/test/browser_test_utils.h
+++ b/content/public/test/browser_test_utils.h
@@ -1574,7 +1574,6 @@
 // BrowserPluginHostMsg_SynchronizeVisualProperties messages. This allows the
 // message to continue to the target child so that processing can be verified by
 // tests.
-// It also monitors for GesturePinchBegin/End events.
 class SynchronizeVisualPropertiesMessageFilter
     : public content::BrowserMessageFilter {
  public:
@@ -1593,11 +1592,6 @@
   // Waits for the next viz::LocalSurfaceId be received and returns it.
   viz::LocalSurfaceId WaitForSurfaceId();
 
-  bool pinch_gesture_active_set() { return pinch_gesture_active_set_; }
-  bool pinch_gesture_active_cleared() { return pinch_gesture_active_cleared_; }
-
-  void WaitForPinchGestureEnd();
-
  protected:
   ~SynchronizeVisualPropertiesMessageFilter() override;
 
@@ -1629,11 +1623,6 @@
   viz::LocalSurfaceId last_surface_id_;
   std::unique_ptr<base::RunLoop> surface_id_run_loop_;
 
-  bool pinch_gesture_active_set_;
-  bool pinch_gesture_active_cleared_;
-  bool last_pinch_gesture_active_;
-  std::unique_ptr<base::RunLoop> pinch_end_run_loop_;
-
   DISALLOW_COPY_AND_ASSIGN(SynchronizeVisualPropertiesMessageFilter);
 };
 
diff --git a/content/renderer/compositor/layer_tree_view.cc b/content/renderer/compositor/layer_tree_view.cc
index 6d7e1f34..5f163f8 100644
--- a/content/renderer/compositor/layer_tree_view.cc
+++ b/content/renderer/compositor/layer_tree_view.cc
@@ -425,11 +425,8 @@
   layer_tree_host_->SetRasterColorSpace(color_space);
 }
 
-void LayerTreeView::SetExternalPageScaleFactor(
-    float page_scale_factor,
-    bool is_external_pinch_gesture_active) {
-  layer_tree_host_->SetExternalPageScaleFactor(
-      page_scale_factor, is_external_pinch_gesture_active);
+void LayerTreeView::SetExternalPageScaleFactor(float page_scale_factor) {
+  layer_tree_host_->SetExternalPageScaleFactor(page_scale_factor);
 }
 
 void LayerTreeView::ClearCachesOnNextCommit() {
diff --git a/content/renderer/compositor/layer_tree_view.h b/content/renderer/compositor/layer_tree_view.h
index a477847..7b0aac53 100644
--- a/content/renderer/compositor/layer_tree_view.h
+++ b/content/renderer/compositor/layer_tree_view.h
@@ -107,8 +107,7 @@
   bool SendMessageToMicroBenchmark(int id, std::unique_ptr<base::Value> value);
   void SetFrameSinkId(const viz::FrameSinkId& frame_sink_id);
   void SetRasterColorSpace(const gfx::ColorSpace& color_space);
-  void SetExternalPageScaleFactor(float page_scale_factor,
-                                  bool is_external_pinch_gesture_active);
+  void SetExternalPageScaleFactor(float page_scale_factor);
   void ClearCachesOnNextCommit();
   void SetContentSourceId(uint32_t source_id);
   void SetViewportSizeAndScale(
diff --git a/content/renderer/loader/request_extra_data.h b/content/renderer/loader/request_extra_data.h
index c649fcf..323a1493 100644
--- a/content/renderer/loader/request_extra_data.h
+++ b/content/renderer/loader/request_extra_data.h
@@ -55,13 +55,6 @@
     navigation_response_override_ = std::move(response_override);
   }
 
-  // The request is for a prefetch-only client (i.e. running NoStatePrefetch)
-  // and should use LOAD_PREFETCH network flags.
-  bool is_for_no_state_prefetch() const { return is_for_no_state_prefetch_; }
-  void set_is_for_no_state_prefetch(bool prefetch) {
-    is_for_no_state_prefetch_ = prefetch;
-  }
-
   // Copy of the settings value determining if mixed plugin content should be
   // blocked.
   bool block_mixed_plugin_content() const {
@@ -91,7 +84,6 @@
   blink::WebString custom_user_agent_;
   std::unique_ptr<NavigationResponseOverrideParameters>
       navigation_response_override_;
-  bool is_for_no_state_prefetch_ = false;
   bool block_mixed_plugin_content_ = false;
   std::vector<std::unique_ptr<URLLoaderThrottle>> url_loader_throttles_;
   scoped_refptr<FrameRequestBlocker> frame_request_blocker_;
diff --git a/content/renderer/loader/web_url_loader_impl.cc b/content/renderer/loader/web_url_loader_impl.cc
index 779511df..2ef7ebf 100644
--- a/content/renderer/loader/web_url_loader_impl.cc
+++ b/content/renderer/loader/web_url_loader_impl.cc
@@ -735,7 +735,7 @@
     resource_request->do_not_prompt_for_login = true;
   }
 
-  resource_request->load_flags = GetLoadFlagsForWebURLRequest(request);
+  resource_request->load_flags = request.GetLoadFlagsForWebURLRequest();
 
   // |plugin_child_id| only needs to be non-zero if the request originates
   // outside the render process, so we can use requestorProcessID even
diff --git a/content/renderer/loader/web_url_request_util.cc b/content/renderer/loader/web_url_request_util.cc
index d55a4a1..213837d 100644
--- a/content/renderer/loader/web_url_request_util.cc
+++ b/content/renderer/loader/web_url_request_util.cc
@@ -224,57 +224,6 @@
   return flattener.GetBuffer();
 }
 
-int GetLoadFlagsForWebURLRequest(const WebURLRequest& request) {
-  int load_flags = net::LOAD_NORMAL;
-
-  GURL url = request.Url();
-  switch (request.GetCacheMode()) {
-    case FetchCacheMode::kNoStore:
-      load_flags |= net::LOAD_DISABLE_CACHE;
-      break;
-    case FetchCacheMode::kValidateCache:
-      load_flags |= net::LOAD_VALIDATE_CACHE;
-      break;
-    case FetchCacheMode::kBypassCache:
-      load_flags |= net::LOAD_BYPASS_CACHE;
-      break;
-    case FetchCacheMode::kForceCache:
-      load_flags |= net::LOAD_SKIP_CACHE_VALIDATION;
-      break;
-    case FetchCacheMode::kOnlyIfCached:
-      load_flags |= net::LOAD_ONLY_FROM_CACHE | net::LOAD_SKIP_CACHE_VALIDATION;
-      break;
-    case FetchCacheMode::kUnspecifiedOnlyIfCachedStrict:
-      load_flags |= net::LOAD_ONLY_FROM_CACHE;
-      break;
-    case FetchCacheMode::kDefault:
-      break;
-    case FetchCacheMode::kUnspecifiedForceCacheMiss:
-      load_flags |= net::LOAD_ONLY_FROM_CACHE | net::LOAD_BYPASS_CACHE;
-      break;
-  }
-
-  if (!request.AllowStoredCredentials()) {
-    load_flags |= net::LOAD_DO_NOT_SAVE_COOKIES;
-    load_flags |= net::LOAD_DO_NOT_SEND_COOKIES;
-    load_flags |= net::LOAD_DO_NOT_SEND_AUTH_DATA;
-  }
-
-  if (request.GetRequestContext() == blink::mojom::RequestContextType::PREFETCH)
-    load_flags |= net::LOAD_PREFETCH;
-
-  if (request.GetExtraData()) {
-    RequestExtraData* extra_data =
-        static_cast<RequestExtraData*>(request.GetExtraData());
-    if (extra_data->is_for_no_state_prefetch())
-      load_flags |= net::LOAD_PREFETCH;
-  }
-  if (request.SupportsAsyncRevalidation())
-    load_flags |= net::LOAD_SUPPORT_ASYNC_REVALIDATION;
-
-  return load_flags;
-}
-
 WebHTTPBody GetWebHTTPBodyForRequestBody(
     const network::ResourceRequestBody& input) {
   return GetWebHTTPBodyForRequestBodyWithBlobPtrs(input, {});
diff --git a/content/renderer/loader/web_url_request_util.h b/content/renderer/loader/web_url_request_util.h
index 213dbfb..e00bd898 100644
--- a/content/renderer/loader/web_url_request_util.h
+++ b/content/renderer/loader/web_url_request_util.h
@@ -35,8 +35,6 @@
 std::string GetWebURLRequestHeadersAsString(
     const blink::WebURLRequest& request);
 
-int GetLoadFlagsForWebURLRequest(const blink::WebURLRequest& request);
-
 // Takes a ResourceRequestBody and converts into WebHTTPBody.
 blink::WebHTTPBody GetWebHTTPBodyForRequestBody(
     const network::ResourceRequestBody& input);
diff --git a/content/renderer/media/stream/media_stream_audio_processor_unittest.cc b/content/renderer/media/stream/media_stream_audio_processor_unittest.cc
index 662e3b1..d4bd6299 100644
--- a/content/renderer/media/stream/media_stream_audio_processor_unittest.cc
+++ b/content/renderer/media/stream/media_stream_audio_processor_unittest.cc
@@ -111,7 +111,8 @@
         expected_output_buffer_size * base::TimeDelta::FromSeconds(1) /
             expected_output_sample_rate;
     for (int i = 0; i < kNumberOfPacketsForTest; ++i) {
-      data_bus->FromInterleaved(data_ptr, data_bus->frames(), 2);
+      data_bus->FromInterleaved<media::SignedInt16SampleTypeTraits>(
+          data_ptr, data_bus->frames());
       audio_processor->PushCaptureData(*data_bus, input_capture_delay);
 
       // |audio_processor| does nothing when the audio processing is off in
diff --git a/content/renderer/media/webrtc/webrtc_audio_device_impl.cc b/content/renderer/media/webrtc/webrtc_audio_device_impl.cc
index 32f808d7..82f7916 100644
--- a/content/renderer/media/webrtc/webrtc_audio_device_impl.cc
+++ b/content/renderer/media/webrtc/webrtc_audio_device_impl.cc
@@ -75,16 +75,17 @@
 
   // Get 10ms audio and copy result to temporary byte buffer.
   render_buffer_.resize(audio_bus->frames() * audio_bus->channels());
-  const int bytes_per_sample = sizeof(render_buffer_[0]);
-  static const int kBitsPerByte = 8;
+  constexpr int kBytesPerSample = 2;
+  static_assert(sizeof(render_buffer_[0]) == kBytesPerSample,
+                "kBytesPerSample and FromInterleaved expect 2 bytes.");
   int64_t elapsed_time_ms = -1;
   int64_t ntp_time_ms = -1;
   int16_t* audio_data = render_buffer_.data();
 
   TRACE_EVENT_BEGIN0("audio", "VoE::PullRenderData");
   audio_transport_callback_->PullRenderData(
-      bytes_per_sample * kBitsPerByte, sample_rate, audio_bus->channels(),
-      frames_per_10_ms, audio_data, &elapsed_time_ms, &ntp_time_ms);
+      kBytesPerSample * 8, sample_rate, audio_bus->channels(), frames_per_10_ms,
+      audio_data, &elapsed_time_ms, &ntp_time_ms);
   TRACE_EVENT_END2("audio", "VoE::PullRenderData", "elapsed_time_ms",
                    elapsed_time_ms, "ntp_time_ms", ntp_time_ms);
   if (elapsed_time_ms >= 0)
@@ -92,7 +93,8 @@
 
   // De-interleave each channel and convert to 32-bit floating-point
   // with nominal range -1.0 -> +1.0 to match the callback format.
-  audio_bus->FromInterleaved(audio_data, audio_bus->frames(), bytes_per_sample);
+  audio_bus->FromInterleaved<media::SignedInt16SampleTypeTraits>(
+      audio_data, audio_bus->frames());
 
   // Pass the render data to the playout sinks.
   base::AutoLock auto_lock(lock_);
diff --git a/content/renderer/media/webrtc/webrtc_audio_sink.cc b/content/renderer/media/webrtc/webrtc_audio_sink.cc
index c880b1d2..45bc0a6 100644
--- a/content/renderer/media/webrtc/webrtc_audio_sink.cc
+++ b/content/renderer/media/webrtc/webrtc_audio_sink.cc
@@ -87,9 +87,10 @@
 
   // TODO(henrika): Remove this conversion once the interface in libjingle
   // supports float vectors.
-  audio_bus.ToInterleaved(audio_bus.frames(),
-                          sizeof(interleaved_data_[0]),
-                          interleaved_data_.get());
+  static_assert(sizeof(interleaved_data_[0]) == 2,
+                "ToInterleaved expects 2 bytes.");
+  audio_bus.ToInterleaved<media::SignedInt16SampleTypeTraits>(
+      audio_bus.frames(), interleaved_data_.get());
   adapter_->DeliverPCMToWebRtcSinks(interleaved_data_.get(),
                                     params_.sample_rate(),
                                     audio_bus.channels(),
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 6a61a8b..75479724 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -7123,7 +7123,7 @@
   blink::mojom::BlobURLTokenPtr blob_url_token(
       CloneBlobURLToken(info->blob_url_token.get()));
 
-  int load_flags = GetLoadFlagsForWebURLRequest(info->url_request);
+  int load_flags = info->url_request.GetLoadFlagsForWebURLRequest();
   std::unique_ptr<base::DictionaryValue> initiator =
       GetDevToolsInitiator(info->devtools_initiator_info);
   mojom::BeginNavigationParamsPtr begin_navigation_params =
diff --git a/content/renderer/render_frame_proxy.cc b/content/renderer/render_frame_proxy.cc
index 5342a18b..d4e8c3f0 100644
--- a/content/renderer/render_frame_proxy.cc
+++ b/content/renderer/render_frame_proxy.cc
@@ -311,10 +311,8 @@
   SynchronizeVisualProperties();
 }
 
-void RenderFrameProxy::OnPageScaleFactorChanged(float page_scale_factor,
-                                                bool is_pinch_gesture_active) {
+void RenderFrameProxy::OnPageScaleFactorChanged(float page_scale_factor) {
   pending_visual_properties_.page_scale_factor = page_scale_factor;
-  pending_visual_properties_.is_pinch_gesture_active = is_pinch_gesture_active;
   SynchronizeVisualProperties();
 }
 
@@ -689,8 +687,6 @@
           pending_visual_properties_.zoom_level ||
       sent_visual_properties_->page_scale_factor !=
           pending_visual_properties_.page_scale_factor ||
-      sent_visual_properties_->is_pinch_gesture_active !=
-          pending_visual_properties_.is_pinch_gesture_active ||
       capture_sequence_number_changed;
 
   if (synchronized_props_changed) {
diff --git a/content/renderer/render_frame_proxy.h b/content/renderer/render_frame_proxy.h
index bebf7d1..947c70a 100644
--- a/content/renderer/render_frame_proxy.h
+++ b/content/renderer/render_frame_proxy.h
@@ -145,9 +145,8 @@
   void OnZoomLevelChanged(double zoom_level);
 
   // Out-of-process child frames receive a signal from RenderWidget when the
-  // page scale factor has changed, and/or a pinch-zoom gesture starts/ends.
-  void OnPageScaleFactorChanged(float page_scale_factor,
-                                bool is_pinch_gesture_active);
+  // page scale factor has changed.
+  void OnPageScaleFactorChanged(float page_scale_factor);
 
   // Invoked by RenderWidget when a new capture sequence number was set,
   // indicating that surfaces should be synchronized.
@@ -230,10 +229,6 @@
 
   void WasEvicted();
 
-  bool is_pinch_gesture_active_for_testing() {
-    return pending_visual_properties_.is_pinch_gesture_active;
-  }
-
  private:
   RenderFrameProxy(int routing_id);
 
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc
index 3bb88dc9..0ff9552 100644
--- a/content/renderer/render_view_browsertest.cc
+++ b/content/renderer/render_view_browsertest.cc
@@ -548,54 +548,6 @@
   }
 };
 
-TEST_F(RenderViewImplTest, IsPinchGestureActivePropagatesToProxies) {
-  LoadHTML(
-      "<body style='min-height:1000px;'>"
-      "  <iframe src='data:text/html,frame 1'></iframe>"
-      "  <iframe src='data:text/html,frame 2'></iframe>"
-      "</body>");
-
-  // Verify child's proxy doesn't think we're pinching.
-  blink::WebFrame* root_web_frame = frame()->GetWebFrame();
-  ASSERT_TRUE(root_web_frame->FirstChild()->IsWebLocalFrame());
-  TestRenderFrame* child_frame_1 =
-      static_cast<TestRenderFrame*>(RenderFrame::FromWebFrame(
-          root_web_frame->FirstChild()->ToWebLocalFrame()));
-  ASSERT_TRUE(child_frame_1);
-  TestRenderFrame* child_frame_2 =
-      static_cast<TestRenderFrame*>(RenderFrame::FromWebFrame(
-          root_web_frame->FirstChild()->NextSibling()->ToWebLocalFrame()));
-  ASSERT_TRUE(child_frame_2);
-  child_frame_1->SwapOut(kProxyRoutingId, true,
-                         ReconstructReplicationStateForTesting(child_frame_1));
-  EXPECT_TRUE(root_web_frame->FirstChild()->IsWebRemoteFrame());
-  RenderFrameProxy* child_proxy_1 = RenderFrameProxy::FromWebFrame(
-      root_web_frame->FirstChild()->ToWebRemoteFrame());
-  ASSERT_TRUE(child_proxy_1);
-  EXPECT_FALSE(child_proxy_1->is_pinch_gesture_active_for_testing());
-
-  // Set the |is_pinch_gesture_active| flag.
-  view()->PageScaleFactorChanged(1.f, true);
-  EXPECT_TRUE(child_proxy_1->is_pinch_gesture_active_for_testing());
-
-  // Create a new remote child, and get its proxy. Swapping out will force
-  // creation and registering of a new RenderFrameProxy, which should pick up
-  // the existing setting.
-  child_frame_2->SwapOut(kProxyRoutingId + 1, true,
-                         ReconstructReplicationStateForTesting(child_frame_2));
-  EXPECT_TRUE(root_web_frame->FirstChild()->NextSibling()->IsWebRemoteFrame());
-  RenderFrameProxy* child_proxy_2 = RenderFrameProxy::FromWebFrame(
-      root_web_frame->FirstChild()->NextSibling()->ToWebRemoteFrame());
-
-  // Verify new child has the flag too.
-  EXPECT_TRUE(child_proxy_2->is_pinch_gesture_active_for_testing());
-
-  // Reset the flag, make sure both children respond.
-  view()->PageScaleFactorChanged(1.f, false);
-  EXPECT_FALSE(child_proxy_1->is_pinch_gesture_active_for_testing());
-  EXPECT_FALSE(child_proxy_2->is_pinch_gesture_active_for_testing());
-}
-
 // Test that we get form state change notifications when input fields change.
 TEST_F(RenderViewImplTest, OnNavStateChanged) {
   view()->set_send_content_state_immediately(true);
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index cd7cccd..9fb5ae6 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -860,18 +860,10 @@
         // the visual properties here. While blink doesn't need to know this
         // page scale factor outside the main frame, the compositor does in
         // order to produce its output at the correct scale.
-        layer_tree_view_->SetExternalPageScaleFactor(
-            params.page_scale_factor, params.is_pinch_gesture_active);
+        layer_tree_view_->SetExternalPageScaleFactor(params.page_scale_factor);
         // Store the value to give to any new RenderFrameProxy that is
         // registered.
         page_scale_factor_from_mainframe_ = params.page_scale_factor;
-        // Similarly, only the main frame knows when a pinch gesture is active,
-        // but this information is needed in subframes so they can throttle
-        // re-rastering in the same manner as the main frame.
-        // |is_pinch_gesture_active| follows the same path to the subframe
-        // compositor(s) as |page_scale_factor|.
-        is_pinch_gesture_active_from_mainframe_ =
-            params.is_pinch_gesture_active;
         // Push the page scale factor down to any child RenderWidgets via our
         // child proxy frames.
         // TODO(danakj): This ends up setting the page scale factor in the
@@ -880,10 +872,8 @@
         // global value per-page, we could instead store it once in the browser
         // (such as in RenderViewHost) and distribute it to each frame-hosted
         // RenderWidget from there.
-        for (auto& child_proxy : render_frame_proxies_) {
-          child_proxy.OnPageScaleFactorChanged(params.page_scale_factor,
-                                               params.is_pinch_gesture_active);
-        }
+        for (auto& child_proxy : render_frame_proxies_)
+          child_proxy.OnPageScaleFactorChanged(params.page_scale_factor);
       }
 
       gfx::Size old_visible_viewport_size = visible_viewport_size_;
@@ -3450,8 +3440,7 @@
   // frame trees). A new RenderFrameProxy means there is a new child
   // RenderWidget in another frame tree. In order for it to hear about
   // the page scale factor we pass along the last seen value here.
-  proxy->OnPageScaleFactorChanged(page_scale_factor_from_mainframe_,
-                                  is_pinch_gesture_active_from_mainframe_);
+  proxy->OnPageScaleFactorChanged(page_scale_factor_from_mainframe_);
 }
 
 void RenderWidget::UnregisterRenderFrameProxy(RenderFrameProxy* proxy) {
@@ -3598,16 +3587,21 @@
   // of which will be via proxy child frame). These will each in turn forward
   // the message to their child RenderWidgets (through their proxy child
   // frames).
+  // TODO(crbug.com/924336): This value is continuously propagated during a
+  // pinch-zoom, causing the child RenderWidgets to re-raster, while the main
+  // frame is able to throttle re-raster to powers of 2. We could find some way
+  // to throttle child RenderWidgets also, perhaps by informing them when the
+  // pinch-zoom gesture is started and stopped.
   DCHECK(!is_frozen_);
   DCHECK(delegate());
 
-  for (auto& observer : render_frame_proxies_) {
-    observer.OnPageScaleFactorChanged(page_scale_factor,
-                                      is_pinch_gesture_active);
-  }
+  // TODO(wjmaclean): In the next CL, plumb |is_pinch_gesture_active| into the
+  // observer via observer.OnPageScaleFactorChanged() and allow it to trigger
+  // SynchronizeVisualProperties if needed.
+  for (auto& observer : render_frame_proxies_)
+    observer.OnPageScaleFactorChanged(page_scale_factor);
   // Store the value to give to any new RenderFrameProxy that is registered.
   page_scale_factor_from_mainframe_ = page_scale_factor;
-  is_pinch_gesture_active_from_mainframe_ = is_pinch_gesture_active;
 }
 
 void RenderWidget::UseSynchronousResizeModeForTesting(bool enable) {
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index a289a6a..d0fd4036 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -1136,11 +1136,10 @@
   // The height of the browser bottom controls.
   float bottom_controls_height_ = 0.f;
 
-  // The last seen page scale state, which comes from the main frame and is
-  // propagated through the RenderWidget tree. This state is passed to any new
+  // The last seen page scale factor, which comes from the main frame and is
+  // propagated through the RenderWidget tree. This value is passed to any new
   // child RenderWidget.
   float page_scale_factor_from_mainframe_ = 1.f;
-  bool is_pinch_gesture_active_from_mainframe_ = false;
 
   // This is initialized to zero and is incremented on each non-same-page
   // navigation commit by RenderFrameImpl. At that time it is sent to the
diff --git a/content/renderer/render_widget_unittest.cc b/content/renderer/render_widget_unittest.cc
index e25ab23..023f4ede 100644
--- a/content/renderer/render_widget_unittest.cc
+++ b/content/renderer/render_widget_unittest.cc
@@ -15,13 +15,11 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/scoped_task_environment.h"
-#include "base/unguessable_token.h"
 #include "build/build_config.h"
 #include "cc/layers/solid_color_layer.h"
 #include "cc/trees/layer_tree_host.h"
 #include "components/viz/common/features.h"
 #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
-#include "content/common/frame_replication_state.h"
 #include "content/common/input/input_handler.mojom.h"
 #include "content/common/input/synthetic_web_input_event_builders.h"
 #include "content/common/input_messages.h"
@@ -33,7 +31,6 @@
 #include "content/renderer/compositor/layer_tree_view.h"
 #include "content/renderer/devtools/render_widget_screen_metrics_emulator.h"
 #include "content/renderer/input/widget_input_handler_manager.h"
-#include "content/renderer/render_frame_proxy.h"
 #include "content/renderer/render_widget_delegate.h"
 #include "content/test/fake_compositor_dependencies.h"
 #include "content/test/mock_render_process.h"
@@ -554,41 +551,6 @@
       const blink::WebDeviceEmulationParams& params) override {}
 };
 
-// Tests that the value of VisualProperties::is_pinch_gesture_active is
-// propagated to the LayerTreeHost when properties are synced, but only for
-// subframe widgets.
-TEST_F(RenderWidgetUnittest, ActivePinchGestureUpdatesLayerTreeHost) {
-  auto* layer_tree_host = widget()->layer_tree_view()->layer_tree_host();
-  EXPECT_FALSE(layer_tree_host->is_external_pinch_gesture_active_for_testing());
-  content::VisualProperties visual_properties;
-
-  // Sync visual properties on a child RenderWidget.
-  visual_properties.is_pinch_gesture_active = true;
-  widget()->OnSynchronizeVisualProperties(visual_properties);
-  // We expect the |is_pinch_gesture_active| value to propagate to the
-  // LayerTreeHost for sub-frames. Since GesturePinch events are handled
-  // directly in the main-frame's layer tree (and only there), information about
-  // whether or not we're in a pinch gesture must be communicated separately to
-  // sub-frame layer trees, via SynchronizeVisualProperties. This information
-  // is required to allow sub-frame compositors to throttle rastering while
-  // pinch gestures are active.
-  EXPECT_TRUE(layer_tree_host->is_external_pinch_gesture_active_for_testing());
-  visual_properties.is_pinch_gesture_active = false;
-  widget()->OnSynchronizeVisualProperties(visual_properties);
-  EXPECT_FALSE(layer_tree_host->is_external_pinch_gesture_active_for_testing());
-
-  // Repeat with a 'mainframe' widget.
-  widget()->set_delegate(std::make_unique<StubRenderWidgetDelegate>());
-  visual_properties.is_pinch_gesture_active = true;
-  widget()->OnSynchronizeVisualProperties(visual_properties);
-  // We do not expect the |is_pinch_gesture_active| value to propagate to the
-  // LayerTreeHost for the main-frame. Since GesturePinch events are handled
-  // directly by the layer tree for the main frame, it already knows whether or
-  // not a pinch gesture is active, and so we shouldn't propagate this
-  // information to the layer tree for a main-frame's widget.
-  EXPECT_FALSE(layer_tree_host->is_external_pinch_gesture_active_for_testing());
-}
-
 TEST_F(RenderWidgetPopupUnittest, EmulatingPopupRect) {
   blink::WebRect popup_screen_rect(200, 250, 100, 400);
   widget()->SetWindowRect(popup_screen_rect);
diff --git a/gpu/command_buffer/service/shared_image_factory.h b/gpu/command_buffer/service/shared_image_factory.h
index fbe6add4..824f2c9 100644
--- a/gpu/command_buffer/service/shared_image_factory.h
+++ b/gpu/command_buffer/service/shared_image_factory.h
@@ -75,13 +75,14 @@
                     base::trace_event::ProcessMemoryDump* pmd,
                     int client_id,
                     uint64_t client_tracing_id);
-  bool RegisterBacking(std::unique_ptr<SharedImageBacking> backing,
-                       bool allow_legacy_mailbox);
+  MemoryTypeTracker* memory_tracker() const { return memory_tracker_.get(); }
 
  private:
   bool IsSharedBetweenThreads(uint32_t usage);
   SharedImageBackingFactory* GetFactoryByUsage(uint32_t usage,
                                                bool* allow_legacy_mailbox);
+  bool RegisterBacking(std::unique_ptr<SharedImageBacking> backing,
+                       bool allow_legacy_mailbox);
   MailboxManager* mailbox_manager_;
   SharedImageManager* shared_image_manager_;
   std::unique_ptr<MemoryTypeTracker> memory_tracker_;
diff --git a/gpu/ipc/service/shared_image_stub.cc b/gpu/ipc/service/shared_image_stub.cc
index 92b0c71..1a0dd1b 100644
--- a/gpu/ipc/service/shared_image_stub.cc
+++ b/gpu/ipc/service/shared_image_stub.cc
@@ -27,8 +27,7 @@
               CommandBufferNamespace::GPU_IO,
               CommandBufferIdFromChannelAndRoute(channel->client_id(),
                                                  route_id),
-              sequence_)),
-      weak_factory_(this) {
+              sequence_)) {
   base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
       this, "gpu::SharedImageStub", channel_->task_runner());
 }
@@ -362,34 +361,4 @@
   return factory_->OnMemoryDump(args, pmd, ClientId(), ClientTracingId());
 }
 
-SharedImageStub::SharedImageDestructionCallback
-SharedImageStub::GetSharedImageDestructionCallback(const Mailbox& mailbox) {
-  auto destruction_cb = base::BindOnce(
-      [](base::WeakPtr<gpu::SharedImageStub> stub, const gpu::Mailbox& mailbox,
-         const gpu::SyncToken& sync_token) {
-        stub->DestroySharedImage(mailbox, sync_token);
-      },
-      weak_factory_.GetWeakPtr(), mailbox);
-  return destruction_cb;
-}
-
-void SharedImageStub::DestroySharedImage(const Mailbox& mailbox,
-                                         const SyncToken& sync_token) {
-  // If there is no sync token, we don't need to wait.
-  if (!sync_token.HasData()) {
-    OnSyncTokenReleased(mailbox);
-    return;
-  }
-
-  auto done_cb = base::BindOnce(&SharedImageStub::OnSyncTokenReleased,
-                                weak_factory_.GetWeakPtr(), mailbox);
-  channel_->scheduler()->ScheduleTask(
-      gpu::Scheduler::Task(sequence_, std::move(done_cb),
-                           std::vector<gpu::SyncToken>({sync_token})));
-}
-
-void SharedImageStub::OnSyncTokenReleased(const Mailbox& mailbox) {
-  factory_->DestroySharedImage(mailbox);
-}
-
 }  // namespace gpu
diff --git a/gpu/ipc/service/shared_image_stub.h b/gpu/ipc/service/shared_image_stub.h
index 99792469..8e832fa 100644
--- a/gpu/ipc/service/shared_image_stub.h
+++ b/gpu/ipc/service/shared_image_stub.h
@@ -5,14 +5,11 @@
 #ifndef GPU_IPC_SERVICE_SHARED_IMAGE_STUB_H_
 #define GPU_IPC_SERVICE_SHARED_IMAGE_STUB_H_
 
-#include "base/memory/weak_ptr.h"
 #include "base/trace_event/memory_dump_provider.h"
 #include "components/viz/common/resources/resource_format.h"
 #include "gpu/command_buffer/service/memory_tracking.h"
-#include "gpu/command_buffer/service/sequence_id.h"
 #include "gpu/command_buffer/service/sync_point_manager.h"
 #include "gpu/ipc/common/gpu_messages.h"
-#include "gpu/ipc/service/gpu_ipc_service_export.h"
 #include "ipc/ipc_listener.h"
 
 namespace gpu {
@@ -21,16 +18,12 @@
 class GpuChannel;
 class SharedImageFactory;
 
-class GPU_IPC_SERVICE_EXPORT SharedImageStub
-    : public IPC::Listener,
-      public MemoryTracker,
-      public base::trace_event::MemoryDumpProvider {
+class SharedImageStub : public IPC::Listener,
+                        public MemoryTracker,
+                        public base::trace_event::MemoryDumpProvider {
  public:
   ~SharedImageStub() override;
 
-  using SharedImageDestructionCallback =
-      base::OnceCallback<void(const gpu::SyncToken&)>;
-
   static std::unique_ptr<SharedImageStub> Create(GpuChannel* channel,
                                                  int32_t route_id);
 
@@ -50,10 +43,6 @@
 
   SequenceId sequence() const { return sequence_; }
   SharedImageFactory* factory() const { return factory_.get(); }
-  GpuChannel* channel() const { return channel_; }
-
-  SharedImageDestructionCallback GetSharedImageDestructionCallback(
-      const Mailbox& mailbox);
 
  private:
   SharedImageStub(GpuChannel* channel, int32_t route_id);
@@ -69,10 +58,6 @@
   bool MakeContextCurrent();
   ContextResult MakeContextCurrentAndCreateFactory();
   void OnError();
-  void OnSyncTokenReleased(const Mailbox& mailbox);
-
-  // Wait on the sync token if any and destroy the shared image.
-  void DestroySharedImage(const Mailbox& mailbox, const SyncToken& sync_token);
 
   GpuChannel* channel_;
   SequenceId sequence_;
@@ -83,8 +68,6 @@
   // Holds shared memory used in initial data uploads.
   base::ReadOnlySharedMemoryRegion upload_memory_;
   base::ReadOnlySharedMemoryMapping upload_memory_mapping_;
-
-  base::WeakPtrFactory<SharedImageStub> weak_factory_;
 };
 
 }  // namespace gpu
diff --git a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
index 318df227..922d702 100644
--- a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
+++ b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
@@ -585,6 +585,7 @@
     }
   } else {
     [self changeToState:IDENTITY_PICKER_STATE];
+    [_unifiedConsentCoordinator resetSettingLinkTapped];
   }
 }
 
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.h b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.h
index 7f09cab..2258aa9 100644
--- a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.h
+++ b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.h
@@ -65,6 +65,9 @@
 // Scrolls the consent view to the bottom.
 - (void)scrollToBottom;
 
+// Resets settingsLinkWasTapped flag.
+- (void)resetSettingLinkTapped;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_AUTHENTICATION_UNIFIED_CONSENT_UNIFIED_CONSENT_COORDINATOR_H_
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.mm b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.mm
index af5ce8c14..589a82c 100644
--- a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.mm
+++ b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_coordinator.mm
@@ -48,6 +48,16 @@
   [self.unifiedConsentMediator start];
 }
 
+- (void)scrollToBottom {
+  [self.unifiedConsentViewController scrollToBottom];
+}
+
+- (void)resetSettingLinkTapped {
+  self.settingsLinkWasTapped = NO;
+}
+
+#pragma mark - Properties
+
 - (ChromeIdentity*)selectedIdentity {
   return self.unifiedConsentMediator.selectedIdentity;
 }
@@ -68,10 +78,6 @@
   return [self.unifiedConsentViewController consentStringIds];
 }
 
-- (void)scrollToBottom {
-  [self.unifiedConsentViewController scrollToBottom];
-}
-
 - (BOOL)isScrolledToBottom {
   return self.unifiedConsentViewController.isScrolledToBottom;
 }
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
index 696e64ed..7c079ac 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -2318,6 +2318,8 @@
     NSArray<GuideName*>* guideNames = @[
       kContentAreaGuide,
       kOmniboxGuide,
+      kOmniboxLeadingImageGuide,
+      kOmniboxTextFieldGuide,
       kBackButtonGuide,
       kForwardButtonGuide,
       kToolsMenuGuide,
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_container_view.mm b/ios/chrome/browser/ui/omnibox/omnibox_container_view.mm
index 9b2f7395..bab2a32aa 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_container_view.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_container_view.mm
@@ -6,6 +6,7 @@
 
 #import "ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.h"
 #import "ios/chrome/browser/ui/util/animation_util.h"
+#import "ios/chrome/browser/ui/util/named_guide.h"
 #include "ios/chrome/browser/ui/util/rtl_geometry.h"
 #include "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
@@ -94,6 +95,13 @@
   return self;
 }
 
+- (void)didMoveToWindow {
+  [super didMoveToWindow];
+
+  [NamedGuide guideWithName:kOmniboxTextFieldGuide view:self].constrainedView =
+      self.textField;
+}
+
 - (void)setLeadingImageHidden:(BOOL)hidden {
   if (hidden) {
     [_leadingImageView removeFromSuperview];
@@ -116,6 +124,9 @@
       self.leadingImageViewLeadingConstraint,
       leadingImageViewToTextField,
     ]];
+
+    [NamedGuide guideWithName:kOmniboxLeadingImageGuide view:self]
+        .constrainedView = self.leadingImageView;
   }
 }
 
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm
index 27819be..07ea3787 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm
@@ -166,7 +166,10 @@
 #pragma mark - private
 
 - (void)updateLeadingImageVisibility {
-  [self.view setLeadingImageHidden:!IsRegularXRegularSizeClass(self)];
+  BOOL newOmniboxPopupLayout =
+      base::FeatureList::IsEnabled(kNewOmniboxPopupLayout);
+  [self.view setLeadingImageHidden:!newOmniboxPopupLayout &&
+                                   !IsRegularXRegularSizeClass(self)];
 }
 
 // Tint color for the textfield placeholder and the clear button.
diff --git a/ios/chrome/browser/ui/omnibox/popup/BUILD.gn b/ios/chrome/browser/ui/omnibox/popup/BUILD.gn
index 71209a57..f1726cc4 100644
--- a/ios/chrome/browser/ui/omnibox/popup/BUILD.gn
+++ b/ios/chrome/browser/ui/omnibox/popup/BUILD.gn
@@ -26,6 +26,7 @@
     "//ios/chrome/browser",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui:feature_flags",
     "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/ntp:util",
     "//ios/chrome/browser/ui/omnibox:omnibox_util",
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm
index b91b062..116e6818 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm
@@ -14,8 +14,10 @@
 #import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_legacy_view_controller.h"
 #import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_mediator.h"
 #import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_presenter.h"
+#import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.h"
 #include "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_ios.h"
 #include "ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_coordinator.h"
+#include "ios/chrome/browser/ui/ui_feature_flags.h"
 #include "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
@@ -63,7 +65,11 @@
                                            delegate:_popupView.get()];
   self.mediator.dispatcher = (id<BrowserCommands>)self.dispatcher;
   self.mediator.webStateList = self.webStateList;
-  self.popupViewController = [[OmniboxPopupLegacyViewController alloc] init];
+  if (base::FeatureList::IsEnabled(kNewOmniboxPopupLayout)) {
+    self.popupViewController = [[OmniboxPopupViewController alloc] init];
+  } else {
+    self.popupViewController = [[OmniboxPopupLegacyViewController alloc] init];
+  }
   self.popupViewController.incognito = self.browserState->IsOffTheRecord();
 
   BOOL isIncognito = self.browserState->IsOffTheRecord();
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell.mm
index 4db7a8f..59724923 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell.mm
@@ -12,6 +12,7 @@
 #import "ios/chrome/browser/ui/omnibox/popup/image_retriever.h"
 #import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_truncating_label.h"
 #import "ios/chrome/browser/ui/toolbar/public/toolbar_constants.h"
+#import "ios/chrome/browser/ui/util/named_guide.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ios/chrome/grit/ios_theme_resources.h"
@@ -23,10 +24,7 @@
 #endif
 
 namespace {
-const CGFloat kLeadingMargin = 12;
-const CGFloat kLeadingMarginIpad = 183;
 const CGFloat kTextTopMargin = 6;
-const CGFloat kTextLeadingMargin = 10;
 const CGFloat kImageViewSize = 28;
 const CGFloat kImageViewCornerRadius = 7;
 const CGFloat kTrailingButtonSize = 24;
@@ -77,6 +75,7 @@
         initWithArrangedSubviews:@[ _textTruncatingLabel ]];
     _textStackView.translatesAutoresizingMaskIntoConstraints = NO;
     _textStackView.axis = UILayoutConstraintAxisVertical;
+    _textStackView.alignment = UIStackViewAlignmentLeading;
 
     _detailTruncatingLabel =
         [[OmniboxPopupTruncatingLabel alloc] initWithFrame:CGRectZero];
@@ -115,6 +114,14 @@
   return self;
 }
 
+- (void)didMoveToWindow {
+  [super didMoveToWindow];
+
+  if (self.window) {
+    [self attachToLayoutGuides];
+  }
+}
+
 #pragma mark - Layout
 
 // Setup the layout of the cell initially. This only adds the elements that are
@@ -127,23 +134,19 @@
     // Row has a minimum height.
     [self.contentView.heightAnchor constraintGreaterThanOrEqualToConstant:48],
 
-    // Position leadingImageView at the leading edge of the view
+    // Position leadingImageView at the leading edge of the view.
+    // Leave the horizontal position unconstrained as that will be added via a
+    // layout guide once the cell has been added to the view hierarchy.
     [self.leadingImageView.heightAnchor
         constraintEqualToConstant:kImageViewSize],
     [self.leadingImageView.widthAnchor
         constraintEqualToConstant:kImageViewSize],
-    [self.leadingImageView.leadingAnchor
-        constraintEqualToAnchor:self.contentView.leadingAnchor
-                       constant:IsRegularXRegularSizeClass()
-                                    ? kLeadingMarginIpad
-                                    : kLeadingMargin],
     [self.leadingImageView.centerYAnchor
         constraintEqualToAnchor:self.contentView.centerYAnchor],
 
-    // Position textStackView after leadingImageView.
-    [self.textStackView.leadingAnchor
-        constraintEqualToAnchor:self.leadingImageView.trailingAnchor
-                       constant:kTextLeadingMargin],
+    // Position textStackView "after" leadingImageView. The leading constraint
+    // is actually left off because it will be added via a
+    // layout guide once the cell has been added to the view hierarchy.
     // Use greater than or equal constraints because there may be a trailing
     // view here.
     [self.contentView.trailingAnchor
@@ -195,6 +198,24 @@
   ]];
 }
 
+- (void)attachToLayoutGuides {
+  NamedGuide* imageLayoutGuide =
+      [NamedGuide guideWithName:kOmniboxLeadingImageGuide view:self];
+  NamedGuide* textLayoutGuide = [NamedGuide guideWithName:kOmniboxTextFieldGuide
+                                                     view:self];
+
+  // Layout guides should both be setup
+  DCHECK(imageLayoutGuide.isConstrained);
+  DCHECK(textLayoutGuide.isConstrained);
+
+  [NSLayoutConstraint activateConstraints:@[
+    [self.leadingImageView.centerXAnchor
+        constraintEqualToAnchor:imageLayoutGuide.centerXAnchor],
+    [self.textStackView.leadingAnchor
+        constraintEqualToAnchor:textLayoutGuide.leadingAnchor],
+  ]];
+}
+
 - (void)prepareForReuse {
   [super prepareForReuse];
 
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.mm
index a984dd68..f704c5cf 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.mm
@@ -6,6 +6,7 @@
 #import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_base_view_controller+internal.h"
 
 #import "base/logging.h"
+#include "base/mac/foundation_util.h"
 #import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -45,6 +46,11 @@
 
 - (CGFloat)tableView:(UITableView*)tableView
     heightForRowAtIndexPath:(NSIndexPath*)indexPath {
+  if (self.shortcutsEnabled && indexPath.row == 0 &&
+      self.currentResult.count == 0) {
+    return self.shortcutsViewController.collectionView.collectionViewLayout
+        .collectionViewContentSize.height;
+  }
   return UITableViewAutomaticDimension;
 }
 
diff --git a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
index 40cc072a..646538e6 100644
--- a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
@@ -25,6 +25,7 @@
 #include "ios/chrome/browser/ios_chrome_flag_descriptions.h"
 #include "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h"
 #include "ios/chrome/browser/pref_names.h"
+#include "ios/chrome/browser/search_engines/search_engine_observer_bridge.h"
 #include "ios/chrome/browser/search_engines/template_url_service_factory.h"
 #import "ios/chrome/browser/signin/authentication_service.h"
 #include "ios/chrome/browser/signin/authentication_service_factory.h"
@@ -202,14 +203,16 @@
     GoogleServicesSettingsCoordinatorDelegate,
     PrefObserverDelegate,
     SettingsControllerProtocol,
+    SearchEngineObserving,
     SettingsMainPageCommands,
     SigninPresenter,
     SigninPromoViewConsumer,
     SyncObserverModelBridge> {
   // The current browser state that hold the settings. Never off the record.
   ios::ChromeBrowserState* _browserState;  // weak
-
-  std::unique_ptr<IdentityObserverBridge> _notificationBridge;
+  // Bridge for TemplateURLServiceObserver.
+  std::unique_ptr<SearchEngineObserverBridge> _searchEngineObserverBridge;
+  std::unique_ptr<IdentityObserverBridge> _identityObserverBridge;
   std::unique_ptr<SyncObserverBridge> _syncObserverBridge;
   // Whether the impression of the Signin button has already been recorded.
   BOOL _hasRecordedSigninImpression;
@@ -288,7 +291,11 @@
   if (self) {
     _browserState = browserState;
     self.title = l10n_util::GetNSStringWithFixup(IDS_IOS_SETTINGS_TITLE);
-    _notificationBridge.reset(new IdentityObserverBridge(_browserState, self));
+    _searchEngineObserverBridge.reset(new SearchEngineObserverBridge(
+        self,
+        ios::TemplateURLServiceFactory::GetForBrowserState(_browserState)));
+    _identityObserverBridge.reset(
+        new IdentityObserverBridge(_browserState, self));
     syncer::SyncService* syncService =
         ProfileSyncServiceFactory::GetForBrowserState(_browserState);
     _syncObserverBridge.reset(new SyncObserverBridge(self, syncService));
@@ -344,7 +351,7 @@
 
 - (void)stopBrowserStateServiceObservers {
   _syncObserverBridge.reset();
-  _notificationBridge.reset();
+  _identityObserverBridge.reset();
   _identityServiceObserver.reset();
   [_showMemoryDebugToolsEnabled setObserver:nil];
   [_articlesEnabled setObserver:nil];
@@ -366,14 +373,6 @@
       UINavigationItemLargeTitleDisplayModeAlways;
 }
 
-// TODO(crbug.com/661915): Refactor TemplateURLObserver and re-implement this so
-// it observes the default search engine name instead of reloading on
-// ViewWillAppear.
-- (void)viewWillAppear:(BOOL)animated {
-  [super viewWillAppear:animated];
-  [self updateSearchCell];
-}
-
 #pragma mark SettingsRootTableViewController
 
 - (void)loadModel {
@@ -690,17 +689,6 @@
 }
 #endif  // CHROMIUM_BUILD && !defined(NDEBUG)
 
-#pragma mark Item Updaters
-
-- (void)updateSearchCell {
-  NSString* defaultSearchEngineName =
-      base::SysUTF16ToNSString(GetDefaultSearchEngineName(
-          ios::TemplateURLServiceFactory::GetForBrowserState(_browserState)));
-
-  _defaultSearchEngineItem.detailText = defaultSearchEngineName;
-  [self reconfigureCellsForItems:@[ _defaultSearchEngineItem ]];
-}
-
 #pragma mark Item Constructors
 
 - (TableViewDetailIconItem*)detailItemWithType:(NSInteger)type
@@ -1211,6 +1199,15 @@
   return _resizedImage;
 }
 
+#pragma mark - SearchEngineObserverBridge
+
+- (void)searchEngineChanged {
+  _defaultSearchEngineItem.detailText =
+      base::SysUTF16ToNSString(GetDefaultSearchEngineName(
+          ios::TemplateURLServiceFactory::GetForBrowserState(_browserState)));
+  [self reconfigureCellsForItems:@[ _defaultSearchEngineItem ]];
+}
+
 #pragma mark ChromeIdentityServiceObserver
 
 - (void)profileUpdate:(ChromeIdentity*)identity {
diff --git a/ios/chrome/browser/ui/settings/table_cell_catalog_view_controller.mm b/ios/chrome/browser/ui/settings/table_cell_catalog_view_controller.mm
index 7830dbe..4ab632498 100644
--- a/ios/chrome/browser/ui/settings/table_cell_catalog_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/table_cell_catalog_view_controller.mm
@@ -181,11 +181,27 @@
   detailIconItem.detailText = @"Short";
   [model addItem:detailIconItem toSectionWithIdentifier:SectionIdentifierText];
 
-  TableViewDetailIconItem* detailIconItemLong =
+  TableViewDetailIconItem* detailIconItemLeftLong =
       [[TableViewDetailIconItem alloc] initWithType:ItemTypeTextSettingsDetail];
-  detailIconItemLong.text = @"Very long text eating the other detail label";
-  detailIconItemLong.detailText = @"A bit less short";
-  [model addItem:detailIconItemLong
+  detailIconItemLeftLong.text =
+      @"Left label is very very very very very very very long";
+  detailIconItemLeftLong.detailText = @"R";
+  [model addItem:detailIconItemLeftLong
+      toSectionWithIdentifier:SectionIdentifierText];
+
+  TableViewDetailIconItem* detailIconItemRightLong =
+      [[TableViewDetailIconItem alloc] initWithType:ItemTypeTextSettingsDetail];
+  detailIconItemRightLong.text = @"L";
+  detailIconItemRightLong.detailText =
+      @"Right label is very very very very very very very long";
+  [model addItem:detailIconItemRightLong
+      toSectionWithIdentifier:SectionIdentifierText];
+
+  TableViewDetailIconItem* detailIconItemBothLong =
+      [[TableViewDetailIconItem alloc] initWithType:ItemTypeTextSettingsDetail];
+  detailIconItemBothLong.text = @"Left label occupy 75% of row space";
+  detailIconItemBothLong.detailText = @"Right label occupy 25% of row space";
+  [model addItem:detailIconItemBothLong
       toSectionWithIdentifier:SectionIdentifierText];
 
   // SectionIdentifierSettings.
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_detail_icon_item.h b/ios/chrome/browser/ui/table_view/cells/table_view_detail_icon_item.h
index 0ec99f5..f1c847d0 100644
--- a/ios/chrome/browser/ui/table_view/cells/table_view_detail_icon_item.h
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_detail_icon_item.h
@@ -41,27 +41,6 @@
 // the full width of the cell.
 - (void)setIconImage:(UIImage*)image;
 
-// The amount of horizontal space to provide to each of the labels, Exposed for
-// testing. When the preferred ContentSize category chosen by the user isn't one
-// of the accessibility categories, these values are determined with the
-// following logic:
-//
-// - If there is sufficient room (after accounting for margins) for the full
-//   width of each label, use the current width of each label.
-// - If not, use the current width of the main label and a clipped width for the
-//   detail label.
-// - Unless the main label wants more than 75% of the available width and the
-//   detail label wants 25% or less of the available width, in which case use a
-//   clipped width for the main label and the current width of the detail label.
-// - If both labels want more width than their guaranteed minimums (75% and
-//   25%), use the guaranteed minimum amount for each.
-//
-// If the PreferredContentSizeCategory is an Accessibility category, those
-// values aren't used. The content is displayed on two labels, one above the
-// other, without limitation on the number of lines used by the labels.
-@property(nonatomic, readonly) CGFloat textLabelTargetWidth;
-@property(nonatomic, readonly) CGFloat detailTextLabelTargetWidth;
-
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_TABLE_VIEW_CELLS_TABLE_VIEW_DETAIL_ICON_ITEM_H_
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_detail_icon_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_detail_icon_item.mm
index 7879f74..11a35f7 100644
--- a/ios/chrome/browser/ui/table_view/cells/table_view_detail_icon_item.mm
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_detail_icon_item.mm
@@ -20,22 +20,16 @@
 
 // Padding used between the icon and the text labels.
 const CGFloat kIconTrailingPadding = 12;
-
 // Size of the icon image.
 const CGFloat kIconImageSize = 28;
+// Proportion of Cell's textLabel/detailTextLabel. This guarantees that the
+// textLabel occupies 75% of the row space and detailTextLabel occupies 25%.
+const CGFloat kCellLabelsWidthProportion = 3.0f;
 
-// Minimum proportion of the available width to guarantee to the main and detail
-// labels.
-const CGFloat kMinTextWidthRatio = 0.75f;
-const CGFloat kMinDetailTextWidthRatio = 0.25f;
 }  // namespace
 
 @implementation TableViewDetailIconItem
 
-@synthesize iconImageName = _iconImageName;
-@synthesize text = _text;
-@synthesize detailText = _detailText;
-
 - (instancetype)initWithType:(NSInteger)type {
   self = [super initWithType:type];
   if (self) {
@@ -83,8 +77,6 @@
   UILayoutGuide* _labelContainerGuide;
   NSLayoutConstraint* _iconHiddenConstraint;
   NSLayoutConstraint* _iconVisibleConstraint;
-  NSLayoutConstraint* _textLabelWidthConstraint;
-  NSLayoutConstraint* _detailTextLabelWidthConstraint;
 }
 
 @synthesize detailTextLabel = _detailTextLabel;
@@ -113,6 +105,7 @@
     _textLabel.adjustsFontForContentSizeCategory = YES;
     _textLabel.textColor = [UIColor blackColor];
     _textLabel.backgroundColor = [UIColor clearColor];
+    _textLabel.textAlignment = NSTextAlignmentLeft;
     [contentView addSubview:_textLabel];
 
     _detailTextLabel = [[UILabel alloc] init];
@@ -122,15 +115,9 @@
     _detailTextLabel.adjustsFontForContentSizeCategory = YES;
     _detailTextLabel.textColor = UIColorFromRGB(kSettingsCellsDetailTextColor);
     _detailTextLabel.backgroundColor = [UIColor clearColor];
+    _detailTextLabel.textAlignment = NSTextAlignmentRight;
     [contentView addSubview:_detailTextLabel];
 
-    // Set up the width constraints. They are activated here and updated in
-    // layoutSubviews.
-    _textLabelWidthConstraint =
-        [_textLabel.widthAnchor constraintEqualToConstant:0];
-    _detailTextLabelWidthConstraint =
-        [_detailTextLabel.widthAnchor constraintEqualToConstant:0];
-
     // Set up the constraints for when the icon is visible and hidden.  One of
     // these will be active at a time, defaulting to hidden.
     _iconHiddenConstraint = [_labelContainerGuide.leadingAnchor
@@ -140,17 +127,45 @@
         constraintEqualToAnchor:_iconImageView.trailingAnchor
                        constant:kIconTrailingPadding];
 
+    // Rules between |_textLabel| width and |_detailTextLabel| width:
+    //   1. Widths are represented by the percentage according to the
+    //      available space inside |_labelContainerGuide|;
+    //   2. |_textLabel| has a width quota of 75%;
+    //   3. |_detailTextLabe| has a width quota of 25%;
+    //   4. When label A fits in A's quota, rest of A's quota can be used by
+    //      the other label(i.e. B can exceed B's quota), and vice versa;
+    //   5. When both labels exceed their quota, they occupy their quotas.
+    //
+    // Expected space allocation result:
+    //   Rows are |_textLabel|'s quota.
+    //   Columns are |_detailTextLabel|'s quota.
+    //   Pairs are actual width for (|_textLabel|, |_detailTextLabel|).
+    //
+    //                20%             60%             90%
+    //
+    //   20%       (20%, 20%)      (20%, 60%)      (20%, 80%)
+    //   60%       (60%, 20%)      (60%, 40%)      (60%, 30%)
+    //   90%       (80%, 20%)      (75%, 25%)      (75%, 25%)
+    //
+    NSLayoutConstraint* widthConstraint = [_textLabel.widthAnchor
+        constraintEqualToAnchor:_detailTextLabel.widthAnchor
+                     multiplier:kCellLabelsWidthProportion];
+    // Set low priority to the proportion constraint between |_textLabel| and
+    // |_detailTextLabel|, so that it won't break other layouts.
+    widthConstraint.priority = UILayoutPriorityDefaultLow;
     _standardConstraints = @[
-      _textLabelWidthConstraint,
-      _detailTextLabelWidthConstraint,
       // Set up the vertical constraints and align the baselines of the two text
       // labels.
       [_textLabel.centerYAnchor
           constraintEqualToAnchor:contentView.centerYAnchor],
+      [_textLabel.trailingAnchor
+          constraintLessThanOrEqualToAnchor:_detailTextLabel.leadingAnchor
+                                   constant:-kTableViewHorizontalSpacing],
       [_detailTextLabel.firstBaselineAnchor
           constraintEqualToAnchor:_textLabel.firstBaselineAnchor],
       [_detailTextLabel.trailingAnchor
           constraintEqualToAnchor:_labelContainerGuide.trailingAnchor],
+      widthConstraint,
     ];
 
     _accessibilityConstraints = @[
@@ -235,24 +250,6 @@
   }
 }
 
-// Updates the layout constraints of the text labels and then calls the
-// superclass's implementation of layoutSubviews which can then take account of
-// the new constraints.
-- (void)layoutSubviews {
-  [super layoutSubviews];
-
-  // Size the labels in order to determine how much width they want.
-  [self.textLabel sizeToFit];
-  [self.detailTextLabel sizeToFit];
-
-  // Update the width constraints.
-  _textLabelWidthConstraint.constant = self.textLabelTargetWidth;
-  _detailTextLabelWidthConstraint.constant = self.detailTextLabelTargetWidth;
-
-  // Now invoke the layout.
-  [super layoutSubviews];
-}
-
 #pragma mark - UITableViewCell
 
 - (void)prepareForReuse {
@@ -281,34 +278,6 @@
   }
 }
 
-- (CGFloat)textLabelTargetWidth {
-  CGFloat availableWidth = CGRectGetWidth(_labelContainerGuide.layoutFrame) -
-                           kTableViewHorizontalSpacing;
-  CGFloat textLabelWidth = self.textLabel.frame.size.width;
-  CGFloat detailTextLabelWidth = self.detailTextLabel.frame.size.width;
-
-  if (textLabelWidth + detailTextLabelWidth <= availableWidth)
-    return textLabelWidth;
-
-  return std::max(
-      availableWidth - detailTextLabelWidth,
-      std::min(availableWidth * kMinTextWidthRatio, textLabelWidth));
-}
-
-- (CGFloat)detailTextLabelTargetWidth {
-  CGFloat availableWidth = CGRectGetWidth(_labelContainerGuide.layoutFrame) -
-                           kTableViewHorizontalSpacing;
-  CGFloat textLabelWidth = self.textLabel.frame.size.width;
-  CGFloat detailTextLabelWidth = self.detailTextLabel.frame.size.width;
-
-  if (textLabelWidth + detailTextLabelWidth <= availableWidth)
-    return detailTextLabelWidth;
-
-  return std::max(availableWidth - textLabelWidth,
-                  std::min(availableWidth * kMinDetailTextWidthRatio,
-                           detailTextLabelWidth));
-}
-
 - (NSString*)accessibilityLabel {
   return self.textLabel.text;
 }
diff --git a/ios/chrome/browser/ui/util/layout_guide_names.h b/ios/chrome/browser/ui/util/layout_guide_names.h
index e4506b5f..6679c84 100644
--- a/ios/chrome/browser/ui/util/layout_guide_names.h
+++ b/ios/chrome/browser/ui/util/layout_guide_names.h
@@ -22,6 +22,12 @@
 extern GuideName* const kSecondaryToolbarNoFullscreenGuide;
 // A guide that is constrained to match the frame of the omnibox.
 extern GuideName* const kOmniboxGuide;
+// A guide that is constrained to match the frame of the leading image view in
+// the omnibox.
+extern GuideName* const kOmniboxLeadingImageGuide;
+// A guide that is constrainted to match the frame of the text field in the
+// omnibox.
+extern GuideName* const kOmniboxTextFieldGuide;
 // A guide that is constrained to match the frame of the back button's image.
 extern GuideName* const kBackButtonGuide;
 // A guide that is constrained to match the frame of the forward button's image.
diff --git a/ios/chrome/browser/ui/util/layout_guide_names.mm b/ios/chrome/browser/ui/util/layout_guide_names.mm
index 8c011ef1..cc10b17 100644
--- a/ios/chrome/browser/ui/util/layout_guide_names.mm
+++ b/ios/chrome/browser/ui/util/layout_guide_names.mm
@@ -13,6 +13,8 @@
 GuideName* const kSecondaryToolbarNoFullscreenGuide =
     @"kSecondaryToolbarNoFullscreenGuide";
 GuideName* const kOmniboxGuide = @"kOmniboxGuide";
+GuideName* const kOmniboxLeadingImageGuide = @"kOmniboxLeadingImageGuide";
+GuideName* const kOmniboxTextFieldGuide = @"kOmniboxTextFieldGuide";
 GuideName* const kBackButtonGuide = @"kBackButtonGuide";
 GuideName* const kForwardButtonGuide = @"kForwardButtonGuide";
 GuideName* const kSearchButtonGuide = @"kSearchButtonGuide";
diff --git a/media/audio/android/audio_android_unittest.cc b/media/audio/android/audio_android_unittest.cc
index 4e63f2e6..5af0c4a3 100644
--- a/media/audio/android/audio_android_unittest.cc
+++ b/media/audio/android/audio_android_unittest.cc
@@ -280,12 +280,13 @@
               double volume) override {
     const int num_samples = src->frames() * src->channels();
     std::unique_ptr<int16_t> interleaved(new int16_t[num_samples]);
-    const int bytes_per_sample = sizeof(*interleaved);
-    src->ToInterleaved(src->frames(), bytes_per_sample, interleaved.get());
+    src->ToInterleaved<SignedInt16SampleTypeTraits>(src->frames(),
+                                                    interleaved.get());
 
     // Store data data in a temporary buffer to avoid making blocking
     // fwrite() calls in the audio callback. The complete buffer will be
     // written to file in the destructor.
+    const int bytes_per_sample = sizeof(*interleaved);
     const int size = bytes_per_sample * num_samples;
     if (!buffer_->Append((const uint8_t*)interleaved.get(), size))
       event_->Signal();
@@ -331,8 +332,9 @@
 
     const int num_samples = src->frames() * src->channels();
     std::unique_ptr<int16_t> interleaved(new int16_t[num_samples]);
+    src->ToInterleaved<SignedInt16SampleTypeTraits>(src->frames(),
+                                                    interleaved.get());
     const int bytes_per_sample = sizeof(*interleaved);
-    src->ToInterleaved(src->frames(), bytes_per_sample, interleaved.get());
     const int size = bytes_per_sample * num_samples;
 
     base::AutoLock lock(lock_);
diff --git a/media/audio/mac/audio_low_latency_input_mac_unittest.cc b/media/audio/mac/audio_low_latency_input_mac_unittest.cc
index 970f4b3..bace146 100644
--- a/media/audio/mac/audio_low_latency_input_mac_unittest.cc
+++ b/media/audio/mac/audio_low_latency_input_mac_unittest.cc
@@ -89,12 +89,13 @@
               double volume) override {
     const int num_samples = src->frames() * src->channels();
     std::unique_ptr<int16_t> interleaved(new int16_t[num_samples]);
-    const int bytes_per_sample = sizeof(*interleaved);
-    src->ToInterleaved(src->frames(), bytes_per_sample, interleaved.get());
+    src->ToInterleaved<SignedInt16SampleTypeTraits>(src->frames(),
+                                                    interleaved.get());
 
     // Store data data in a temporary buffer to avoid making blocking
     // fwrite() calls in the audio callback. The complete buffer will be
     // written to file in the destructor.
+    const int bytes_per_sample = sizeof(*interleaved);
     const int size = bytes_per_sample * num_samples;
     if (buffer_.Append((const uint8_t*)interleaved.get(), size)) {
       bytes_to_write_ += size;
diff --git a/media/audio/win/audio_low_latency_output_win_unittest.cc b/media/audio/win/audio_low_latency_output_win_unittest.cc
index 60648d2..877c883 100644
--- a/media/audio/win/audio_low_latency_output_win_unittest.cc
+++ b/media/audio/win/audio_low_latency_output_win_unittest.cc
@@ -130,11 +130,13 @@
 
     // Use samples read from a data file and fill up the audio buffer
     // provided to us in the callback.
-    if (pos_ + static_cast<int>(max_size) > file_size())
+    if (pos_ + max_size > file_size())
       max_size = file_size() - pos_;
     int frames = max_size / (dest->channels() * kBitsPerSample / 8);
     if (max_size) {
-      dest->FromInterleaved(file_->data() + pos_, frames, kBitsPerSample / 8);
+      static_assert(kBitsPerSample == 16, "FromInterleaved expects 2 bytes.");
+      dest->FromInterleaved<SignedInt16SampleTypeTraits>(
+          reinterpret_cast<const int16_t*>(file_->data() + pos_), frames);
       pos_ += max_size;
     }
     return frames;
diff --git a/media/base/audio_bus.cc b/media/base/audio_bus.cc
index 0c61d5f..12f2e7ae 100644
--- a/media/base/audio_bus.cc
+++ b/media/base/audio_bus.cc
@@ -346,31 +346,6 @@
   }
 }
 
-// Forwards to non-deprecated version.
-void AudioBus::ToInterleavedPartial(int start_frame,
-                                    int frames,
-                                    int bytes_per_sample,
-                                    void* dest) const {
-  DCHECK(!is_bitstream_format_);
-  switch (bytes_per_sample) {
-    case 1:
-      ToInterleavedPartial<UnsignedInt8SampleTypeTraits>(
-          start_frame, frames, reinterpret_cast<uint8_t*>(dest));
-      break;
-    case 2:
-      ToInterleavedPartial<SignedInt16SampleTypeTraits>(
-          start_frame, frames, reinterpret_cast<int16_t*>(dest));
-      break;
-    case 4:
-      ToInterleavedPartial<SignedInt32SampleTypeTraits>(
-          start_frame, frames, reinterpret_cast<int32_t*>(dest));
-      break;
-    default:
-      NOTREACHED() << "Unsupported bytes per sample encountered: "
-                   << bytes_per_sample;
-  }
-}
-
 void AudioBus::CopyTo(AudioBus* dest) const {
   dest->set_is_bitstream_format(is_bitstream_format());
   if (is_bitstream_format()) {
diff --git a/media/base/audio_bus.h b/media/base/audio_bus.h
index 7726302..e128f32 100644
--- a/media/base/audio_bus.h
+++ b/media/base/audio_bus.h
@@ -147,14 +147,6 @@
       int num_frames_to_read,
       typename TargetSampleTypeTraits::ValueType* dest_buffer) const;
 
-  // DEPRECATED (https://crbug.com/580391)
-  // Please use the version templated with TargetSampleTypeTraits instead.
-  // TODO(chfremer): Remove (https://crbug.com/619623)
-  void ToInterleavedPartial(int start_frame,
-                            int frames,
-                            int bytes_per_sample,
-                            void* dest) const;
-
   // Helper method for copying channel data from one AudioBus to another.  Both
   // AudioBus object must have the same frames() and channels().
   void CopyTo(AudioBus* dest) const;
diff --git a/media/base/audio_bus_unittest.cc b/media/base/audio_bus_unittest.cc
index aacafb9..9b21d76 100644
--- a/media/base/audio_bus_unittest.cc
+++ b/media/base/audio_bus_unittest.cc
@@ -558,20 +558,6 @@
            kTestVectorFrameCount * sizeof(*expected->channel(ch)));
   }
 
-  // Test deprecated version that takes |bytes_per_sample| as an input.
-  {
-    SCOPED_TRACE("int16_t");
-    int16_t test_array[base::size(kTestVectorInt16)];
-    expected->ToInterleavedPartial(kPartialStart, kPartialFrames,
-                                   sizeof(*kTestVectorInt16), test_array);
-    ASSERT_EQ(0, memcmp(test_array, kTestVectorInt16 +
-                                        kPartialStart * kTestVectorChannelCount,
-                        kPartialFrames * sizeof(*kTestVectorInt16) *
-                            kTestVectorChannelCount));
-  }
-
-  // Test non-deprecated version that takes SampleTypeTraits as a template
-  // parameter.
   {
     SCOPED_TRACE("Float32SampleTypeTraits");
     float test_array[base::size(kTestVectorFloat32)];
diff --git a/media/cast/receiver/audio_decoder.cc b/media/cast/receiver/audio_decoder.cc
index 9792777..39f56ec6 100644
--- a/media/cast/receiver/audio_decoder.cc
+++ b/media/cast/receiver/audio_decoder.cc
@@ -205,7 +205,8 @@
       pcm_data[i] = static_cast<int16_t>(base::NetToHost16(pcm_data[i]));
 #endif
     audio_bus = AudioBus::Create(num_channels_, num_samples);
-    audio_bus->FromInterleaved(pcm_data, num_samples, sizeof(int16_t));
+    audio_bus->FromInterleaved<SignedInt16SampleTypeTraits>(pcm_data,
+                                                            num_samples);
     return audio_bus;
   }
 
diff --git a/media/cast/receiver/audio_decoder_unittest.cc b/media/cast/receiver/audio_decoder_unittest.cc
index 2c7f12b..2e324d5 100644
--- a/media/cast/receiver/audio_decoder_unittest.cc
+++ b/media/cast/receiver/audio_decoder_unittest.cc
@@ -95,8 +95,8 @@
     // Encode |audio_bus| into |encoded_frame->data|.
     const int num_elements = audio_bus->channels() * audio_bus->frames();
     std::vector<int16_t> interleaved(num_elements);
-    audio_bus->ToInterleaved(audio_bus->frames(), sizeof(int16_t),
-                             &interleaved.front());
+    audio_bus->ToInterleaved<SignedInt16SampleTypeTraits>(audio_bus->frames(),
+                                                          &interleaved.front());
     if (GetParam().codec == CODEC_AUDIO_PCM16) {
       encoded_frame->data.resize(num_elements * sizeof(int16_t));
       int16_t* const pcm_data =
diff --git a/media/cast/sender/audio_encoder.cc b/media/cast/sender/audio_encoder.cc
index 3031912..ade6228 100644
--- a/media/cast/sender/audio_encoder.cc
+++ b/media/cast/sender/audio_encoder.cc
@@ -732,8 +732,8 @@
                                  int source_offset,
                                  int buffer_fill_offset,
                                  int num_samples) final {
-    audio_bus->ToInterleavedPartial(
-        source_offset, num_samples, sizeof(int16_t),
+    audio_bus->ToInterleavedPartial<SignedInt16SampleTypeTraits>(
+        source_offset, num_samples,
         buffer_.get() + buffer_fill_offset * num_channels_);
   }
 
diff --git a/media/gpu/BUILD.gn b/media/gpu/BUILD.gn
index a4ca0aec3..357e51f 100644
--- a/media/gpu/BUILD.gn
+++ b/media/gpu/BUILD.gn
@@ -138,6 +138,8 @@
       "android/promotion_hint_aggregator.h",
       "android/promotion_hint_aggregator_impl.cc",
       "android/promotion_hint_aggregator_impl.h",
+      "android/shared_image_pool.cc",
+      "android/shared_image_pool.h",
       "android/shared_image_video.cc",
       "android/shared_image_video.h",
       "android/surface_chooser_helper.cc",
diff --git a/media/gpu/android/shared_image_pool.cc b/media/gpu/android/shared_image_pool.cc
new file mode 100644
index 0000000..a722d60
--- /dev/null
+++ b/media/gpu/android/shared_image_pool.cc
@@ -0,0 +1,94 @@
+// 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 "media/gpu/android/shared_image_pool.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "gpu/command_buffer/service/shared_image_representation.h"
+#include "media/gpu/command_buffer_helper.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/scoped_make_current.h"
+
+namespace media {
+
+SharedImagePool::SharedImagePool(scoped_refptr<CommandBufferHelper> helper)
+    : helper_(std::move(helper)), weak_factory_(this) {
+  if (helper_) {
+    helper_->SetWillDestroyStubCB(base::BindOnce(
+        &SharedImagePool::OnWillDestroyStub, weak_factory_.GetWeakPtr()));
+  }
+}
+
+SharedImagePool::~SharedImagePool() {
+  // All the refs should have been dropped by this time and pool should be
+  // empty. This is because video frames keep a ref of pool and once all frames
+  // are released, then only pool will get destructed.
+  DCHECK(pool_.empty());
+}
+
+void SharedImagePool::AddSharedImage(
+    std::unique_ptr<gpu::SharedImageRepresentationFactoryRef>
+        shared_image_ref) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(pool_.find(shared_image_ref.get()) == pool_.end());
+  // Don't permit additions after we've lost the stub.
+  // TODO(liberato): consider making this fail gracefully.  However, nobody
+  // should be doing this, so for now it's a DCHECK.
+  DCHECK(helper_);
+  pool_.insert(std::move(shared_image_ref));
+}
+
+void SharedImagePool::ReleaseSharedImage(
+    gpu::SharedImageRepresentationFactoryRef* shared_image_ref,
+    const gpu::SyncToken& sync_token) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+  // If we don't have a sync token, or if we have no stub, then just finish.
+  if (!sync_token.HasData() || !helper_) {
+    OnSyncTokenReleased(shared_image_ref);
+    return;
+  }
+
+  // We keep a strong ref to |this| in the callback, so that we are guaranteed
+  // to receive it.  It's common for the last ref to us to be our caller, as
+  // a callback.  We need to stick around a bit longer than that if there's a
+  // sync token.  Plus, we're required to keep |helper_| around while a wait is
+  // still pending.
+  helper_->WaitForSyncToken(
+      sync_token,
+      base::BindOnce(&SharedImagePool::OnSyncTokenReleased,
+                     scoped_refptr<SharedImagePool>(this), shared_image_ref));
+}
+
+void SharedImagePool::OnSyncTokenReleased(
+    gpu::SharedImageRepresentationFactoryRef* shared_image_ref) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+  // If there is no |helper_|, it means stub has been destroyed and pool has
+  // been already cleared.
+  if (!helper_) {
+    DCHECK(pool_.empty());
+    return;
+  }
+  auto iter = pool_.find(shared_image_ref);
+  DCHECK(iter != pool_.end());
+
+  // Drop the shared_image_ref.  This is safe without the context being current.
+  // It's also safe if the stub has been destroyed.
+  pool_.erase(iter);
+}
+
+void SharedImagePool::OnWillDestroyStub(bool have_context) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(helper_);
+
+  // Clearing the pools clears up all the refs which in turn releases all the
+  // codec buffers.
+  pool_.clear();
+  helper_ = nullptr;
+}
+
+}  // namespace media
diff --git a/media/gpu/android/shared_image_pool.h b/media/gpu/android/shared_image_pool.h
new file mode 100644
index 0000000..ac7307a
--- /dev/null
+++ b/media/gpu/android/shared_image_pool.h
@@ -0,0 +1,81 @@
+// 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 MEDIA_GPU_ANDROID_SHARED_IMAGE_POOL_H_
+#define MEDIA_GPU_ANDROID_SHARED_IMAGE_POOL_H_
+
+#include <memory>
+
+#include "base/containers/flat_set.h"
+#include "base/containers/unique_ptr_adapters.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "gpu/ipc/service/command_buffer_stub.h"
+#include "media/gpu/media_gpu_export.h"
+
+namespace gpu {
+class SharedImageRepresentationFactoryRef;
+}  // namespace gpu
+
+namespace media {
+
+class CommandBufferHelper;
+
+// TODO(vikassoni): This is a temporary class which will go away soon once all
+// the video mailbox consumers switches to using shared image mailbox instead of
+// legacy mailbox. Video frame will have the ownership of shared image ref
+// instead of this shared image pool.
+// SharedImagePool owns shared image ref. Shared image are used to hold decoded
+// video frames. This pool allows shared images to outlive the decoder that
+// created them, since decoders are torn down when the pipeline is suspended,
+// but decoded frames can be on-screen indefinitely.
+class MEDIA_GPU_EXPORT SharedImagePool
+    : public base::RefCounted<SharedImagePool> {
+ public:
+  SharedImagePool(scoped_refptr<CommandBufferHelper> helper);
+
+  // Add a new shared image ref into the pool.  This may only be done before
+  // |stub_| is destroyed.  When |stub_| is destroyed, we will destroy/clear any
+  // refs that are in the pool.
+  void AddSharedImage(std::unique_ptr<gpu::SharedImageRepresentationFactoryRef>
+                          shared_image_ref);
+
+  // Release a shared image ref back into the pool.  |shared_image_ref| must
+  // have been added to the pool previously, and not released.  Otherwise, this
+  // is undefined. Note: since we don't actually pool things, this just forgets
+  // |shared_image_ref|. It's okay if this is called after we've lost |stub_|.
+  // If |sync_token| is not null, then we'll wait for that token before taking
+  // any action.
+  void ReleaseSharedImage(
+      gpu::SharedImageRepresentationFactoryRef* shared_image_ref,
+      const gpu::SyncToken& sync_token);
+
+ protected:
+  virtual ~SharedImagePool();
+
+  // Called after a sync token has been released, to free |shared_image_ref|.
+  void OnSyncTokenReleased(
+      gpu::SharedImageRepresentationFactoryRef* shared_image_ref);
+
+  // Called when |stub_| notifies us that the underlying stub will be destroyed.
+  void OnWillDestroyStub(bool have_context);
+
+ private:
+  friend class base::RefCounted<SharedImagePool>;
+  THREAD_CHECKER(thread_checker_);
+
+  scoped_refptr<CommandBufferHelper> helper_;
+
+  base::flat_set<std::unique_ptr<gpu::SharedImageRepresentationFactoryRef>,
+                 base::UniquePtrComparator>
+      pool_;
+
+  base::WeakPtrFactory<SharedImagePool> weak_factory_;
+};
+
+}  // namespace media
+
+#endif  // MEDIA_GPU_ANDROID_SHARED_IMAGE_POOL_H_
diff --git a/media/gpu/android/video_frame_factory_impl.cc b/media/gpu/android/video_frame_factory_impl.cc
index 06e74b9..b24ed37 100644
--- a/media/gpu/android/video_frame_factory_impl.cc
+++ b/media/gpu/android/video_frame_factory_impl.cc
@@ -11,7 +11,6 @@
 #include "base/bind_helpers.h"
 #include "base/callback.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/single_thread_task_runner.h"
@@ -32,6 +31,7 @@
 #include "media/gpu/android/codec_image.h"
 #include "media/gpu/android/codec_image_group.h"
 #include "media/gpu/android/codec_wrapper.h"
+#include "media/gpu/android/shared_image_pool.h"
 #include "media/gpu/android/shared_image_video.h"
 #include "media/gpu/command_buffer_helper.h"
 #include "mojo/public/cpp/bindings/callback_helpers.h"
@@ -189,6 +189,9 @@
     return nullptr;
   stub_->AddDestructionObserver(this);
 
+  shared_image_pool_ =
+      base::MakeRefCounted<SharedImagePool>(CommandBufferHelper::Create(stub_));
+
   decoder_helper_ = GLES2DecoderHelper::Create(stub_->decoder_context());
 
   gpu::ContextResult result;
@@ -223,30 +226,34 @@
     scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   scoped_refptr<VideoFrame> frame;
+  std::unique_ptr<gpu::SharedImageRepresentationFactoryRef> shared_image_ref;
   CodecImage* codec_image = nullptr;
   CreateVideoFrameInternal(std::move(output_buffer), std::move(texture_owner_),
                            timestamp, natural_size,
-                           std::move(promotion_hint_cb), &frame, &codec_image);
+                           std::move(promotion_hint_cb), &frame,
+                           &shared_image_ref, &codec_image);
   TRACE_EVENT0("media", "GpuVideoFrameFactory::CreateVideoFrame");
-  if (!frame)
+  if (!frame || !shared_image_ref)
     return;
 
   // Try to render this frame if possible.
   internal::MaybeRenderEarly(&images_);
 
-  // This callback destroys the shared image when video frame is
-  // released/destroyed. This callback has a weak pointer to the shared image
-  // stub because shared image stub could be destroyed before video frame. In
-  // those cases there is no need to destroy the shared image as the shared
-  // image stub destruction will cause all the shared images to be destroyed.
-  auto destroy_shared_image =
-      stub_->channel()->shared_image_stub()->GetSharedImageDestructionCallback(
-          frame->mailbox_holder(0).mailbox);
+  // Note that this keeps the pool around while any texture is.
+  auto drop_shared_image_ref = base::BindOnce(
+      [](scoped_refptr<SharedImagePool> shared_image_pool,
+         gpu::SharedImageRepresentationFactoryRef* shared_image_ref,
+         const gpu::SyncToken& sync_token) {
+        shared_image_pool->ReleaseSharedImage(shared_image_ref, sync_token);
+      },
+      shared_image_pool_, base::Unretained(shared_image_ref.get()));
 
-  // Guarantee that the SharedImage is destroyed even if the VideoFrame is
-  // dropped. Otherwise we could keep shared images we don't need alive.
+  shared_image_pool_->AddSharedImage(std::move(shared_image_ref));
+
+  // Guarantee that the SharedImageRef is released even if the VideoFrame is
+  // dropped. Otherwise we could keep TextureRefs we don't need alive.
   auto release_cb = mojo::WrapCallbackWithDefaultInvokeIfNotRun(
-      BindToCurrentLoop(std::move(destroy_shared_image)), gpu::SyncToken());
+      BindToCurrentLoop(std::move(drop_shared_image_ref)), gpu::SyncToken());
   frame->SetReleaseMailboxCB(std::move(release_cb));
   task_runner->PostTask(FROM_HERE,
                         base::BindOnce(std::move(output_cb), std::move(frame)));
@@ -259,6 +266,8 @@
     gfx::Size natural_size,
     PromotionHintAggregator::NotifyPromotionHintCB promotion_hint_cb,
     scoped_refptr<VideoFrame>* video_frame_out,
+    std::unique_ptr<gpu::SharedImageRepresentationFactoryRef>*
+        shared_image_ref_out,
     CodecImage** codec_image_out) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   if (!MakeContextCurrent(stub_))
@@ -333,12 +342,17 @@
       std::move(texture), std::move(shared_context),
       false /* is_thread_safe */);
 
-  // Register it with shared image mailbox as well as legacy mailbox.
-  // NOTE: Currently none of the video mailbox consumer uses shared image
-  // mailbox.
+  // Register it with shared image mailbox.
   DCHECK(stub_->channel()->gpu_channel_manager()->shared_image_manager());
-  stub_->channel()->shared_image_stub()->factory()->RegisterBacking(
-      std::move(shared_image), /* legacy_mailbox */ true);
+  std::unique_ptr<gpu::SharedImageRepresentationFactoryRef> shared_image_ref =
+      stub_->channel()->gpu_channel_manager()->shared_image_manager()->Register(
+          std::move(shared_image),
+          stub_->channel()->shared_image_stub()->factory()->memory_tracker());
+
+  // Register it with legacy mailbox.
+  // NOTE: All the video mailbox consumers are using legacy mailbox as of now.
+  shared_image_ref->ProduceLegacyMailbox(
+      stub_->channel()->gpu_channel_manager()->mailbox_manager());
 
   gpu::MailboxHolder mailbox_holders[VideoFrame::kMaxPlanes];
   mailbox_holders[0] =
@@ -378,6 +392,7 @@
                                 !!texture_owner_);
 
   *video_frame_out = std::move(frame);
+  *shared_image_ref_out = std::move(shared_image_ref);
 }
 
 void GpuVideoFrameFactory::OnWillDestroyStub(bool have_context) {
diff --git a/media/gpu/android/video_frame_factory_impl.h b/media/gpu/android/video_frame_factory_impl.h
index e6d4918c..85c91db 100644
--- a/media/gpu/android/video_frame_factory_impl.h
+++ b/media/gpu/android/video_frame_factory_impl.h
@@ -26,6 +26,7 @@
 namespace media {
 class CodecImageGroup;
 class GpuVideoFrameFactory;
+class SharedImagePool;
 
 // VideoFrameFactoryImpl creates CodecOutputBuffer backed VideoFrames and tries
 // to eagerly render them to their surface to release the buffers back to the
@@ -99,6 +100,8 @@
       gfx::Size natural_size,
       PromotionHintAggregator::NotifyPromotionHintCB promotion_hint_cb,
       scoped_refptr<VideoFrame>* video_frame_out,
+      std::unique_ptr<gpu::SharedImageRepresentationFactoryRef>*
+          shared_image_ref_out,
       CodecImage** codec_image_out);
 
   void OnWillDestroyStub(bool have_context) override;
@@ -124,6 +127,9 @@
   // replace this when SetImageGroup() is called.
   scoped_refptr<CodecImageGroup> image_group_;
 
+  // Pool which owns all the shared image refs that we create.
+  scoped_refptr<SharedImagePool> shared_image_pool_;
+
   THREAD_CHECKER(thread_checker_);
   base::WeakPtrFactory<GpuVideoFrameFactory> weak_factory_;
   DISALLOW_COPY_AND_ASSIGN(GpuVideoFrameFactory);
diff --git a/media/gpu/image_processor_test.cc b/media/gpu/image_processor_test.cc
index 4349a2e..b6829117 100644
--- a/media/gpu/image_processor_test.cc
+++ b/media/gpu/image_processor_test.cc
@@ -62,15 +62,14 @@
     // TODO(crbug.com/917951): Select more appropriate number of buffers.
     constexpr size_t kNumBuffers = 1;
     LOG_ASSERT(output_image.IsMetadataLoaded());
+    std::vector<std::unique_ptr<test::VideoFrameProcessor>> frame_processors;
     // TODO(crbug.com/944823): Use VideoFrameValidator for RGB formats.
-    std::unique_ptr<test::VideoFrameValidator> vf_validator;
     if (IsYuvPlanar(input_image.PixelFormat()) &&
         IsYuvPlanar(output_image.PixelFormat())) {
-      vf_validator = test::VideoFrameValidator::Create(
+      auto vf_validator = test::VideoFrameValidator::Create(
           {output_image.Checksum()}, output_image.PixelFormat());
+      frame_processors.push_back(std::move(vf_validator));
     }
-    std::vector<std::unique_ptr<test::VideoFrameProcessor>> frame_processors;
-    frame_processors.push_back(std::move(vf_validator));
     auto ip_client = test::ImageProcessorClient::Create(
         input_config, output_config, kNumBuffers, std::move(frame_processors));
     LOG_ASSERT(ip_client) << "Failed to create ImageProcessorClient";
diff --git a/media/gpu/libyuv_image_processor.cc b/media/gpu/libyuv_image_processor.cc
index 43ada7f..3bc9b2a 100644
--- a/media/gpu/libyuv_image_processor.cc
+++ b/media/gpu/libyuv_image_processor.cc
@@ -9,10 +9,43 @@
 #include "base/memory/ptr_util.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/gpu/macros.h"
-#include "third_party/libyuv/include/libyuv/convert_from.h"
+#include "third_party/libyuv/include/libyuv/convert.h"
 
 namespace media {
 
+namespace {
+
+enum class SupportResult {
+  Supported,
+  SupportedWithPivot,
+  Unsupported,
+};
+
+SupportResult IsFormatSupported(VideoPixelFormat input_format,
+                                VideoPixelFormat output_format) {
+  constexpr struct {
+    VideoPixelFormat input;
+    VideoPixelFormat output;
+    bool need_pivot;
+  } kSupportFormatConversionArray[] = {
+      {PIXEL_FORMAT_I420, PIXEL_FORMAT_NV12, false},
+      {PIXEL_FORMAT_YV12, PIXEL_FORMAT_NV12, false},
+      {PIXEL_FORMAT_RGB32, PIXEL_FORMAT_NV12, true},
+  };
+
+  for (auto* conv = std::cbegin(kSupportFormatConversionArray);
+       conv != std::cend(kSupportFormatConversionArray); conv++) {
+    if (conv->input == input_format && conv->output == output_format) {
+      return conv->need_pivot ? SupportResult::SupportedWithPivot
+                              : SupportResult::Supported;
+    }
+  }
+
+  return SupportResult::Unsupported;
+}
+
+}  // namespace
+
 LibYUVImageProcessor::LibYUVImageProcessor(
     const VideoFrameLayout& input_layout,
     const gfx::Size& input_visible_size,
@@ -45,14 +78,6 @@
     const ImageProcessor::OutputMode output_mode,
     ErrorCB error_cb) {
   VLOGF(2);
-
-  if (!IsFormatSupported(input_config.layout.format(),
-                         output_config.layout.format())) {
-    VLOGF(2) << "Conversion from " << input_config.layout.format() << " to "
-             << output_config.layout.format() << " is not supported";
-    return nullptr;
-  }
-
   // LibYUVImageProcessor supports only memory-based video frame for input.
   VideoFrame::StorageType input_storage_type = VideoFrame::STORAGE_UNKNOWN;
   for (auto input_type : input_config.preferred_storage_types) {
@@ -84,10 +109,29 @@
     return nullptr;
   }
 
+  SupportResult res = IsFormatSupported(input_config.layout.format(),
+                                        output_config.layout.format());
+  if (res == SupportResult::Unsupported) {
+    VLOGF(2) << "Conversion from " << input_config.layout.format() << " to "
+             << output_config.layout.format() << " is not supported";
+    return nullptr;
+  }
+
   auto processor = base::WrapUnique(new LibYUVImageProcessor(
       input_config.layout, input_config.visible_size, input_storage_type,
       output_config.layout, output_config.visible_size, output_storage_type,
       media::BindToCurrentLoop(std::move(error_cb))));
+  if (res == SupportResult::SupportedWithPivot) {
+    processor->intermediate_frame_ =
+        VideoFrame::CreateFrame(PIXEL_FORMAT_I420, input_config.visible_size,
+                                gfx::Rect(input_config.visible_size),
+                                input_config.visible_size, base::TimeDelta());
+    if (!processor->intermediate_frame_) {
+      VLOGF(1) << "Failed to create intermediate frame";
+      return nullptr;
+    }
+  }
+
   if (!processor->process_thread_.Start()) {
     VLOGF(1) << "Failed to start processing thread";
     return nullptr;
@@ -158,28 +202,6 @@
   error_cb_.Run();
 }
 
-// static
-bool LibYUVImageProcessor::IsFormatSupported(VideoPixelFormat input_format,
-                                             VideoPixelFormat output_format) {
-  constexpr struct {
-    VideoPixelFormat input;
-    VideoPixelFormat output;
-  } kSupportFormatConversionArray[] = {
-      {PIXEL_FORMAT_I420, PIXEL_FORMAT_NV12},
-      {PIXEL_FORMAT_YV12, PIXEL_FORMAT_NV12},
-  };
-
-  for (auto* conv = std::cbegin(kSupportFormatConversionArray);
-       conv != std::cend(kSupportFormatConversionArray); conv++) {
-    if (conv->input == input_format && conv->output == output_format)
-      return true;
-  }
-
-  VLOGF(2) << "Unsupported conversion: input=" << input_format
-           << ", output=" << output_format;
-  return false;
-}
-
 int LibYUVImageProcessor::DoConversion(const VideoFrame* const input,
                                        VideoFrame* const output) {
   DCHECK(process_thread_.task_runner()->BelongsToCurrentThread());
@@ -198,6 +220,9 @@
   fr->data(VideoFrame::kYPlane), fr->stride(VideoFrame::kYPlane), \
       fr->data(VideoFrame::kUVPlane), fr->stride(VideoFrame::kUVPlane)
 
+#define RGB_DATA(fr) \
+  fr->data(VideoFrame::kARGBPlane), fr->stride(VideoFrame::kARGBPlane)
+
 #define LIBYUV_FUNC(func, i, o)                      \
   libyuv::func(i, o, output->visible_rect().width(), \
                output->visible_rect().height())
@@ -208,13 +233,27 @@
         return LIBYUV_FUNC(I420ToNV12, Y_U_V_DATA(input), Y_UV_DATA(output));
       case PIXEL_FORMAT_YV12:
         return LIBYUV_FUNC(I420ToNV12, Y_V_U_DATA(input), Y_UV_DATA(output));
+
+      // RGB conversions. NOTE: Libyuv functions called here are named in
+      // little-endian manner.
+      case PIXEL_FORMAT_RGB32:
+        // There is no libyuv function to convert to RGBA to NV12. Therefore, we
+        // convert RGBA to I420 tentatively and thereafter convert the tentative
+        // one to NV12.
+        LIBYUV_FUNC(ABGRToI420, RGB_DATA(input),
+                    Y_U_V_DATA(intermediate_frame_));
+        return LIBYUV_FUNC(I420ToNV12, Y_U_V_DATA(intermediate_frame_),
+                           Y_UV_DATA(output));
       default:
         VLOGF(1) << "Unexpected input format: " << input->format();
         return -1;
     }
   }
+
 #undef Y_U_V_DATA
+#undef Y_V_U_DATA
 #undef Y_UV_DATA
+#undef RGB_DATA
 #undef LIBYUV_FUNC
 
   VLOGF(1) << "Unexpected output format: " << output->format();
diff --git a/media/gpu/libyuv_image_processor.h b/media/gpu/libyuv_image_processor.h
index 61ebe71a..57f8038 100644
--- a/media/gpu/libyuv_image_processor.h
+++ b/media/gpu/libyuv_image_processor.h
@@ -70,15 +70,16 @@
 
   void NotifyError();
 
-  static bool IsFormatSupported(VideoPixelFormat input_format,
-                                VideoPixelFormat output_format);
-
   // Execute Libyuv function for the conversion from |input| to |output|.
   int DoConversion(const VideoFrame* const input, VideoFrame* const output);
 
   const gfx::Rect input_visible_rect_;
   const gfx::Rect output_visible_rect_;
 
+  // A VideoFrame for intermediate format conversion when there is no direct
+  // conversion method in libyuv, e.g., RGBA -> I420 (pivot) -> NV12.
+  scoped_refptr<VideoFrame> intermediate_frame_;
+
   // Error callback to the client.
   ErrorCB error_cb_;
 
diff --git a/media/gpu/linux/OWNERS b/media/gpu/linux/OWNERS
new file mode 100644
index 0000000..113b8608
--- /dev/null
+++ b/media/gpu/linux/OWNERS
@@ -0,0 +1,3 @@
+acourbot@chromium.org
+dstaessens@chromium.org
+hiroh@chromium.org
\ No newline at end of file
diff --git a/media/gpu/test/BUILD.gn b/media/gpu/test/BUILD.gn
index 73d65c09..1b68a08 100644
--- a/media/gpu/test/BUILD.gn
+++ b/media/gpu/test/BUILD.gn
@@ -154,8 +154,6 @@
       "video_player/test_vda_video_decoder.h",
       "video_player/video.cc",
       "video_player/video.h",
-      "video_player/video_collection.cc",
-      "video_player/video_collection.h",
       "video_player/video_decoder_client.cc",
       "video_player/video_decoder_client.h",
       "video_player/video_player.cc",
diff --git a/media/gpu/test/OWNERS b/media/gpu/test/OWNERS
new file mode 100644
index 0000000..f2b8fd7a
--- /dev/null
+++ b/media/gpu/test/OWNERS
@@ -0,0 +1,2 @@
+dstaessens@chromium.org
+hiroh@chromium.org
\ No newline at end of file
diff --git a/media/gpu/test/video_player/test_vda_video_decoder.cc b/media/gpu/test/video_player/test_vda_video_decoder.cc
index bfa1a5b..735e00aa 100644
--- a/media/gpu/test/video_player/test_vda_video_decoder.cc
+++ b/media/gpu/test/video_player/test_vda_video_decoder.cc
@@ -43,6 +43,8 @@
   weak_this_ = weak_this_factory_.GetWeakPtr();
 }
 
+TestVDAVideoDecoder::~TestVDAVideoDecoder() = default;
+
 void TestVDAVideoDecoder::Destroy() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(vda_wrapper_sequence_checker_);
 
@@ -55,6 +57,14 @@
   frame_renderer_->ReleaseGLContext();
 }
 
+std::string TestVDAVideoDecoder::GetDisplayName() const {
+  return "TestVDAVideoDecoder";
+}
+
+bool TestVDAVideoDecoder::IsPlatformDecoder() const {
+  return true;
+}
+
 void TestVDAVideoDecoder::Initialize(const VideoDecoderConfig& config,
                                      bool low_delay,
                                      CdmContext* cdm_context,
@@ -134,6 +144,18 @@
   decoder_->Reset();
 }
 
+bool TestVDAVideoDecoder::NeedsBitstreamConversion() const {
+  return false;
+}
+
+bool TestVDAVideoDecoder::CanReadWithoutStalling() const {
+  return true;
+}
+
+int TestVDAVideoDecoder::GetMaxDecodeRequests() const {
+  return 4;
+}
+
 void TestVDAVideoDecoder::ProvidePictureBuffers(
     uint32_t requested_num_of_buffers,
     VideoPixelFormat pixel_format,
diff --git a/media/gpu/test/video_player/test_vda_video_decoder.h b/media/gpu/test/video_player/test_vda_video_decoder.h
index 29cbf11..ba4aa930 100644
--- a/media/gpu/test/video_player/test_vda_video_decoder.h
+++ b/media/gpu/test/video_player/test_vda_video_decoder.h
@@ -36,10 +36,11 @@
   TestVDAVideoDecoder(AllocationMode allocation_mode,
                       const gfx::ColorSpace& target_color_space,
                       FrameRenderer* const frame_renderer);
+  ~TestVDAVideoDecoder() override;
 
   // media::VideoDecoder implementation
-  std::string GetDisplayName() const override { return "TestVDAVideoDecoder"; }
-  bool IsPlatformDecoder() const override { return true; }
+  std::string GetDisplayName() const override;
+  bool IsPlatformDecoder() const override;
   void Initialize(const VideoDecoderConfig& config,
                   bool low_delay,
                   CdmContext* cdm_context,
@@ -49,9 +50,9 @@
   void Decode(scoped_refptr<DecoderBuffer> buffer,
               const DecodeCB& decode_cb) override;
   void Reset(const base::RepeatingClosure& reset_cb) override;
-  bool NeedsBitstreamConversion() const override { return false; }
-  bool CanReadWithoutStalling() const override { return true; }
-  int GetMaxDecodeRequests() const override { return 4; }
+  bool NeedsBitstreamConversion() const override;
+  bool CanReadWithoutStalling() const override;
+  int GetMaxDecodeRequests() const override;
 
  private:
   void Destroy() override;
diff --git a/media/gpu/test/video_player/video_collection.cc b/media/gpu/test/video_player/video_collection.cc
deleted file mode 100644
index 03bd997..0000000
--- a/media/gpu/test/video_player/video_collection.cc
+++ /dev/null
@@ -1,56 +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 "media/gpu/test/video_player/video_collection.h"
-
-#include <utility>
-
-#include "media/gpu/test/video_player/video.h"
-
-namespace media {
-namespace test {
-
-constexpr base::FilePath::CharType kTestVideoH264[] = "test-25fps.h264";
-constexpr base::FilePath::CharType kTestVideoVP8[] = "test-25fps.vp8";
-constexpr base::FilePath::CharType kTestVideoVP9[] = "test-25fps.vp9";
-
-const VideoCollection kDefaultTestVideoCollection =
-    std::move(VideoCollection()
-                  .Add(std::make_unique<Video>(base::FilePath(kTestVideoH264)))
-                  .Add(std::make_unique<Video>(base::FilePath(kTestVideoVP8)))
-                  .Add(std::make_unique<Video>(base::FilePath(kTestVideoVP9))));
-
-VideoCollection::VideoCollection() {}
-
-VideoCollection::~VideoCollection() {}
-
-VideoCollection::VideoCollection(VideoCollection&& other) {
-  video_collection_ = std::move(other.video_collection_);
-}
-
-VideoCollection& VideoCollection::Add(std::unique_ptr<Video> video) {
-  video_collection_.push_back(std::move(video));
-  return *this;
-}
-
-const Video& VideoCollection::operator[](size_t index) const {
-  CHECK_LT(index, video_collection_.size());
-  Video* video = video_collection_.at(index).get();
-
-  // Only load video when actually requested, to avoid loading all videos in the
-  // collection, even when only a single video is needed.
-  if (!video->IsLoaded()) {
-    bool loaded = video->Load();
-    LOG_IF(FATAL, !loaded) << "Loading video failed";
-  }
-
-  return *video;
-}
-
-size_t VideoCollection::Size() const {
-  return video_collection_.size();
-}
-
-}  // namespace test
-}  // namespace media
diff --git a/media/gpu/test/video_player/video_collection.h b/media/gpu/test/video_player/video_collection.h
deleted file mode 100644
index e8a52bb..0000000
--- a/media/gpu/test/video_player/video_collection.h
+++ /dev/null
@@ -1,56 +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 MEDIA_GPU_TEST_VIDEO_PLAYER_VIDEO_COLLECTION_H_
-#define MEDIA_GPU_TEST_VIDEO_PLAYER_VIDEO_COLLECTION_H_
-
-#include <stdint.h>
-#include <memory>
-#include <vector>
-
-#include "base/macros.h"
-
-namespace media {
-namespace test {
-
-class Video;
-
-// The video collection class helps managing different sets of test videos.
-// Multiple test video collections can be maintained:
-// * A collection of lightweight videos for CQ testing.
-// * A collection of large video files for performance testing.
-// * A set of corrupt videos to test decoder stability.
-// * A set of small generated video files with various properties.
-// TODO(dstaessens@):
-// * Add functionality to fetch video by codec/resolution/name/...
-// * Add a collection of videos to test different codecs.
-// * Add a collection of videos to test various resolutions.
-// * Add a collection of lightweight videos (defined directly in code?).
-class VideoCollection {
- public:
-  VideoCollection();
-  ~VideoCollection();
-  VideoCollection(VideoCollection&& other);
-
-  // Add a video to the collection, this will transfer ownership.
-  VideoCollection& Add(std::unique_ptr<Video> video);
-
-  // Get the video with specified index from the collection.
-  const Video& operator[](size_t index) const;
-
-  size_t Size() const;
-
- private:
-  std::vector<std::unique_ptr<Video>> video_collection_;
-
-  DISALLOW_COPY_AND_ASSIGN(VideoCollection);
-};
-
-// The default video test file collection
-extern const VideoCollection kDefaultTestVideoCollection;
-
-}  // namespace test
-}  // namespace media
-
-#endif  // MEDIA_GPU_TEST_VIDEO_PLAYER_VIDEO_COLLECTION_H_
diff --git a/media/gpu/test/video_player/video_player_test_environment.cc b/media/gpu/test/video_player/video_player_test_environment.cc
index 974ca91a..5589a5b2 100644
--- a/media/gpu/test/video_player/video_player_test_environment.cc
+++ b/media/gpu/test/video_player/video_player_test_environment.cc
@@ -4,6 +4,8 @@
 
 #include "media/gpu/test/video_player/video_player_test_environment.h"
 
+#include <utility>
+
 #include "base/command_line.h"
 #include "base/test/test_timeouts.h"
 #include "media/gpu/buildflags.h"
@@ -21,8 +23,35 @@
 
 namespace media {
 namespace test {
-VideoPlayerTestEnvironment::VideoPlayerTestEnvironment(const Video* video)
-    : video_(video) {}
+
+// Default video to be used if no test video was specified.
+constexpr base::FilePath::CharType kDefaultTestVideoPath[] = "test-25fps.h264";
+
+// static
+VideoPlayerTestEnvironment* VideoPlayerTestEnvironment::Create(
+    const base::FilePath& video_path,
+    bool enable_validator,
+    bool output_frames) {
+  auto video = std::make_unique<media::test::Video>(
+      video_path.empty() ? base::FilePath(kDefaultTestVideoPath) : video_path);
+  if (!video->Load()) {
+    LOG(ERROR) << "Failed to load " << video_path;
+    return nullptr;
+  }
+
+  return new VideoPlayerTestEnvironment(std::move(video), enable_validator,
+                                        output_frames);
+}
+
+VideoPlayerTestEnvironment::VideoPlayerTestEnvironment(
+    std::unique_ptr<media::test::Video> video,
+    bool enable_validator,
+    bool output_frames)
+    : video_(std::move(video)),
+      enable_validator_(enable_validator),
+      output_frames_(output_frames) {}
+
+VideoPlayerTestEnvironment::~VideoPlayerTestEnvironment() = default;
 
 void VideoPlayerTestEnvironment::SetUp() {
   // Using shared memory requires mojo to be initialized (crbug.com/849207).
@@ -68,5 +97,18 @@
 void VideoPlayerTestEnvironment::TearDown() {
   task_environment_.reset();
 }
+
+const media::test::Video* VideoPlayerTestEnvironment::Video() const {
+  return video_.get();
+}
+
+bool VideoPlayerTestEnvironment::IsValidatorEnabled() const {
+  return enable_validator_;
+}
+
+bool VideoPlayerTestEnvironment::IsFramesOutputEnabled() const {
+  return output_frames_;
+}
+
 }  // namespace test
 }  // namespace media
diff --git a/media/gpu/test/video_player/video_player_test_environment.h b/media/gpu/test/video_player/video_player_test_environment.h
index 014e9700..358f8f5 100644
--- a/media/gpu/test/video_player/video_player_test_environment.h
+++ b/media/gpu/test/video_player/video_player_test_environment.h
@@ -26,19 +26,33 @@
 // the entire test run.
 class VideoPlayerTestEnvironment : public ::testing::Environment {
  public:
-  explicit VideoPlayerTestEnvironment(const Video* video);
+  static VideoPlayerTestEnvironment* Create(const base::FilePath& video_path,
+                                            bool enable_validator,
+                                            bool output_frames);
+  ~VideoPlayerTestEnvironment() override;
 
   // Set up the video decode test environment, only called once.
   void SetUp() override;
   // Tear down the video decode test environment, only called once.
   void TearDown() override;
 
-  std::unique_ptr<base::test::ScopedTaskEnvironment> task_environment_;
-  const Video* video_ = nullptr;
-  bool enable_validator_ = true;
-  bool output_frames_ = false;
+  // Get the video the tests will be ran on.
+  const media::test::Video* Video() const;
+  // Check whether frame validation is enabled.
+  bool IsValidatorEnabled() const;
+  // Check whether outputting frames is enabled.
+  bool IsFramesOutputEnabled() const;
 
  private:
+  VideoPlayerTestEnvironment(std::unique_ptr<media::test::Video> video,
+                             bool enable_validator,
+                             bool output_frames);
+
+  std::unique_ptr<base::test::ScopedTaskEnvironment> task_environment_;
+  const std::unique_ptr<media::test::Video> video_;
+  const bool enable_validator_;
+  const bool output_frames_;
+
   // An exit manager is required to run callbacks on shutdown.
   base::AtExitManager at_exit_manager;
 
diff --git a/media/gpu/video_decode_accelerator_perf_tests.cc b/media/gpu/video_decode_accelerator_perf_tests.cc
index b1e51e14..db82195 100644
--- a/media/gpu/video_decode_accelerator_perf_tests.cc
+++ b/media/gpu/video_decode_accelerator_perf_tests.cc
@@ -9,7 +9,6 @@
 #include "media/base/test_data_util.h"
 #include "media/gpu/test/video_player/frame_renderer_dummy.h"
 #include "media/gpu/test/video_player/video.h"
-#include "media/gpu/test/video_player/video_collection.h"
 #include "media/gpu/test/video_player/video_decoder_client.h"
 #include "media/gpu/test/video_player/video_player.h"
 #include "media/gpu/test/video_player/video_player_test_environment.h"
@@ -162,7 +161,7 @@
 // TODO(dstaessens@) Add a test to measure capped decode performance, measuring
 // the number of frames dropped.
 TEST_F(VideoDecoderTest, MeasureUncappedPerfomance) {
-  auto tvp = CreateVideoPlayer(g_env->video_);
+  auto tvp = CreateVideoPlayer(g_env->Video());
 
   performance_evaluator_->StartMeasuring();
   tvp->Play();
@@ -171,7 +170,7 @@
   performance_evaluator_->WriteMetricsToFile();
 
   EXPECT_EQ(tvp->GetFlushDoneCount(), 1u);
-  EXPECT_EQ(tvp->GetFrameDecodedCount(), g_env->video_->NumFrames());
+  EXPECT_EQ(tvp->GetFrameDecodedCount(), g_env->Video()->NumFrames());
 }
 
 }  // namespace test
@@ -181,14 +180,23 @@
   testing::InitGoogleTest(&argc, argv);
   base::CommandLine::Init(argc, argv);
 
+  // Check if a video was specified on the command line.
+  const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
+  base::CommandLine::StringVector args = cmd_line->GetArgs();
+  base::FilePath video_path =
+      (args.size() >= 1) ? base::FilePath(args[0]) : base::FilePath();
+
   // Set the default test data path.
   media::test::Video::SetTestDataPath(media::GetTestDataPath());
 
-  // Set up our test environment
+  // Set up our test environment.
+  media::test::VideoPlayerTestEnvironment* test_environment =
+      media::test::VideoPlayerTestEnvironment::Create(video_path, false, false);
+  if (!test_environment)
+    return 0;
+
   media::test::g_env = static_cast<media::test::VideoPlayerTestEnvironment*>(
-      testing::AddGlobalTestEnvironment(
-          new media::test::VideoPlayerTestEnvironment(
-              &media::test::kDefaultTestVideoCollection[0])));
+      testing::AddGlobalTestEnvironment(test_environment));
 
   return RUN_ALL_TESTS();
 }
diff --git a/media/gpu/video_decode_accelerator_tests.cc b/media/gpu/video_decode_accelerator_tests.cc
index 72af438..bbf385b 100644
--- a/media/gpu/video_decode_accelerator_tests.cc
+++ b/media/gpu/video_decode_accelerator_tests.cc
@@ -9,7 +9,6 @@
 #include "media/gpu/test/video_player/frame_renderer_dummy.h"
 #include "media/gpu/test/video_player/frame_renderer_thumbnail.h"
 #include "media/gpu/test/video_player/video.h"
-#include "media/gpu/test/video_player/video_collection.h"
 #include "media/gpu/test/video_player/video_decoder_client.h"
 #include "media/gpu/test/video_player/video_player.h"
 #include "media/gpu/test/video_player/video_player_test_environment.h"
@@ -48,13 +47,13 @@
     std::vector<std::unique_ptr<VideoFrameProcessor>> frame_processors;
 
     // Validate decoded video frames.
-    if (g_env->enable_validator_) {
+    if (g_env->IsValidatorEnabled()) {
       frame_processors.push_back(
           media::test::VideoFrameValidator::Create(video->FrameChecksums()));
     }
 
     // Write decoded video frames to the 'video_frames/<test_name/>' folder.
-    if (g_env->output_frames_) {
+    if (g_env->IsFramesOutputEnabled()) {
       const ::testing::TestInfo* const test_info =
           ::testing::UnitTest::GetInstance()->current_test_info();
       base::FilePath output_folder =
@@ -73,19 +72,19 @@
 // Play video from start to end. Wait for the kFlushDone event at the end of the
 // stream, that notifies us all frames have been decoded.
 TEST_F(VideoDecoderTest, FlushAtEndOfStream) {
-  auto tvp = CreateVideoPlayer(g_env->video_);
+  auto tvp = CreateVideoPlayer(g_env->Video());
 
   tvp->Play();
   EXPECT_TRUE(tvp->WaitForFlushDone());
 
   EXPECT_EQ(tvp->GetFlushDoneCount(), 1u);
-  EXPECT_EQ(tvp->GetFrameDecodedCount(), g_env->video_->NumFrames());
+  EXPECT_EQ(tvp->GetFrameDecodedCount(), g_env->Video()->NumFrames());
   EXPECT_TRUE(tvp->WaitForFrameProcessors());
 }
 
 // Flush the decoder immediately after initialization.
 TEST_F(VideoDecoderTest, FlushAfterInitialize) {
-  auto tvp = CreateVideoPlayer(g_env->video_);
+  auto tvp = CreateVideoPlayer(g_env->Video());
 
   tvp->Flush();
   EXPECT_TRUE(tvp->WaitForFlushDone());
@@ -93,13 +92,13 @@
   EXPECT_TRUE(tvp->WaitForFlushDone());
 
   EXPECT_EQ(tvp->GetFlushDoneCount(), 2u);
-  EXPECT_EQ(tvp->GetFrameDecodedCount(), g_env->video_->NumFrames());
+  EXPECT_EQ(tvp->GetFrameDecodedCount(), g_env->Video()->NumFrames());
   EXPECT_TRUE(tvp->WaitForFrameProcessors());
 }
 
 // Reset the decoder immediately after initialization.
 TEST_F(VideoDecoderTest, ResetAfterInitialize) {
-  auto tvp = CreateVideoPlayer(g_env->video_);
+  auto tvp = CreateVideoPlayer(g_env->Video());
 
   tvp->Reset();
   EXPECT_TRUE(tvp->WaitForResetDone());
@@ -108,16 +107,16 @@
 
   EXPECT_EQ(tvp->GetResetDoneCount(), 1u);
   EXPECT_EQ(tvp->GetFlushDoneCount(), 1u);
-  EXPECT_EQ(tvp->GetFrameDecodedCount(), g_env->video_->NumFrames());
+  EXPECT_EQ(tvp->GetFrameDecodedCount(), g_env->Video()->NumFrames());
   EXPECT_TRUE(tvp->WaitForFrameProcessors());
 }
 
 // Reset the decoder when the middle of the stream is reached.
 TEST_F(VideoDecoderTest, ResetMidStream) {
-  auto tvp = CreateVideoPlayer(g_env->video_);
+  auto tvp = CreateVideoPlayer(g_env->Video());
 
   tvp->Play();
-  EXPECT_TRUE(tvp->WaitForFrameDecoded(g_env->video_->NumFrames() / 2));
+  EXPECT_TRUE(tvp->WaitForFrameDecoded(g_env->Video()->NumFrames() / 2));
   tvp->Reset();
   EXPECT_TRUE(tvp->WaitForResetDone());
   size_t numFramesDecoded = tvp->GetFrameDecodedCount();
@@ -127,17 +126,17 @@
   EXPECT_EQ(tvp->GetResetDoneCount(), 1u);
   EXPECT_EQ(tvp->GetFlushDoneCount(), 1u);
   EXPECT_EQ(tvp->GetFrameDecodedCount(),
-            numFramesDecoded + g_env->video_->NumFrames());
+            numFramesDecoded + g_env->Video()->NumFrames());
   EXPECT_TRUE(tvp->WaitForFrameProcessors());
 }
 
 // Reset the decoder when the end of the stream is reached.
 TEST_F(VideoDecoderTest, ResetEndOfStream) {
-  auto tvp = CreateVideoPlayer(g_env->video_);
+  auto tvp = CreateVideoPlayer(g_env->Video());
 
   tvp->Play();
   EXPECT_TRUE(tvp->WaitForFlushDone());
-  EXPECT_EQ(tvp->GetFrameDecodedCount(), g_env->video_->NumFrames());
+  EXPECT_EQ(tvp->GetFrameDecodedCount(), g_env->Video()->NumFrames());
   tvp->Reset();
   EXPECT_TRUE(tvp->WaitForResetDone());
   tvp->Play();
@@ -145,14 +144,14 @@
 
   EXPECT_EQ(tvp->GetResetDoneCount(), 1u);
   EXPECT_EQ(tvp->GetFlushDoneCount(), 2u);
-  EXPECT_EQ(tvp->GetFrameDecodedCount(), g_env->video_->NumFrames() * 2);
+  EXPECT_EQ(tvp->GetFrameDecodedCount(), g_env->Video()->NumFrames() * 2);
   EXPECT_TRUE(tvp->WaitForFrameProcessors());
 }
 
 // Reset the decoder immediately when the end-of-stream flush starts, without
 // waiting for a kFlushDone event.
 TEST_F(VideoDecoderTest, ResetBeforeFlushDone) {
-  auto tvp = CreateVideoPlayer(g_env->video_);
+  auto tvp = CreateVideoPlayer(g_env->Video());
 
   // Reset when a kFlushing event is received.
   tvp->Play();
@@ -167,7 +166,7 @@
   // have been dropped.
   EXPECT_LE(tvp->GetFlushDoneCount(), 1u);
   EXPECT_EQ(tvp->GetResetDoneCount(), 1u);
-  EXPECT_LE(tvp->GetFrameDecodedCount(), g_env->video_->NumFrames());
+  EXPECT_LE(tvp->GetFrameDecodedCount(), g_env->Video()->NumFrames());
   EXPECT_TRUE(tvp->WaitForFrameProcessors());
 }
 
@@ -175,11 +174,11 @@
 // H.264 video stream. After resetting the video is played until the end.
 TEST_F(VideoDecoderTest, ResetAfterFirstConfigInfo) {
   // This test is only relevant for H.264 video streams.
-  if (g_env->video_->Profile() < H264PROFILE_MIN ||
-      g_env->video_->Profile() > H264PROFILE_MAX)
+  if (g_env->Video()->Profile() < H264PROFILE_MIN ||
+      g_env->Video()->Profile() > H264PROFILE_MAX)
     GTEST_SKIP();
 
-  auto tvp = CreateVideoPlayer(g_env->video_);
+  auto tvp = CreateVideoPlayer(g_env->Video());
 
   tvp->PlayUntil(VideoPlayerEvent::kConfigInfo);
   EXPECT_TRUE(tvp->WaitForEvent(VideoPlayerEvent::kConfigInfo));
@@ -192,7 +191,7 @@
   EXPECT_EQ(tvp->GetResetDoneCount(), 1u);
   EXPECT_EQ(tvp->GetFlushDoneCount(), 1u);
   EXPECT_EQ(tvp->GetFrameDecodedCount(),
-            numFramesDecoded + g_env->video_->NumFrames());
+            numFramesDecoded + g_env->Video()->NumFrames());
   EXPECT_GE(tvp->GetEventCount(VideoPlayerEvent::kConfigInfo), 1u);
   EXPECT_TRUE(tvp->WaitForFrameProcessors());
 }
@@ -201,14 +200,14 @@
 // decoder, without waiting for the result of the previous decode requests.
 TEST_F(VideoDecoderTest, FlushAtEndOfStream_MultipleOutstandingDecodes) {
   VideoDecoderClientConfig config;
-  config.max_outstanding_decode_requests = 4;
-  auto tvp = CreateVideoPlayer(g_env->video_, config);
+  config.max_outstanding_decode_requests = 5;
+  auto tvp = CreateVideoPlayer(g_env->Video(), config);
 
   tvp->Play();
   EXPECT_TRUE(tvp->WaitForFlushDone());
 
   EXPECT_EQ(tvp->GetFlushDoneCount(), 1u);
-  EXPECT_EQ(tvp->GetFrameDecodedCount(), g_env->video_->NumFrames());
+  EXPECT_EQ(tvp->GetFrameDecodedCount(), g_env->Video()->NumFrames());
   EXPECT_TRUE(tvp->WaitForFrameProcessors());
 }
 
@@ -220,7 +219,7 @@
   std::vector<std::unique_ptr<VideoPlayer>> tvps(
       kMinSupportedConcurrentDecoders);
   for (size_t i = 0; i < kMinSupportedConcurrentDecoders; ++i)
-    tvps[i] = CreateVideoPlayer(g_env->video_);
+    tvps[i] = CreateVideoPlayer(g_env->Video());
 
   for (size_t i = 0; i < kMinSupportedConcurrentDecoders; ++i)
     tvps[i]->Play();
@@ -228,7 +227,7 @@
   for (size_t i = 0; i < kMinSupportedConcurrentDecoders; ++i) {
     EXPECT_TRUE(tvps[i]->WaitForFlushDone());
     EXPECT_EQ(tvps[i]->GetFlushDoneCount(), 1u);
-    EXPECT_EQ(tvps[i]->GetFrameDecodedCount(), g_env->video_->NumFrames());
+    EXPECT_EQ(tvps[i]->GetFrameDecodedCount(), g_env->Video()->NumFrames());
     EXPECT_TRUE(tvps[i]->WaitForFrameProcessors());
   }
 }
@@ -240,20 +239,20 @@
 // test is only ran when --disable_validator is specified, and will be
 // deprecated in the future.
 TEST_F(VideoDecoderTest, FlushAtEndOfStream_RenderThumbnails) {
-  if (g_env->enable_validator_)
+  if (g_env->IsValidatorEnabled())
     GTEST_SKIP();
 
   VideoDecoderClientConfig config;
   config.allocation_mode = AllocationMode::kAllocate;
   auto tvp = CreateVideoPlayer(
-      g_env->video_, config,
-      FrameRendererThumbnail::Create(g_env->video_->ThumbnailChecksums()));
+      g_env->Video(), config,
+      FrameRendererThumbnail::Create(g_env->Video()->ThumbnailChecksums()));
 
   tvp->Play();
   EXPECT_TRUE(tvp->WaitForFlushDone());
 
   EXPECT_EQ(tvp->GetFlushDoneCount(), 1u);
-  EXPECT_EQ(tvp->GetFrameDecodedCount(), g_env->video_->NumFrames());
+  EXPECT_EQ(tvp->GetFrameDecodedCount(), g_env->Video()->NumFrames());
   EXPECT_TRUE(tvp->WaitForFrameProcessors());
   EXPECT_TRUE(static_cast<FrameRendererThumbnail*>(tvp->GetFrameRenderer())
                   ->ValidateThumbnail());
@@ -280,31 +279,20 @@
   media::test::Video::SetTestDataPath(media::GetTestDataPath());
 
   // Check if a video was specified on the command line.
-  std::unique_ptr<media::test::Video> video;
   base::CommandLine::StringVector args = cmd_line->GetArgs();
-  if (args.size() >= 1) {
-    video = std::make_unique<media::test::Video>(base::FilePath(args[0]));
-    if (!video->Load()) {
-      LOG(ERROR) << "Failed to load " << args[0];
-      return 0;
-    }
-  }
-
-  // Set up our test environment.
-  media::test::g_env = static_cast<media::test::VideoPlayerTestEnvironment*>(
-      testing::AddGlobalTestEnvironment(
-          new media::test::VideoPlayerTestEnvironment(
-              video ? video.get()
-                    : &media::test::kDefaultTestVideoCollection[0])));
+  base::FilePath video_path =
+      (args.size() >= 1) ? base::FilePath(args[0]) : base::FilePath();
 
   // Parse command line arguments.
+  bool enable_validator = true;
+  bool output_frames = false;
   base::CommandLine::SwitchMap switches = cmd_line->GetSwitches();
   for (base::CommandLine::SwitchMap::const_iterator it = switches.begin();
        it != switches.end(); ++it) {
     if (it->first == "disable_validator") {
-      media::test::g_env->enable_validator_ = false;
+      enable_validator = false;
     } else if (it->first == "output_frames") {
-      media::test::g_env->output_frames_ = true;
+      output_frames = true;
     } else if (it->first.find("gtest_") == 0 || it->first == "v" ||
                it->first == "vmodule") {
       // Ignore
@@ -315,5 +303,15 @@
     }
   }
 
+  // Set up our test environment.
+  media::test::VideoPlayerTestEnvironment* test_environment =
+      media::test::VideoPlayerTestEnvironment::Create(
+          video_path, enable_validator, output_frames);
+  if (!test_environment)
+    return 0;
+
+  media::test::g_env = static_cast<media::test::VideoPlayerTestEnvironment*>(
+      testing::AddGlobalTestEnvironment(test_environment));
+
   return RUN_ALL_TESTS();
 }
diff --git a/media/webrtc/audio_processor_unittest.cc b/media/webrtc/audio_processor_unittest.cc
index 96d7030..acfb1ac1 100644
--- a/media/webrtc/audio_processor_unittest.cc
+++ b/media/webrtc/audio_processor_unittest.cc
@@ -101,7 +101,8 @@
     const base::TimeDelta input_capture_delay =
         base::TimeDelta::FromMilliseconds(20);
     for (int i = 0; i < kNumberOfPacketsForTest; ++i) {
-      data_bus->FromInterleaved(data_ptr, data_bus->frames(), 2);
+      data_bus->FromInterleaved<SignedInt16SampleTypeTraits>(
+          data_ptr, data_bus->frames());
       // |audio_processor| does nothing when the audio processing is off in
       // the processor.
       webrtc::AudioProcessing* ap = audio_processor->audio_processing_.get();
diff --git a/ppapi/proxy/audio_input_resource.cc b/ppapi/proxy/audio_input_resource.cc
index 60db9b8..96d6cff 100644
--- a/ppapi/proxy/audio_input_resource.cc
+++ b/ppapi/proxy/audio_input_resource.cc
@@ -273,9 +273,10 @@
 
     // Convert an AudioBus from deinterleaved float to interleaved integer data.
     // Store the result in a preallocated |client_buffer_|.
-    audio_bus_->ToInterleaved(audio_bus_->frames(),
-                              kBitsPerAudioInputSample / 8,
-                              client_buffer_.get());
+    static_assert(kBitsPerAudioInputSample == 16,
+                  "ToInterleaved expects 2 bytes.");
+    audio_bus_->ToInterleaved<media::SignedInt16SampleTypeTraits>(
+        audio_bus_->frames(), reinterpret_cast<int16_t*>(client_buffer_.get()));
 
     // Inform other side that we have read the data from the shared memory.
     ++buffer_index;
diff --git a/ppapi/proxy/audio_output_resource.cc b/ppapi/proxy/audio_output_resource.cc
index d8a85cd..bd11c7c 100644
--- a/ppapi/proxy/audio_output_resource.cc
+++ b/ppapi/proxy/audio_output_resource.cc
@@ -253,8 +253,10 @@
     }
 
     // Deinterleave the audio data into the shared memory as floats.
-    audio_bus_->FromInterleaved(client_buffer_.get(), audio_bus_->frames(),
-                                kBitsPerAudioOutputSample / 8);
+    static_assert(kBitsPerAudioOutputSample == 16,
+                  "FromInterleaved expects 2 bytes.");
+    audio_bus_->FromInterleaved<media::SignedInt16SampleTypeTraits>(
+        reinterpret_cast<int16_t*>(client_buffer_.get()), audio_bus_->frames());
 
     // Inform other side that we have read the data from the shared memory.
     // Let the other end know which buffer we just filled.  The buffer index is
diff --git a/ppapi/shared_impl/ppb_audio_shared.cc b/ppapi/shared_impl/ppb_audio_shared.cc
index dc67f415..241d6ecd2 100644
--- a/ppapi/shared_impl/ppb_audio_shared.cc
+++ b/ppapi/shared_impl/ppb_audio_shared.cc
@@ -236,9 +236,10 @@
     }
 
     // Deinterleave the audio data into the shared memory as floats.
-    audio_bus_->FromInterleaved(client_buffer_.get(),
-                                audio_bus_->frames(),
-                                kBitsPerAudioOutputSample / 8);
+    static_assert(kBitsPerAudioOutputSample == 16,
+                  "FromInterleaved expects 2 bytes.");
+    audio_bus_->FromInterleaved<media::SignedInt16SampleTypeTraits>(
+        reinterpret_cast<int16_t*>(client_buffer_.get()), audio_bus_->frames());
 
     // Let the other end know which buffer we just filled.  The buffer index is
     // used to ensure the other end is getting the buffer it expects.  For more
diff --git a/remoting/codec/audio_encoder_opus.cc b/remoting/codec/audio_encoder_opus.cc
index 536c667..3831dc1 100644
--- a/remoting/codec/audio_encoder_opus.cc
+++ b/remoting/codec/audio_encoder_opus.cc
@@ -127,9 +127,10 @@
   int samples_left = (resampling_data_size_ - resampling_data_pos_) /
       kBytesPerSample / channels_;
   DCHECK_LE(audio_bus->frames(), samples_left);
-  audio_bus->FromInterleaved(
-      resampling_data_ + resampling_data_pos_,
-      audio_bus->frames(), kBytesPerSample);
+  static_assert(kBytesPerSample == 2, "FromInterleaved expects 2 bytes.");
+  audio_bus->FromInterleaved<media::SignedInt16SampleTypeTraits>(
+      reinterpret_cast<const int16_t*>(resampling_data_ + resampling_data_pos_),
+      audio_bus->frames());
   resampling_data_pos_ += audio_bus->frames() * kBytesPerSample * channels_;
   DCHECK_LE(resampling_data_pos_, static_cast<int>(resampling_data_size_));
 }
@@ -186,8 +187,9 @@
       resampling_data_ = nullptr;
       samples_consumed = resampling_data_pos_ / channels_ / kBytesPerSample;
 
-      resampler_bus_->ToInterleaved(kFrameSamples, kBytesPerSample,
-                                    resample_buffer_.get());
+      static_assert(kBytesPerSample == 2, "ToInterleaved expects 2 bytes.");
+      resampler_bus_->ToInterleaved<media::SignedInt16SampleTypeTraits>(
+          kFrameSamples, reinterpret_cast<int16_t*>(resample_buffer_.get()));
       pcm_buffer = reinterpret_cast<int16_t*>(resample_buffer_.get());
     } else {
       samples_consumed = frame_size_;
diff --git a/services/audio/public/cpp/sounds/audio_stream_handler.cc b/services/audio/public/cpp/sounds/audio_stream_handler.cc
index 12084c1..d8f3bf2 100644
--- a/services/audio/public/cpp/sounds/audio_stream_handler.cc
+++ b/services/audio/public/cpp/sounds/audio_stream_handler.cc
@@ -45,23 +45,12 @@
       std::unique_ptr<service_manager::Connector> connector,
       std::unique_ptr<media::WavAudioHandler> wav_audio)
       : started_(false),
+        connector_(std::move(connector)),
         cursor_(0),
         delayed_stop_posted_(false),
         wav_audio_(std::move(wav_audio)) {
     DCHECK(wav_audio_);
     task_runner_ = base::SequencedTaskRunnerHandle::Get();
-
-    const media::AudioParameters params(
-        media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
-        media::GuessChannelLayout(wav_audio_->num_channels()),
-        wav_audio_->sample_rate(), kDefaultFrameCount);
-
-    if (g_observer_for_testing) {
-      g_observer_for_testing->Initialize(this, params);
-      return;
-    }
-    device_ = std::make_unique<audio::OutputDevice>(
-        std::move(connector), params, this, std::string());
   }
 
   ~AudioStreamContainer() override {
@@ -71,6 +60,20 @@
   void Play() {
     DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
+    // Create OutputDevice if it is the first time playing.
+    if (device_ == nullptr) {
+      const media::AudioParameters params(
+          media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
+          media::GuessChannelLayout(wav_audio_->num_channels()),
+          wav_audio_->sample_rate(), kDefaultFrameCount);
+      if (g_observer_for_testing) {
+        g_observer_for_testing->Initialize(this, params);
+      } else {
+        device_ = std::make_unique<audio::OutputDevice>(
+            connector_->Clone(), params, this, std::string());
+      }
+    }
+
     {
       base::AutoLock al(state_lock_);
 
@@ -148,6 +151,7 @@
   }
 
   bool started_;
+  std::unique_ptr<service_manager::Connector> connector_;
   std::unique_ptr<audio::OutputDevice> device_;
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
 
diff --git a/third_party/blink/public/mojom/payments/payment_request.mojom b/third_party/blink/public/mojom/payments/payment_request.mojom
index 034d0e2..8f118931 100644
--- a/third_party/blink/public/mojom/payments/payment_request.mojom
+++ b/third_party/blink/public/mojom/payments/payment_request.mojom
@@ -217,7 +217,7 @@
        PaymentOptions options);
 
   // Shows the user interface with the payment details.
-  Show(bool is_user_gesture, bool wait_for_updated_details);
+  Show(bool is_user_gesture);
 
   // Updates the payment details in response to new shipping address or shipping
   // option.
diff --git a/third_party/blink/public/platform/web_url_request.h b/third_party/blink/public/platform/web_url_request.h
index fdf28d0..0572432 100644
--- a/third_party/blink/public/platform/web_url_request.h
+++ b/third_party/blink/public/platform/web_url_request.h
@@ -139,6 +139,13 @@
       service_worker_provider_id_ = service_worker_provider_id;
     }
 
+    // The request is for a prefetch-only client (i.e. running NoStatePrefetch)
+    // and should use LOAD_PREFETCH network flags.
+    bool is_for_no_state_prefetch() const { return is_for_no_state_prefetch_; }
+    void set_is_for_no_state_prefetch(bool prefetch) {
+      is_for_no_state_prefetch_ = prefetch;
+    }
+
     // true if the request originated from within a service worker e.g. due to
     // a fetch() in the service worker script.
     void set_originated_from_service_worker(
@@ -165,6 +172,7 @@
     bool allow_download_ = true;
     ui::PageTransition transition_type_ = ui::PAGE_TRANSITION_LINK;
     int service_worker_provider_id_ = blink::kInvalidServiceWorkerProviderId;
+    bool is_for_no_state_prefetch_ = false;
     bool originated_from_service_worker_ = false;
     bool initiated_in_secure_context_ = false;
     bool attach_same_site_cookies_ = false;
@@ -382,6 +390,8 @@
 
   BLINK_PLATFORM_EXPORT base::Optional<WebString> GetDevToolsId() const;
 
+  BLINK_PLATFORM_EXPORT int GetLoadFlagsForWebURLRequest() const;
+
 #if INSIDE_BLINK
   BLINK_PLATFORM_EXPORT ResourceRequest& ToMutableResourceRequest();
   BLINK_PLATFORM_EXPORT const ResourceRequest& ToResourceRequest() const;
diff --git a/third_party/blink/renderer/core/exported/web_frame_test.cc b/third_party/blink/renderer/core/exported/web_frame_test.cc
index 6bc5842..a8fba24 100644
--- a/third_party/blink/renderer/core/exported/web_frame_test.cc
+++ b/third_party/blink/renderer/core/exported/web_frame_test.cc
@@ -5540,27 +5540,7 @@
   EXPECT_FALSE(active_now);
 }
 
-struct FakeTimerSetter {
-  FakeTimerSetter() {
-    time_elapsed_ = 1.0;
-    original_time_function_ = SetTimeFunctionsForTesting(ReturnMockTime);
-  }
-
-  ~FakeTimerSetter() { SetTimeFunctionsForTesting(original_time_function_); }
-  static double ReturnMockTime() {
-    time_elapsed_ += 1.0;
-    return time_elapsed_;
-  }
-
- private:
-  TimeFunction original_time_function_;
-  static double time_elapsed_;
-};
-double FakeTimerSetter::time_elapsed_ = 0.;
-
 TEST_F(WebFrameTest, FindInPageJavaScriptUpdatesDOMProperOrdinal) {
-  FakeTimerSetter fake_timer;
-
   const WebString search_pattern = WebString::FromUTF8("abc");
   // We have 2 occurrences of the pattern in our text.
   const char* html =
diff --git a/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc b/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc
index d5ad417..7bcfa63f 100644
--- a/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc
+++ b/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc
@@ -51,6 +51,7 @@
 #include "third_party/blink/renderer/platform/graphics/test/fake_gles2_interface.h"
 #include "third_party/blink/renderer/platform/graphics/test/fake_web_graphics_context_3d_provider.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
 #include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
@@ -75,8 +76,9 @@
     image2_ = surface2->makeImageSnapshot();
 
     // Save the global memory cache to restore it upon teardown.
-    global_memory_cache_ = ReplaceMemoryCacheForTesting(MemoryCache::Create(
-        blink::scheduler::GetSingleThreadTaskRunnerForTesting()));
+    global_memory_cache_ =
+        ReplaceMemoryCacheForTesting(MakeGarbageCollected<MemoryCache>(
+            blink::scheduler::GetSingleThreadTaskRunnerForTesting()));
 
     auto factory = [](FakeGLES2Interface* gl, bool* gpu_compositing_disabled)
         -> std::unique_ptr<WebGraphicsContext3DProvider> {
diff --git a/third_party/blink/renderer/core/layout/layout_block.h b/third_party/blink/renderer/core/layout/layout_block.h
index 1658619..3795e57 100644
--- a/third_party/blink/renderer/core/layout/layout_block.h
+++ b/third_party/blink/renderer/core/layout/layout_block.h
@@ -594,8 +594,6 @@
   virtual void AdjustChildDebugRect(LayoutRect&) const {}
 };
 
-DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutBlock, IsLayoutBlock());
-
 template <>
 struct DowncastTraits<LayoutBlock> {
   static bool AllowFrom(const LayoutObject& object) {
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow.cc b/third_party/blink/renderer/core/layout/layout_block_flow.cc
index f0298d4..8a52ee3 100644
--- a/third_party/blink/renderer/core/layout/layout_block_flow.cc
+++ b/third_party/blink/renderer/core/layout/layout_block_flow.cc
@@ -2829,7 +2829,7 @@
           !child->IsLayoutBlock())
         continue;
       if (!child->IsLayoutBlockFlow()) {
-        LayoutBlock* child_block = ToLayoutBlock(child);
+        auto* child_block = To<LayoutBlock>(child);
         if (child_block->ShrinkToAvoidFloats() && child_block->EverHadLayout())
           child_block->SetChildNeedsLayout(mark_parents);
         continue;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
index ee6ac56..331908f9 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
@@ -1002,7 +1002,8 @@
     WritingMode container_writing_mode,
     const MinMaxSizeInput& input,
     NGLineBreakerMode mode,
-    NGLineBreaker::MaxSizeCache* max_size_cache) {
+    NGLineBreaker::MaxSizeCache* max_size_cache,
+    base::Optional<LayoutUnit>* max_size_out) {
   const ComputedStyle& style = node.Style();
   WritingMode writing_mode = style.GetWritingMode();
   LayoutUnit available_inline_size =
@@ -1031,6 +1032,98 @@
                              /* handled_leading_floats_index */ 0u,
                              /* break_token */ nullptr, &empty_exclusion_space);
   line_breaker.SetMaxSizeCache(max_size_cache);
+  const NGInlineItemsData& items_data = line_breaker.ItemsData();
+
+  // This struct computes the max size from the line break results for the min
+  // size.
+  struct MaxSizeFromMinSize {
+    LayoutUnit position;
+    LayoutUnit max_size;
+    const NGInlineItemsData& items_data;
+    const NGInlineItem* next_item;
+    const NGLineBreaker::MaxSizeCache& max_size_cache;
+    bool is_after_break = true;
+
+    explicit MaxSizeFromMinSize(
+        const NGInlineItemsData& items_data,
+        const NGLineBreaker::MaxSizeCache& max_size_cache)
+        : items_data(items_data),
+          next_item(items_data.items.begin()),
+          max_size_cache(max_size_cache) {}
+
+    // Add all text items up to |end|. The line break results for min size
+    // may break text into multiple lines, and may remove trailing spaces. For
+    // max size, use the original text widths from NGInlineItem instead.
+    void AddTextUntil(const NGInlineItem* end) {
+      DCHECK(end);
+      for (; next_item != end; ++next_item) {
+        if (next_item->Type() == NGInlineItem::kText) {
+          DCHECK(next_item->TextShapeResult());
+          const ShapeResult& shape_result = *next_item->TextShapeResult();
+          position += shape_result.SnappedWidth().ClampNegativeToZero();
+        }
+      }
+    }
+
+    void ForceLineBreak(const NGInlineItem& item) {
+      // Add all text up to the forced break. There may be spaces that were
+      // removed during the line breaking.
+      AddTextUntil(&item);
+      next_item = std::next(&item);
+      // Reset |position| to zero.
+      max_size = std::max(max_size, position);
+      position = LayoutUnit();
+      is_after_break = true;
+    }
+
+    LayoutUnit Finish(const NGInlineItem* end) {
+      AddTextUntil(end);
+      return std::max(position, max_size);
+    }
+
+    bool ComputeFromMinSize(const NGLineInfo& line_info) {
+      if (is_after_break) {
+        position += line_info.TextIndent();
+        is_after_break = false;
+      }
+
+      for (const NGInlineItemResult& result : line_info.Results()) {
+        const NGInlineItem& item = *result.item;
+        if (item.Type() == NGInlineItem::kText) {
+          // Text in NGInlineItemResult may be wrapped and trailing spaces
+          // may be removed. Ignore them, but add text later from
+          // NGInlineItem.
+          continue;
+        }
+        if (item.Type() == NGInlineItem::kAtomicInline) {
+          // The max-size for atomic inlines are cached in |max_size_cache|.
+          unsigned item_index = &item - items_data.items.begin();
+          position += max_size_cache[item_index];
+          continue;
+        }
+        if (item.Type() == NGInlineItem::kControl) {
+          UChar c = items_data.text_content[item.StartOffset()];
+          if (c == kNewlineCharacter) {
+            ForceLineBreak(item);
+            continue;
+          }
+          // Tabulation characters change the widths by their positions, so
+          // their widths for the max size may be different from the widths for
+          // the min size. Fall back to 2 pass for now.
+          if (c == kTabulationCharacter)
+            return false;
+        }
+        position += result.inline_size;
+      }
+      return true;
+    }
+  };
+  // Instantiate |MaxSizeFromMinSize| if we can compute the max size in 1 pass.
+  base::Optional<MaxSizeFromMinSize> max_size_from_min_size;
+  if (mode == NGLineBreakerMode::kMinContent && !previous_floats_inline_size) {
+    DCHECK(max_size_cache);
+    max_size_from_min_size.emplace(items_data, *max_size_cache);
+  }
 
   Vector<LayoutObject*> floats_for_min_max;
   do {
@@ -1055,6 +1148,15 @@
     // them now.
     previous_floats_inline_size = LayoutUnit();
 
+    // Compute the max size from the line break result for the min size.
+    if (max_size_from_min_size.has_value()) {
+      // If there were floats, fall back to 2 pass for now.
+      if (!floats_for_min_max.IsEmpty() ||
+          !max_size_from_min_size->ComputeFromMinSize(line_info)) {
+        max_size_from_min_size.reset();
+      }
+    }
+
     for (auto* floating_object : floats_for_min_max) {
       DCHECK(floating_object->IsFloating());
 
@@ -1097,6 +1199,16 @@
     result = std::max(result, inline_size + floats_inline_size);
   } while (!line_breaker.IsFinished());
 
+  if (max_size_from_min_size.has_value()) {
+    *max_size_out = max_size_from_min_size->Finish(items_data.items.end());
+    // Check the max size matches to the value computed from 2 pass.
+    DCHECK_EQ(**max_size_out,
+              ComputeContentSize(node, container_writing_mode, input,
+                                 NGLineBreakerMode::kMaxContent, max_size_cache,
+                                 nullptr))
+        << node.GetLayoutBox();
+  }
+
   return result;
 }
 
@@ -1106,27 +1218,25 @@
     const NGConstraintSpace* constraint_space) {
   PrepareLayoutIfNeeded();
 
-  // Run line breaking with 0 and indefinite available width.
-
-  // TODO(kojii): There are several ways to make this more efficient and faster
-  // than runnning two line breaking.
-
   // Compute the max of inline sizes of all line boxes with 0 available inline
   // size. This gives the min-content, the width where lines wrap at every
   // break opportunity.
   NGLineBreaker::MaxSizeCache max_size_cache;
   MinMaxSize sizes;
-  sizes.min_size =
-      ComputeContentSize(*this, container_writing_mode, input,
-                         NGLineBreakerMode::kMinContent, &max_size_cache);
+  base::Optional<LayoutUnit> max_size;
+  sizes.min_size = ComputeContentSize(*this, container_writing_mode, input,
+                                      NGLineBreakerMode::kMinContent,
+                                      &max_size_cache, &max_size);
 
-  // Compute the sum of inline sizes of all inline boxes with no line breaks.
-  // TODO(kojii): NGConstraintSpaceBuilder does not allow NGSizeIndefinite
-  // inline available size. We can allow it, or make this more efficient
-  // without using NGLineBreaker.
-  sizes.max_size =
-      ComputeContentSize(*this, container_writing_mode, input,
-                         NGLineBreakerMode::kMaxContent, &max_size_cache);
+  // If the max size is also computed, use it.
+  if (max_size.has_value()) {
+    sizes.max_size = *max_size;
+  } else {
+    // Compute the sum of inline sizes of all inline boxes with no line breaks.
+    sizes.max_size = ComputeContentSize(*this, container_writing_mode, input,
+                                        NGLineBreakerMode::kMaxContent,
+                                        &max_size_cache, nullptr);
+  }
 
   // Negative text-indent can make min > max. Ensure min is the minimum size.
   sizes.min_size = std::min(sizes.min_size, sizes.max_size);
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
index 7025566e..f55724b2 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
@@ -42,6 +42,8 @@
                 NGExclusionSpace*);
   ~NGLineBreaker();
 
+  const NGInlineItemsData& ItemsData() const { return items_data_; }
+
   // Compute the next line break point and produces NGInlineItemResults for
   // the line.
   inline void NextLine(NGLineInfo* line_info) {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
index 4982b14..c65f368 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
@@ -144,9 +144,10 @@
   // Returns true if this node should pass its percentage resolution block-size
   // to its children. Typically only quirks-mode, auto block-size, block nodes.
   bool UseParentPercentageResolutionBlockSizeForChildren() const {
-    if (IsBlock() && box_->IsLayoutBlock()) {
+    auto* layout_block = DynamicTo<LayoutBlock>(box_);
+    if (IsBlock() && layout_block) {
       return LayoutBoxUtils::SkipContainingBlockForPercentHeightCalculation(
-          ToLayoutBlock(box_));
+          layout_block);
     }
 
     return false;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
index a128240..7aa74e0 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
@@ -89,7 +89,7 @@
       contains_absolute_(contains_absolute),
       contains_fixed_(contains_fixed) {
   if (!container_builder->HasOutOfFlowDescendantCandidates() &&
-      !ToLayoutBlock(container_builder_->GetLayoutObject())
+      !To<LayoutBlock>(container_builder_->GetLayoutObject())
            ->HasPositionedObjects())
     return;
 
@@ -119,7 +119,7 @@
       &descendant_candidates, current_container);
 
   if (descendant_candidates.IsEmpty() &&
-      !ToLayoutBlock(current_container)->HasPositionedObjects())
+      !To<LayoutBlock>(current_container)->HasPositionedObjects())
     return;
 
   // Special case: containing block is a split inline.
@@ -184,8 +184,8 @@
 // Returns false if no new candidates were found.
 bool NGOutOfFlowLayoutPart::SweepLegacyDescendants(
     HashSet<const LayoutObject*>* placed_objects) {
-  const LayoutBlock* container_block =
-      ToLayoutBlockOrNull(container_builder_->GetLayoutObject());
+  const auto* container_block =
+      DynamicTo<LayoutBlock>(container_builder_->GetLayoutObject());
   if (!container_block)
     return false;
   TrackedLayoutBoxListHashSet* legacy_objects =
@@ -532,7 +532,7 @@
   }
 
   if (node.GetLayoutBox()->IsLayoutNGObject()) {
-    ToLayoutBlock(node.GetLayoutBox())
+    To<LayoutBlock>(node.GetLayoutBox())
         ->SetIsLegacyInitiatedOutOfFlowLayout(false);
   }
   // Legacy grid and flexbox handle OOF-positioned margins on their own, and
diff --git a/third_party/blink/renderer/core/layout/paint_containment_test.cc b/third_party/blink/renderer/core/layout/paint_containment_test.cc
index dcc1d0a58..3b3ba26e 100644
--- a/third_party/blink/renderer/core/layout/paint_containment_test.cc
+++ b/third_party/blink/renderer/core/layout/paint_containment_test.cc
@@ -39,7 +39,7 @@
   LayoutObject* obj = div->GetLayoutObject();
   DCHECK(obj);
   DCHECK(obj->IsLayoutBlock());
-  LayoutBlock& block = ToLayoutBlock(*obj);
+  auto& block = To<LayoutBlock>(*obj);
   EXPECT_TRUE(block.CreatesNewFormattingContext());
   EXPECT_FALSE(block.CanBeScrolledAndHasScrollableArea());
   CheckIsClippingStackingContextAndContainer(block);
diff --git a/third_party/blink/renderer/core/layout/scroll_anchor.cc b/third_party/blink/renderer/core/layout/scroll_anchor.cc
index 4bb9e0d6..0e03552 100644
--- a/third_party/blink/renderer/core/layout/scroll_anchor.cc
+++ b/third_party/blink/renderer/core/layout/scroll_anchor.cc
@@ -332,9 +332,9 @@
 
   // Make a separate pass to catch positioned descendants with a static DOM
   // parent that we skipped over (crbug.com/692701).
-  if (candidate->IsLayoutBlock()) {
+  if (auto* layouy_block = DynamicTo<LayoutBlock>(candidate)) {
     if (TrackedLayoutBoxListHashSet* positioned_descendants =
-            ToLayoutBlock(candidate)->PositionedObjects()) {
+            layouy_block->PositionedObjects()) {
       for (LayoutBox* descendant : *positioned_descendants) {
         if (descendant->Parent() != candidate) {
           if (FindAnchorRecursive(descendant))
diff --git a/third_party/blink/renderer/core/layout/text_autosizer.cc b/third_party/blink/renderer/core/layout/text_autosizer.cc
index 01c9a932..384fd71c 100644
--- a/third_party/blink/renderer/core/layout/text_autosizer.cc
+++ b/third_party/blink/renderer/core/layout/text_autosizer.cc
@@ -324,9 +324,7 @@
   if (!layout_object)
     return;
   PrepareClusterStack(layout_object->Parent());
-
-  if (layout_object->IsLayoutBlock()) {
-    LayoutBlock* block = ToLayoutBlock(layout_object);
+  if (auto* block = DynamicTo<LayoutBlock>(layout_object)) {
 #if DCHECK_IS_ON()
     blocks_that_have_begun_layout_.insert(block);
 #endif
@@ -428,7 +426,7 @@
     }
   } else if (parent->IsLayoutBlock() &&
              (parent->ChildrenInline() || behavior == kDescendToInnerBlocks)) {
-    child = ToLayoutBlock(parent)->FirstChild();
+    child = To<LayoutBlock>(parent)->FirstChild();
   } else if (parent->IsLayoutInline()) {
     child = ToLayoutInline(parent)->FirstChild();
   }
@@ -519,10 +517,8 @@
     return;
 
   Supercluster* last_supercluster = nullptr;
-  LayoutBlock* block = nullptr;
   while (object) {
-    if (object->IsLayoutBlock()) {
-      block = ToLayoutBlock(object);
+    if (auto* block = DynamicTo<LayoutBlock>(object)) {
       if (block->IsTableCell() ||
           ClassifyBlock(block, INDEPENDENT | EXPLICIT_WIDTH)) {
         // If supercluster hasn't been created yet, create one.
@@ -692,12 +688,11 @@
 TextAutosizer::BlockFlags TextAutosizer::ClassifyBlock(
     const LayoutObject* layout_object,
     BlockFlags mask) const {
-  if (!layout_object->IsLayoutBlock())
+  const auto* block = DynamicTo<LayoutBlock>(layout_object);
+  if (!block)
     return 0;
 
-  const LayoutBlock* block = ToLayoutBlock(layout_object);
   BlockFlags flags = 0;
-
   if (IsPotentialClusterRoot(block)) {
     if (mask & POTENTIAL_ROOT)
       flags |= POTENTIAL_ROOT;
@@ -1084,8 +1079,8 @@
     last_node = last_node->Parent();
   }
 
-  if (first_node->IsLayoutBlock())
-    return ToLayoutBlock(first_node);
+  if (auto* layout_block = DynamicTo<LayoutBlock>(first_node))
+    return layout_block;
 
   // containingBlock() should never leave the cluster, since it only skips
   // ancestors when finding the container of position:absolute/fixed blocks, and
@@ -1332,7 +1327,7 @@
     return false;
 
   BlockSet& blocks = *blocks_iter->value;
-  blocks.erase(ToLayoutBlock(layout_object));
+  blocks.erase(To<LayoutBlock>(layout_object));
   if (blocks.IsEmpty()) {
     blocks_for_fingerprint_.erase(blocks_iter);
 
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 77ece29a..6e190d4 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
@@ -126,7 +126,7 @@
     </div>
   )HTML");
 
-  auto* container = ToLayoutBlock(GetLayoutObjectByElementId("container"));
+  auto* container = To<LayoutBlock>(GetLayoutObjectByElementId("container"));
   auto* text = GetLayoutObjectByElementId("text")->SlowFirstChild();
 
   container->SetScrollTop(LayoutUnit(50));
@@ -159,8 +159,7 @@
     </div>
   )HTML");
 
-  LayoutBlock* container =
-      ToLayoutBlock(GetLayoutObjectByElementId("container"));
+  auto* container = To<LayoutBlock>(GetLayoutObjectByElementId("container"));
   LayoutObject* leaf = container->LastChild();
 
   container->SetScrollTop(LayoutUnit(50));
@@ -200,10 +199,9 @@
       "<span><img style='width: 20px; height: 100px'></span>text text text");
   UpdateAllLifecyclePhasesForTest();
 
-  LayoutBlock* frame_container =
-      ToLayoutBlock(GetLayoutObjectByElementId("frameContainer"));
-  LayoutBlock* frame_body =
-      ToLayoutBlock(ChildDocument().body()->GetLayoutObject());
+  auto* frame_container =
+      To<LayoutBlock>(GetLayoutObjectByElementId("frameContainer"));
+  auto* frame_body = To<LayoutBlock>(ChildDocument().body()->GetLayoutObject());
   LayoutText* frame_text = ToLayoutText(frame_body->LastChild());
 
   // This case involves clipping: frame height is 50, y-coordinate of result
@@ -248,8 +246,8 @@
 
   UpdateAllLifecyclePhasesForTest();
 
-  LayoutBlock* frame_container =
-      ToLayoutBlock(GetLayoutObjectByElementId("frameContainer"));
+  auto* frame_container =
+      To<LayoutBlock>(GetLayoutObjectByElementId("frameContainer"));
   LayoutObject* target =
       ChildDocument().getElementById("target")->GetLayoutObject();
   LayoutRect rect(0, 0, 100, 100);
@@ -275,11 +273,10 @@
       "<div style='width:100px;height:100px;'></div>");
   UpdateAllLifecyclePhasesForTest();
 
-  LayoutBlock* frame_container =
-      ToLayoutBlock(GetLayoutObjectByElementId("frameContainer"));
-  LayoutBlock* frame_body =
-      ToLayoutBlock(ChildDocument().body()->GetLayoutObject());
-  LayoutBlock* frame_div = ToLayoutBlock(frame_body->LastChild());
+  auto* frame_container =
+      To<LayoutBlock>(GetLayoutObjectByElementId("frameContainer"));
+  auto* frame_body = To<LayoutBlock>(ChildDocument().body()->GetLayoutObject());
+  auto* frame_div = To<LayoutBlock>(frame_body->LastChild());
 
   // This part is copied from the LayoutView test, just to ensure that the
   // mapped rect is valid before display:none is set on the iframe.
@@ -296,7 +293,7 @@
   frame_element->SetInlineStyleProperty(CSSPropertyID::kDisplay, "none");
   UpdateAllLifecyclePhasesForTest();
 
-  frame_body = ToLayoutBlock(ChildDocument().body()->GetLayoutObject());
+  frame_body = To<LayoutBlock>(ChildDocument().body()->GetLayoutObject());
   EXPECT_EQ(nullptr, frame_body);
 }
 
@@ -308,7 +305,7 @@
     </div>
   )HTML");
 
-  LayoutBlock* target = ToLayoutBlock(GetLayoutObjectByElementId("target"));
+  auto* target = To<LayoutBlock>(GetLayoutObjectByElementId("target"));
   LayoutRect local_visual_rect = target->LocalVisualRect();
   // -40 = -box_shadow_offset_x(40) (with target's top-right corner as the
   // origin)
@@ -341,7 +338,7 @@
     </div>
   )HTML");
 
-  LayoutBlock* target = ToLayoutBlock(GetLayoutObjectByElementId("target"));
+  auto* target = To<LayoutBlock>(GetLayoutObjectByElementId("target"));
   LayoutRect target_local_visual_rect = target->LocalVisualRect();
   // -40 = -box_shadow_offset_x(40) (with target's top-right corner as the
   // origin)
@@ -355,8 +352,7 @@
   // This rect is in physical coordinates of target.
   EXPECT_EQ(LayoutRect(0, 0, 140, 110), rect);
 
-  LayoutBlock* container =
-      ToLayoutBlock(GetLayoutObjectByElementId("container"));
+  auto* container = To<LayoutBlock>(GetLayoutObjectByElementId("container"));
   rect = target_local_visual_rect;
   target->FlipForWritingMode(rect);
   EXPECT_TRUE(target->MapToVisualRectInAncestorSpace(container, rect));
@@ -389,15 +385,14 @@
     </div>
   )HTML");
 
-  LayoutBlock* container =
-      ToLayoutBlock(GetLayoutObjectByElementId("container"));
+  auto* container = To<LayoutBlock>(GetLayoutObjectByElementId("container"));
   EXPECT_EQ(LayoutUnit(), container->ScrollTop());
   EXPECT_EQ(LayoutUnit(), container->ScrollLeft());
   container->SetScrollTop(LayoutUnit(7));
   container->SetScrollLeft(LayoutUnit(8));
   UpdateAllLifecyclePhasesForTest();
 
-  LayoutBlock* target = ToLayoutBlock(GetLayoutObjectByElementId("target"));
+  auto* target = To<LayoutBlock>(GetLayoutObjectByElementId("target"));
   LayoutRect target_local_visual_rect = target->LocalVisualRect();
   // 140 = width(100) + box_shadow_offset_x(40)
   // 110 = height(90) + box_shadow_offset_y(20)
@@ -448,8 +443,7 @@
     </div>
   )HTML");
 
-  LayoutBlock* container =
-      ToLayoutBlock(GetLayoutObjectByElementId("container"));
+  auto* container = To<LayoutBlock>(GetLayoutObjectByElementId("container"));
   EXPECT_EQ(LayoutUnit(), container->ScrollTop());
   // The initial scroll offset is to the left-most because of flipped blocks
   // writing mode.
@@ -460,7 +454,7 @@
   container->SetScrollLeft(LayoutUnit(142));
   UpdateAllLifecyclePhasesForTest();
 
-  LayoutBlock* target = ToLayoutBlock(GetLayoutObjectByElementId("target"));
+  auto* target = To<LayoutBlock>(GetLayoutObjectByElementId("target"));
   LayoutRect target_local_visual_rect = target->LocalVisualRect();
   // -40 = -box_shadow_offset_x(40) (with target's top-right corner as the
   // origin)
@@ -526,15 +520,14 @@
     </div>
   )HTML");
 
-  LayoutBlock* container =
-      ToLayoutBlock(GetLayoutObjectByElementId("container"));
+  auto* container = To<LayoutBlock>(GetLayoutObjectByElementId("container"));
   EXPECT_EQ(LayoutUnit(), container->ScrollTop());
   EXPECT_EQ(LayoutUnit(), container->ScrollLeft());
   container->SetScrollTop(LayoutUnit(27));
   container->SetScrollLeft(LayoutUnit(28));
   UpdateAllLifecyclePhasesForTest();
 
-  LayoutBlock* target = ToLayoutBlock(GetLayoutObjectByElementId("target"));
+  auto* target = To<LayoutBlock>(GetLayoutObjectByElementId("target"));
   LayoutRect target_local_visual_rect = target->LocalVisualRect();
   // 140 = width(100) + box_shadow_offset_x(40)
   // 110 = height(90) + box_shadow_offset_y(20)
@@ -560,8 +553,7 @@
     </div>
   )HTML");
 
-  LayoutBlock* container =
-      ToLayoutBlock(GetLayoutObjectByElementId("container"));
+  auto* container = To<LayoutBlock>(GetLayoutObjectByElementId("container"));
   EXPECT_EQ(LayoutUnit(), container->ScrollTop());
   // The initial scroll offset is to the left-most because of flipped blocks
   // writing mode.
@@ -571,7 +563,7 @@
   container->SetScrollLeft(LayoutUnit(82));  // Scroll to the right by 8 pixels.
   UpdateAllLifecyclePhasesForTest();
 
-  LayoutBlock* target = ToLayoutBlock(GetLayoutObjectByElementId("target"));
+  auto* target = To<LayoutBlock>(GetLayoutObjectByElementId("target"));
   LayoutRect target_local_visual_rect = target->LocalVisualRect();
   // -40 = -box_shadow_offset_x(40) (with target's top-right corner as the
   // origin)
@@ -604,8 +596,7 @@
     </div>
   )HTML");
 
-  LayoutBlock* container =
-      ToLayoutBlock(GetLayoutObjectByElementId("container"));
+  auto* container = To<LayoutBlock>(GetLayoutObjectByElementId("container"));
   EXPECT_EQ(LayoutUnit(), container->ScrollTop());
   // The initial scroll offset is to the left-most because of flipped blocks
   // writing mode.
@@ -616,7 +607,7 @@
       LayoutUnit(142));  // Scroll to the right by 8 pixels.
   UpdateAllLifecyclePhasesForTest();
 
-  LayoutBlock* target = ToLayoutBlock(GetLayoutObjectByElementId("target"));
+  auto* target = To<LayoutBlock>(GetLayoutObjectByElementId("target"));
   LayoutRect target_local_visual_rect = target->LocalVisualRect();
   // 140 = width(100) + box_shadow_offset_x(40)
   // 110 = height(90) + box_shadow_offset_y(20)
@@ -656,13 +647,13 @@
     </div>
   )HTML");
 
-  LayoutBlock* scroller = ToLayoutBlock(GetLayoutObjectByElementId("scroller"));
+  auto* scroller = To<LayoutBlock>(GetLayoutObjectByElementId("scroller"));
   scroller->SetScrollTop(LayoutUnit(77));
   scroller->SetScrollLeft(LayoutUnit(88));
   UpdateAllLifecyclePhasesForTest();
 
-  LayoutBlock* normal_flow =
-      ToLayoutBlock(GetLayoutObjectByElementId("normal-flow"));
+  auto* normal_flow =
+      To<LayoutBlock>(GetLayoutObjectByElementId("normal-flow"));
   if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
     EXPECT_EQ(scroller, &normal_flow->ContainerForPaintInvalidation());
 
@@ -673,9 +664,9 @@
   EXPECT_EQ(LayoutRect(0, 0, 2000, 2000), rect);
   EXPECT_EQ(rect, normal_flow->FirstFragment().VisualRect());
 
-  LayoutBlock* stacking_context =
-      ToLayoutBlock(GetLayoutObjectByElementId("stacking-context"));
-  LayoutBlock* absolute = ToLayoutBlock(GetLayoutObjectByElementId("absolute"));
+  auto* stacking_context =
+      To<LayoutBlock>(GetLayoutObjectByElementId("stacking-context"));
+  auto* absolute = To<LayoutBlock>(GetLayoutObjectByElementId("absolute"));
   EXPECT_EQ(stacking_context, absolute->Container());
 
   EXPECT_EQ(LayoutRect(0, 0, 50, 50), absolute->LocalVisualRect());
@@ -703,11 +694,10 @@
       "  </div>"
       "</div>");
 
-  LayoutBlock* stacking_context =
-      ToLayoutBlock(GetLayoutObjectByElementId("stacking-context"));
-  LayoutBlock* absolute = ToLayoutBlock(GetLayoutObjectByElementId("absolute"));
-  LayoutBlock* container =
-      ToLayoutBlock(GetLayoutObjectByElementId("container"));
+  auto* stacking_context =
+      To<LayoutBlock>(GetLayoutObjectByElementId("stacking-context"));
+  auto* absolute = To<LayoutBlock>(GetLayoutObjectByElementId("absolute"));
+  auto* container = To<LayoutBlock>(GetLayoutObjectByElementId("container"));
   EXPECT_EQ(absolute->View(), &absolute->ContainerForPaintInvalidation());
   EXPECT_EQ(container, absolute->Container());
 
@@ -807,9 +797,8 @@
     </style>
     <div id='container'><div id='target'></div></div>
   )HTML");
-  LayoutBlock* container =
-      ToLayoutBlock(GetLayoutObjectByElementId("container"));
-  LayoutBlock* target = ToLayoutBlock(GetLayoutObjectByElementId("target"));
+  auto* container = To<LayoutBlock>(GetLayoutObjectByElementId("container"));
+  auto* target = To<LayoutBlock>(GetLayoutObjectByElementId("target"));
   LayoutRect original_rect(0, 0, 100, 100);
   // Multiply both matrices together before flattening.
   TransformationMatrix matrix = container->Layer()->CurrentTransform();
@@ -839,9 +828,8 @@
     </style>
     <div id='container'><div id='target'></div></div>
   )HTML");
-  LayoutBlock* container =
-      ToLayoutBlock(GetLayoutObjectByElementId("container"));
-  LayoutBlock* target = ToLayoutBlock(GetLayoutObjectByElementId("target"));
+  auto* container = To<LayoutBlock>(GetLayoutObjectByElementId("container"));
+  auto* target = To<LayoutBlock>(GetLayoutObjectByElementId("target"));
   LayoutRect original_rect(0, 0, 100, 100);
   // Multiply both matrices together before flattening.
   TransformationMatrix matrix = container->Layer()->CurrentTransform();
@@ -868,9 +856,8 @@
     </style>
     <div id='container'><div id='target'></div></div>
   )HTML");
-  LayoutBlock* container =
-      ToLayoutBlock(GetLayoutObjectByElementId("container"));
-  LayoutBlock* target = ToLayoutBlock(GetLayoutObjectByElementId("target"));
+  auto* container = To<LayoutBlock>(GetLayoutObjectByElementId("container"));
+  auto* target = To<LayoutBlock>(GetLayoutObjectByElementId("target"));
   LayoutRect original_rect(0, 0, 100, 100);
   TransformationMatrix matrix = container->Layer()->CurrentTransform();
   matrix.FlattenTo2d();
@@ -903,9 +890,8 @@
     </style>
     <div id='container'><div id='target'></div></div>
   )HTML");
-  LayoutBlock* container =
-      ToLayoutBlock(GetLayoutObjectByElementId("container"));
-  LayoutBlock* target = ToLayoutBlock(GetLayoutObjectByElementId("target"));
+  auto* container = To<LayoutBlock>(GetLayoutObjectByElementId("container"));
+  auto* target = To<LayoutBlock>(GetLayoutObjectByElementId("target"));
   LayoutRect original_rect(0, 0, 100, 100);
   TransformationMatrix matrix = container->Layer()->CurrentTransform();
   TransformationMatrix target_matrix;
@@ -942,12 +928,11 @@
       <div id='spacer'></div>
     </div>
   )HTML");
-  LayoutBlock* container =
-      ToLayoutBlock(GetLayoutObjectByElementId("container"));
+  auto* container = To<LayoutBlock>(GetLayoutObjectByElementId("container"));
   ToElement(container->GetNode())->scrollTo(0, 5);
   UpdateAllLifecyclePhasesForTest();
 
-  LayoutBlock* target = ToLayoutBlock(GetLayoutObjectByElementId("target"));
+  auto* target = To<LayoutBlock>(GetLayoutObjectByElementId("target"));
   LayoutRect originalRect(0, 0, 100, 100);
   TransformationMatrix transform;
   target->GetTransformFromContainer(
diff --git a/third_party/blink/renderer/core/loader/resource/css_style_sheet_resource_test.cc b/third_party/blink/renderer/core/loader/resource/css_style_sheet_resource_test.cc
index cec12528..954e820 100644
--- a/third_party/blink/renderer/core/loader/resource/css_style_sheet_resource_test.cc
+++ b/third_party/blink/renderer/core/loader/resource/css_style_sheet_resource_test.cc
@@ -46,8 +46,9 @@
 class CSSStyleSheetResourceTest : public PageTestBase {
  protected:
   CSSStyleSheetResourceTest() {
-    original_memory_cache_ = ReplaceMemoryCacheForTesting(MemoryCache::Create(
-        blink::scheduler::GetSingleThreadTaskRunnerForTesting()));
+    original_memory_cache_ =
+        ReplaceMemoryCacheForTesting(MakeGarbageCollected<MemoryCache>(
+            blink::scheduler::GetSingleThreadTaskRunnerForTesting()));
   }
 
   ~CSSStyleSheetResourceTest() override {
diff --git a/third_party/blink/renderer/core/loader/resource/image_resource_test.cc b/third_party/blink/renderer/core/loader/resource/image_resource_test.cc
index 9a4ce34..b073a4aa 100644
--- a/third_party/blink/renderer/core/loader/resource/image_resource_test.cc
+++ b/third_party/blink/renderer/core/loader/resource/image_resource_test.cc
@@ -44,6 +44,7 @@
 #include "third_party/blink/renderer/platform/exported/wrapped_resource_response.h"
 #include "third_party/blink/renderer/platform/graphics/bitmap_image.h"
 #include "third_party/blink/renderer/platform/graphics/image.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/instance_counters.h"
 #include "third_party/blink/renderer/platform/loader/fetch/console_logger.h"
 #include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_info.h"
@@ -1879,8 +1880,8 @@
   ImageResource* image_resource = ImageResource::CreateForTest(test_url);
 
   // Ensure that |image_resource| has a loader.
-  ResourceLoader* loader =
-      ResourceLoader::Create(fetcher, scheduler, image_resource);
+  auto* loader =
+      MakeGarbageCollected<ResourceLoader>(fetcher, scheduler, image_resource);
   ALLOW_UNUSED_LOCAL(loader);
 
   image_resource->NotifyStartLoad();
diff --git a/third_party/blink/renderer/core/loader/resource_load_observer_for_frame_test.cc b/third_party/blink/renderer/core/loader/resource_load_observer_for_frame_test.cc
index 66a290a..4b2a1e5 100644
--- a/third_party/blink/renderer/core/loader/resource_load_observer_for_frame_test.cc
+++ b/third_party/blink/renderer/core/loader/resource_load_observer_for_frame_test.cc
@@ -8,6 +8,7 @@
 #include "third_party/blink/renderer/core/loader/empty_clients.h"
 #include "third_party/blink/renderer/core/loader/frame_or_imported_document.h"
 #include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
@@ -46,7 +47,7 @@
   resource_request.SetRequestContext(mojom::RequestContextType::IMAGE);
   ResourceResponse response(url);
   response.SetHasMajorCertificateErrors(true);
-  Resource* resource = MockResource::Create(resource_request);
+  auto* resource = MakeGarbageCollected<MockResource>(resource_request);
   resource->SetResponse(response);
 
   EXPECT_FALSE(client->IsDidDisplayContentWithCertificateErrorsCalled());
diff --git a/third_party/blink/renderer/core/paint/block_painter_test.cc b/third_party/blink/renderer/core/paint/block_painter_test.cc
index fbf1c691..228b9139 100644
--- a/third_party/blink/renderer/core/paint/block_painter_test.cc
+++ b/third_party/blink/renderer/core/paint/block_painter_test.cc
@@ -38,7 +38,7 @@
     </div>
   )HTML");
 
-  auto& container = ToLayoutBlock(*GetLayoutObjectByElementId("container"));
+  auto& container = To<LayoutBlock>(*GetLayoutObjectByElementId("container"));
   auto& child = *GetLayoutObjectByElementId("child");
 
   // The scroll hit test should be after the container background but before the
@@ -129,7 +129,7 @@
   )HTML");
 
   auto& html =
-      ToLayoutBlock(*GetDocument().documentElement()->GetLayoutObject());
+      To<LayoutBlock>(*GetDocument().documentElement()->GetLayoutObject());
   auto& child = *GetLayoutObjectByElementId("child");
 
   // The scroll hit test should be after the document background but before the
@@ -192,7 +192,7 @@
       <div style='width: 50px; height: 5000px'></div>
     </div>
   )HTML");
-  auto* scroller = ToLayoutBlock(GetLayoutObjectByElementId("scroller"));
+  auto* scroller = To<LayoutBlock>(GetLayoutObjectByElementId("scroller"));
   if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
     EXPECT_EQ(LayoutRect(0, 0, 50, 5000),
               BlockPainter(*scroller).OverflowRectForCullRectTesting(false));
@@ -208,7 +208,7 @@
       <div style='width: 50px; height: 5000px'></div>
     </div>
   )HTML");
-  auto* scroller = ToLayoutBlock(GetLayoutObjectByElementId("scroller"));
+  auto* scroller = To<LayoutBlock>(GetLayoutObjectByElementId("scroller"));
   EXPECT_EQ(LayoutRect(0, 0, 50, 5000),
             BlockPainter(*scroller).OverflowRectForCullRectTesting(false));
 }
@@ -607,7 +607,8 @@
   )HTML");
 
   const auto& scrolling_client = ViewScrollingBackgroundClient();
-  const auto* scroller = ToLayoutBlock(GetLayoutObjectByElementId("scroller"));
+  const auto* scroller =
+      To<LayoutBlock>(GetLayoutObjectByElementId("scroller"));
   const auto* child = GetLayoutObjectByElementId("child");
   EXPECT_THAT(RootPaintController().GetDisplayItemList(),
               ElementsAre(IsSameId(&scrolling_client, kDocumentBackgroundType),
diff --git a/third_party/blink/renderer/core/paint/box_model_object_painter.cc b/third_party/blink/renderer/core/paint/box_model_object_painter.cc
index 7828ac83b..78c4fc7 100644
--- a/third_party/blink/renderer/core/paint/box_model_object_painter.cc
+++ b/third_party/blink/renderer/core/paint/box_model_object_painter.cc
@@ -73,8 +73,8 @@
     const RootInlineBox& root = flow_box_->Root();
     flow_box_->Paint(paint_info, paint_offset - local_offset, root.LineTop(),
                      root.LineBottom());
-  } else if (box_model_.IsLayoutBlock()) {
-    ToLayoutBlock(box_model_).PaintObject(paint_info, paint_offset);
+  } else if (auto* layout_block = DynamicTo<LayoutBlock>(box_model_)) {
+    layout_block->PaintObject(paint_info, paint_offset);
   } else {
     // We should go through the above path for LayoutInlines.
     DCHECK(!box_model_.IsLayoutInline());
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc
index 06f087e..86c9f02 100644
--- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc
+++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc
@@ -1030,10 +1030,9 @@
     </div>
   )HTML");
 
-  CompositedLayerMapping* mapping =
-      ToLayoutBlock(GetLayoutObjectByElementId("container"))
-          ->Layer()
-          ->GetCompositedLayerMapping();
+  auto* mapping = To<LayoutBlock>(GetLayoutObjectByElementId("container"))
+                      ->Layer()
+                      ->GetCompositedLayerMapping();
   ASSERT_TRUE(mapping->ScrollingContentsLayer());
   EXPECT_EQ(static_cast<GraphicsLayerPaintingPhase>(
                 kGraphicsLayerPaintOverflowContents |
@@ -1054,7 +1053,7 @@
       negative_composited_child);
   UpdateAllLifecyclePhasesForTest();
 
-  mapping = ToLayoutBlock(GetLayoutObjectByElementId("container"))
+  mapping = To<LayoutBlock>(GetLayoutObjectByElementId("container"))
                 ->Layer()
                 ->GetCompositedLayerMapping();
   ASSERT_TRUE(mapping->ScrollingContentsLayer());
@@ -1213,15 +1212,13 @@
     </div>
   )HTML");
 
-  CompositedLayerMapping* mapping =
-      ToLayoutBlock(GetLayoutObjectByElementId("scroller"))
-          ->Layer()
-          ->GetCompositedLayerMapping();
+  auto* mapping = To<LayoutBlock>(GetLayoutObjectByElementId("scroller"))
+                      ->Layer()
+                      ->GetCompositedLayerMapping();
 
-  CompositedLayerMapping* mapping2 =
-      ToLayoutBlock(GetLayoutObjectByElementId("scroller2"))
-          ->Layer()
-          ->GetCompositedLayerMapping();
+  auto* mapping2 = To<LayoutBlock>(GetLayoutObjectByElementId("scroller2"))
+                       ->Layer()
+                       ->GetCompositedLayerMapping();
 
   ASSERT_TRUE(mapping);
   ASSERT_TRUE(mapping2);
@@ -2231,12 +2228,12 @@
     </div>
   )HTML");
 
-  PaintLayer* sticky1 =
-      ToLayoutBlock(GetLayoutObjectByElementId("sticky1"))->Layer();
-  PaintLayer* sticky2 =
-      ToLayoutBlock(GetLayoutObjectByElementId("sticky2"))->Layer();
-  PaintLayer* sticky3 =
-      ToLayoutBlock(GetLayoutObjectByElementId("sticky3"))->Layer();
+  auto* sticky1 =
+      To<LayoutBlock>(GetLayoutObjectByElementId("sticky1"))->Layer();
+  auto* sticky2 =
+      To<LayoutBlock>(GetLayoutObjectByElementId("sticky2"))->Layer();
+  auto* sticky3 =
+      To<LayoutBlock>(GetLayoutObjectByElementId("sticky3"))->Layer();
   // All three sticky-pos elements are composited, because we composite
   // all sticky elements which stick to scrollers.
   EXPECT_EQ(kPaintsIntoOwnBacking, sticky1->GetCompositingState());
@@ -2272,8 +2269,8 @@
   ASSERT_TRUE(main_graphics_layer);
   ASSERT_TRUE(child_transform_layer);
 
-  PaintLayer* scroller =
-      ToLayoutBlock(GetLayoutObjectByElementId("scroller"))->Layer();
+  auto* scroller =
+      To<LayoutBlock>(GetLayoutObjectByElementId("scroller"))->Layer();
   PaintLayerScrollableArea* scrollable_area = scroller->GetScrollableArea();
   scrollable_area->ScrollToAbsolutePosition(
       FloatPoint(scrollable_area->ScrollPosition().Y(), 100));
@@ -2312,15 +2309,14 @@
     </div>
   )HTML");
 
-  CompositedLayerMapping* mapping =
-      ToLayoutBlock(GetLayoutObjectByElementId("sticky"))
-          ->Layer()
-          ->GetCompositedLayerMapping();
+  auto* mapping = To<LayoutBlock>(GetLayoutObjectByElementId("sticky"))
+                      ->Layer()
+                      ->GetCompositedLayerMapping();
   ASSERT_TRUE(mapping);
   GraphicsLayer* main_graphics_layer = mapping->MainGraphicsLayer();
 
-  PaintLayer* scroller =
-      ToLayoutBlock(GetLayoutObjectByElementId("scroller"))->Layer();
+  auto* scroller =
+      To<LayoutBlock>(GetLayoutObjectByElementId("scroller"))->Layer();
   PaintLayerScrollableArea* scrollable_area = scroller->GetScrollableArea();
   ASSERT_TRUE(scrollable_area);
   scrollable_area->ScrollToAbsolutePosition(
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
index adc174f..067325a 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
@@ -337,7 +337,7 @@
   }
 
   DCHECK(layout_object->IsLayoutBlockFlow());
-  const LayoutBlock& layout_block = ToLayoutBlock(*layout_object);
+  const auto& layout_block = To<LayoutBlock>(*layout_object);
   DCHECK(layout_block.ChildrenInline());
   if (ShouldPaintDescendantOutlines(paint_info.phase)) {
     ObjectPainter(layout_block).PaintInlineChildrenOutlines(paint_info);
diff --git a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
index ef178b9..c23e43bd 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
@@ -1085,7 +1085,7 @@
   // FrameSelection.
   if (!GetLayoutObject()->IsLayoutBlock())
     return false;
-  return ToLayoutBlock(GetLayoutObject())->ShouldPaintCursorCaret();
+  return To<LayoutBlock>(GetLayoutObject())->ShouldPaintCursorCaret();
 }
 
 bool NGPaintFragment::ShouldPaintDragCaret() const {
@@ -1093,7 +1093,7 @@
   // DragCaret.
   if (!GetLayoutObject()->IsLayoutBlock())
     return false;
-  return ToLayoutBlock(GetLayoutObject())->ShouldPaintDragCaret();
+  return To<LayoutBlock>(GetLayoutObject())->ShouldPaintDragCaret();
 }
 
 String NGPaintFragment::DebugName() const {
diff --git a/third_party/blink/renderer/core/paint/paint_controller_paint_test.cc b/third_party/blink/renderer/core/paint/paint_controller_paint_test.cc
index 83399364..a842d22 100644
--- a/third_party/blink/renderer/core/paint/paint_controller_paint_test.cc
+++ b/third_party/blink/renderer/core/paint/paint_controller_paint_test.cc
@@ -55,8 +55,8 @@
       "<div id='div' style='width:100px; height: 200px'>AAAAAAAAAA "
       "BBBBBBBBBB</div>");
   Element& div = *ToElement(GetDocument().body()->firstChild());
-  LayoutBlock& div_block =
-      *ToLayoutBlock(GetDocument().body()->firstChild()->GetLayoutObject());
+  auto& div_block =
+      *To<LayoutBlock>(GetDocument().body()->firstChild()->GetLayoutObject());
   LayoutText& text = *ToLayoutText(div_block.FirstChild());
   DisplayItemClient& first_text_box =
       text.FirstInlineFragment()
@@ -100,7 +100,7 @@
     blue'></div>
     </div>
   )HTML");
-  LayoutBlock& div = *ToLayoutBlock(GetLayoutObjectByElementId("div"));
+  auto& div = *To<LayoutBlock>(GetLayoutObjectByElementId("div"));
   LayoutObject& sub_div = *div.FirstChild();
   LayoutObject& sub_div2 = *sub_div.NextSibling();
 
@@ -125,7 +125,7 @@
     blue'></div>
     </div>
   )HTML");
-  LayoutBlock& div = *ToLayoutBlock(GetLayoutObjectByElementId("div"));
+  auto& div = *To<LayoutBlock>(GetLayoutObjectByElementId("div"));
   LayoutObject& sub_div = *div.FirstChild();
 
   EXPECT_THAT(RootPaintController().GetDisplayItemList(),
@@ -190,7 +190,7 @@
     </container>
   )HTML");
 
-  auto& container = *ToLayoutBlock(GetLayoutObjectByElementId("container"));
+  auto& container = *To<LayoutBlock>(GetLayoutObjectByElementId("container"));
   auto& div1 = *GetLayoutObjectByElementId("div1");
   auto& div2 = *GetLayoutObjectByElementId("div2");
   auto& div3 = *GetLayoutObjectByElementId("div3");
@@ -234,7 +234,7 @@
     <div id='forceDocumentScroll'/>
   )HTML");
 
-  auto& container = *ToLayoutBlock(GetLayoutObjectByElementId("container"));
+  auto& container = *To<LayoutBlock>(GetLayoutObjectByElementId("container"));
   auto& child = *GetLayoutObjectByElementId("child");
 
   // The container's items should all be after the document's scroll hit test
@@ -274,7 +274,7 @@
     </div>
   )HTML");
 
-  auto& container = *ToLayoutBlock(GetLayoutObjectByElementId("container"));
+  auto& container = *To<LayoutBlock>(GetLayoutObjectByElementId("container"));
   auto& child = *GetLayoutObjectByElementId("child");
   auto& neg_z_child = *GetLayoutObjectByElementId("negZChild");
   auto& pos_z_child = *GetLayoutObjectByElementId("posZChild");
@@ -320,7 +320,7 @@
     </div>
   )HTML");
 
-  auto& container = *ToLayoutBlock(GetLayoutObjectByElementId("container"));
+  auto& container = *To<LayoutBlock>(GetLayoutObjectByElementId("container"));
   auto& child = *GetLayoutObjectByElementId("child");
   auto& neg_z_child = *GetLayoutObjectByElementId("negZChild");
   auto& pos_z_child = *GetLayoutObjectByElementId("posZChild");
@@ -365,7 +365,7 @@
     </div>
   )HTML");
 
-  auto& container = *ToLayoutBlock(GetLayoutObjectByElementId("container"));
+  auto& container = *To<LayoutBlock>(GetLayoutObjectByElementId("container"));
   auto& child = *GetLayoutObjectByElementId("child");
   auto& neg_z_child = *GetLayoutObjectByElementId("negZChild");
   auto& pos_z_child = *GetLayoutObjectByElementId("posZChild");
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
index 360f933c..a27559b 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -994,8 +994,7 @@
           SubtreeLayoutScope layout_scope(*GetLayoutBox());
           layout_scope.SetNeedsLayout(
               GetLayoutBox(), layout_invalidation_reason::kScrollbarChanged);
-          if (GetLayoutBox()->IsLayoutBlock()) {
-            LayoutBlock* block = ToLayoutBlock(GetLayoutBox());
+          if (auto* block = DynamicTo<LayoutBlock>(GetLayoutBox())) {
             block->ScrollbarsChanged(horizontal_scrollbar_should_change,
                                      vertical_scrollbar_should_change);
             block->UpdateBlockLayout(true);
@@ -1201,12 +1200,12 @@
   bool vertical_scrollbar_changed =
       SetHasVerticalScrollbar(needs_vertical_scrollbar);
 
-  if (GetLayoutBox()->IsLayoutBlock() &&
+  auto* layout_block = DynamicTo<LayoutBlock>(GetLayoutBox());
+  if (layout_block &&
       (horizontal_scrollbar_changed || vertical_scrollbar_changed)) {
-    ToLayoutBlock(GetLayoutBox())
-        ->ScrollbarsChanged(horizontal_scrollbar_changed,
-                            vertical_scrollbar_changed,
-                            LayoutBlock::ScrollbarChangeContext::kStyleChange);
+    layout_block->ScrollbarsChanged(
+        horizontal_scrollbar_changed, vertical_scrollbar_changed,
+        LayoutBlock::ScrollbarChangeContext::kStyleChange);
   }
 
   // With overflow: scroll, scrollbars are always visible but may be disabled.
@@ -2525,7 +2524,7 @@
         LayoutBox* box = scrollable_area->GetLayoutBox();
         layout_scope_->SetNeedsLayout(
             box, layout_invalidation_reason::kScrollbarChanged);
-        if (box->IsLayoutBlock()) {
+        if (auto* layout_block = DynamicTo<LayoutBlock>(box)) {
           bool horizontal_scrollbar_changed =
               scrollable_area->HasHorizontalScrollbar() !=
               scrollable_area->HadHorizontalScrollbarBeforeRelayout();
@@ -2533,8 +2532,8 @@
               scrollable_area->HasVerticalScrollbar() !=
               scrollable_area->HadVerticalScrollbarBeforeRelayout();
           if (horizontal_scrollbar_changed || vertical_scrollbar_changed) {
-            ToLayoutBlock(box)->ScrollbarsChanged(horizontal_scrollbar_changed,
-                                                  vertical_scrollbar_changed);
+            layout_block->ScrollbarsChanged(horizontal_scrollbar_changed,
+                                            vertical_scrollbar_changed);
           }
         }
         scrollable_area->SetNeedsRelayout(false);
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
index 4be210f..04782c07 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -1493,22 +1493,22 @@
   }
 
   // Some non-block boxes and SVG objects have special overflow rules.
-  if (!object.IsLayoutBlock() || object.IsSVG())
+  const auto* block = DynamicTo<LayoutBlock>(object);
+  if (!block || object.IsSVG())
     return false;
 
-  const auto& block = ToLayoutBlock(object);
   // Selection may overflow.
-  if (block.IsSelected())
+  if (block->IsSelected())
     return false;
   // Other cases that the contents may overflow. The conditions are copied from
   // BlockPainter for SPv1 clip. TODO(wangxianzhu): clean up.
-  if (block.HasControlClip() || block.ShouldPaintCarets())
+  if (block->HasControlClip() || block->ShouldPaintCarets())
     return false;
 
   // We need OverflowClip for hit-testing if the clip rect excluding overlay
   // scrollbars is different from the normal clip rect.
-  auto clip_rect = block.OverflowClipRect(LayoutPoint());
-  auto clip_rect_excluding_overlay_scrollbars = block.OverflowClipRect(
+  auto clip_rect = block->OverflowClipRect(LayoutPoint());
+  auto clip_rect_excluding_overlay_scrollbars = block->OverflowClipRect(
       LayoutPoint(), kExcludeOverlayScrollbarSizeForHitTesting);
   if (clip_rect != clip_rect_excluding_overlay_scrollbars)
     return false;
@@ -1517,14 +1517,14 @@
   // ContentsVisualOverflowRect() does not include self-painting descendants
   // (see comment above |BoxOverflowModel|) so, as a simplification, do not
   // omit the clip if there are any PaintLayer descendants.
-  if (block.HasLayer() && block.Layer()->FirstChild())
+  if (block->HasLayer() && block->Layer()->FirstChild())
     return false;
-  if (!clip_rect.Contains(block.ContentsVisualOverflowRect()))
+  if (!clip_rect.Contains(block->ContentsVisualOverflowRect()))
     return false;
 
   // Content can scroll, and needs to be clipped, if the layout overflow extends
   // beyond the clip rect.
-  return clip_rect.Contains(block.LayoutOverflowRect());
+  return clip_rect.Contains(block->LayoutOverflowRect());
 }
 
 void FragmentPaintPropertyTreeBuilder::UpdateOverflowClip() {
diff --git a/third_party/blink/renderer/core/paint/view_painter_test.cc b/third_party/blink/renderer/core/paint/view_painter_test.cc
index e83f95b..01c0508 100644
--- a/third_party/blink/renderer/core/paint/view_painter_test.cc
+++ b/third_party/blink/renderer/core/paint/view_painter_test.cc
@@ -194,7 +194,7 @@
       LayoutRect(0, 0, 800, 3000));
 
   auto* html =
-      ToLayoutBlock(GetDocument().documentElement()->GetLayoutObject());
+      To<LayoutBlock>(GetDocument().documentElement()->GetLayoutObject());
   HitTestData html_hit_test_data;
   html_hit_test_data.touch_action_rects.emplace_back(
       LayoutRect(0, 0, 800, 3000));
@@ -265,7 +265,7 @@
   view_hit_test_data.touch_action_rects.emplace_back(
       LayoutRect(0, 0, 800, 600));
   auto* html =
-      ToLayoutBlock(GetDocument().documentElement()->GetLayoutObject());
+      To<LayoutBlock>(GetDocument().documentElement()->GetLayoutObject());
   auto scrolling_properties = view->FirstFragment().ContentsProperties();
   HitTestData scrolling_hit_test_data;
   scrolling_hit_test_data.touch_action_rects.emplace_back(
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc
index ecfe1761..5efe873a 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc
@@ -35,6 +35,7 @@
 #include "third_party/blink/renderer/platform/graphics/test/fake_canvas_resource_host.h"
 #include "third_party/blink/renderer/platform/graphics/test/fake_gles2_interface.h"
 #include "third_party/blink/renderer/platform/graphics/test/fake_web_graphics_context_3d_provider.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h"
 #include "third_party/blink/renderer/platform/shared_buffer.h"
 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
@@ -231,8 +232,9 @@
   StringOrCanvasGradientOrCanvasPattern wrapped_alpha_gradient;
   this->AlphaGradient().SetCanvasGradient(alpha_gradient);
 
-  global_memory_cache_ = ReplaceMemoryCacheForTesting(MemoryCache::Create(
-      blink::scheduler::GetSingleThreadTaskRunnerForTesting()));
+  global_memory_cache_ =
+      ReplaceMemoryCacheForTesting(MakeGarbageCollected<MemoryCache>(
+          blink::scheduler::GetSingleThreadTaskRunnerForTesting()));
 }
 
 void CanvasRenderingContext2DTest::TearDown() {
diff --git a/third_party/blink/renderer/modules/installedapp/navigator_installed_app.cc b/third_party/blink/renderer/modules/installedapp/navigator_installed_app.cc
index 206c5e3..17b5465 100644
--- a/third_party/blink/renderer/modules/installedapp/navigator_installed_app.cc
+++ b/third_party/blink/renderer/modules/installedapp/navigator_installed_app.cc
@@ -62,7 +62,7 @@
       const WebVector<WebRelatedApplication>& web_info) {
     HeapVector<Member<RelatedApplication>> applications;
     for (const auto& web_application : web_info)
-      applications.push_back(RelatedApplication::Create(
+      applications.push_back(MakeGarbageCollected<RelatedApplication>(
           web_application.platform, web_application.url, web_application.id));
     return applications;
   }
diff --git a/third_party/blink/renderer/modules/installedapp/related_application.h b/third_party/blink/renderer/modules/installedapp/related_application.h
index fbddca66..16fb773 100644
--- a/third_party/blink/renderer/modules/installedapp/related_application.h
+++ b/third_party/blink/renderer/modules/installedapp/related_application.h
@@ -15,12 +15,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static RelatedApplication* Create(const String& platform,
-                                    const String& url,
-                                    const String& id) {
-    return MakeGarbageCollected<RelatedApplication>(platform, url, id);
-  }
-
   RelatedApplication(const String& platform,
                      const String& url,
                      const String& id)
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc b/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc
index 0b3a2cf..bc3d2a5 100644
--- a/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc
+++ b/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc
@@ -97,10 +97,6 @@
 
 class StubLocalFrameClientForImpl : public EmptyLocalFrameClient {
  public:
-  static StubLocalFrameClientForImpl* Create() {
-    return MakeGarbageCollected<StubLocalFrameClientForImpl>();
-  }
-
   std::unique_ptr<WebMediaPlayer> CreateWebMediaPlayer(
       HTMLMediaElement&,
       const WebMediaPlayerSource&,
@@ -167,12 +163,6 @@
 static const char* kTimeToDismissHistogramName =
     "Media.Controls.Overflow.TimeToDismiss";
 
-static double g_current_time = 1000.0;
-
-static void AdvanceClock(double seconds) {
-  g_current_time += seconds;
-}
-
 class MediaControlsImplTest : public PageTestBase,
                               private ScopedMediaCastOverlayButtonForTest {
  public:
@@ -180,21 +170,15 @@
 
  protected:
   void SetUp() override {
-    original_time_function_ =
-        SetTimeFunctionsForTesting([] { return g_current_time; });
-
     InitializePage();
   }
 
-  void TearDown() override {
-    SetTimeFunctionsForTesting(original_time_function_);
-  }
-
   void InitializePage() {
     Page::PageClients clients;
     FillWithEmptyClients(clients);
     clients.chrome_client = MakeGarbageCollected<MockChromeClientForImpl>();
-    SetupPageWithClients(&clients, StubLocalFrameClientForImpl::Create());
+    SetupPageWithClients(&clients,
+                         MakeGarbageCollected<StubLocalFrameClientForImpl>());
 
     GetDocument().write("<video controls>");
     HTMLVideoElement& video =
@@ -293,15 +277,9 @@
     return ToText(display->firstChild())->data();
   }
 
-  void ToggleOverflowMenu() {
-    MediaControls().ToggleOverflowMenu();
-    test::RunPendingTasks();
-  }
-
  private:
   Persistent<MediaControlsImpl> media_controls_;
   HistogramTester histogram_tester_;
-  TimeFunction original_time_function_;
 };
 
 void MediaControlsImplTest::MouseDownAt(WebFloatPoint pos) {
@@ -875,10 +853,20 @@
   void SetUp() override {
     // DocumentParserTiming has DCHECKS to make sure time > 0.0.
     platform()->AdvanceClockSeconds(1);
+    platform()->SetAutoAdvanceNowToPendingTasks(false);
 
     ModernMediaControlsImplTest::SetUp();
   }
 
+  void TearDown() override {
+    platform()->SetAutoAdvanceNowToPendingTasks(true);
+  }
+
+  void ToggleOverflowMenu() {
+    MediaControls().ToggleOverflowMenu();
+    platform()->RunUntilIdle();
+  }
+
   bool IsCursorHidden() {
     const CSSPropertyValueSet* style = MediaControls().InlineStyle();
     if (!style)
@@ -1109,20 +1097,21 @@
             duration_display->CurrentValue());
 }
 
-TEST_F(MediaControlsImplTest, OverflowMenuMetricsTimeToAction) {
+TEST_F(MediaControlsImplTestWithMockScheduler,
+       OverflowMenuMetricsTimeToAction) {
   GetHistogramTester().ExpectTotalCount(kTimeToActionHistogramName, 0);
   GetHistogramTester().ExpectTotalCount(kTimeToDismissHistogramName, 0);
 
   // Test with the menu open for 42 seconds.
   ToggleOverflowMenu();
-  AdvanceClock(42);
+  platform()->RunForPeriodSeconds(42);
   ClickOverflowButton();
   GetHistogramTester().ExpectBucketCount(kTimeToActionHistogramName, 42, 1);
   GetHistogramTester().ExpectTotalCount(kTimeToActionHistogramName, 1);
 
   // Test with the menu open for 90 seconds.
   ToggleOverflowMenu();
-  AdvanceClock(90);
+  platform()->RunForPeriodSeconds(90);
   ClickOverflowButton();
 
   GetHistogramTester().ExpectBucketCount(kTimeToActionHistogramName, 90, 1);
@@ -1130,48 +1119,49 @@
 
   // Test with the menu open for 42 seconds.
   ToggleOverflowMenu();
-  AdvanceClock(42);
+  platform()->RunForPeriodSeconds(42);
   ClickOverflowButton();
   GetHistogramTester().ExpectBucketCount(kTimeToActionHistogramName, 42, 2);
   GetHistogramTester().ExpectTotalCount(kTimeToActionHistogramName, 3);
 
   // Test with the menu open for 1000 seconds.
   ToggleOverflowMenu();
-  AdvanceClock(1000);
+  platform()->RunForPeriodSeconds(1000);
   ClickOverflowButton();
   GetHistogramTester().ExpectBucketCount(kTimeToActionHistogramName, 100, 1);
   GetHistogramTester().ExpectTotalCount(kTimeToActionHistogramName, 4);
   GetHistogramTester().ExpectTotalCount(kTimeToDismissHistogramName, 0);
 }
 
-TEST_F(MediaControlsImplTest, OverflowMenuMetricsTimeToDismiss) {
+TEST_F(MediaControlsImplTestWithMockScheduler,
+       OverflowMenuMetricsTimeToDismiss) {
   GetHistogramTester().ExpectTotalCount(kTimeToDismissHistogramName, 0);
   GetHistogramTester().ExpectTotalCount(kTimeToActionHistogramName, 0);
 
   // Test with the menu open for 42 seconds.
   ToggleOverflowMenu();
-  AdvanceClock(42);
+  platform()->RunForPeriodSeconds(42);
   ToggleOverflowMenu();
   GetHistogramTester().ExpectBucketCount(kTimeToDismissHistogramName, 42, 1);
   GetHistogramTester().ExpectTotalCount(kTimeToDismissHistogramName, 1);
 
   // Test with the menu open for 90 seconds.
   ToggleOverflowMenu();
-  AdvanceClock(90);
+  platform()->RunForPeriodSeconds(90);
   ToggleOverflowMenu();
   GetHistogramTester().ExpectBucketCount(kTimeToDismissHistogramName, 90, 1);
   GetHistogramTester().ExpectTotalCount(kTimeToDismissHistogramName, 2);
 
   // Test with the menu open for 42 seconds.
   ToggleOverflowMenu();
-  AdvanceClock(42);
+  platform()->RunForPeriodSeconds(42);
   ToggleOverflowMenu();
   GetHistogramTester().ExpectBucketCount(kTimeToDismissHistogramName, 42, 2);
   GetHistogramTester().ExpectTotalCount(kTimeToDismissHistogramName, 3);
 
   // Test with the menu open for 1000 seconds.
   ToggleOverflowMenu();
-  AdvanceClock(1000);
+  platform()->RunForPeriodSeconds(1000);
   ToggleOverflowMenu();
   GetHistogramTester().ExpectBucketCount(kTimeToDismissHistogramName, 100, 1);
   GetHistogramTester().ExpectTotalCount(kTimeToDismissHistogramName, 4);
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate_test.cc b/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate_test.cc
index 09e9f75..9b48647 100644
--- a/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate_test.cc
+++ b/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate_test.cc
@@ -139,11 +139,6 @@
 class StubLocalFrameClientForOrientationLockDelegate final
     : public EmptyLocalFrameClient {
  public:
-  static StubLocalFrameClientForOrientationLockDelegate* Create() {
-    return MakeGarbageCollected<
-        StubLocalFrameClientForOrientationLockDelegate>();
-  }
-
   std::unique_ptr<WebMediaPlayer> CreateWebMediaPlayer(
       HTMLMediaElement&,
       const WebMediaPlayerSource&,
@@ -185,7 +180,8 @@
     clients.chrome_client = chrome_client_.Get();
 
     SetupPageWithClients(
-        &clients, StubLocalFrameClientForOrientationLockDelegate::Create());
+        &clients,
+        MakeGarbageCollected<StubLocalFrameClientForOrientationLockDelegate>());
     previous_orientation_event_value_ =
         RuntimeEnabledFeatures::OrientationEventEnabled();
 
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc b/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc
index c6427d0d..5ff1999 100644
--- a/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc
+++ b/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc
@@ -74,10 +74,6 @@
 
 class StubLocalFrameClient : public EmptyLocalFrameClient {
  public:
-  static StubLocalFrameClient* Create() {
-    return MakeGarbageCollected<StubLocalFrameClient>();
-  }
-
   std::unique_ptr<WebMediaPlayer> CreateWebMediaPlayer(
       HTMLMediaElement&,
       const WebMediaPlayerSource&,
@@ -109,7 +105,8 @@
     FillWithEmptyClients(clients);
     clients.chrome_client = chrome_client_.Get();
 
-    SetupPageWithClients(&clients, StubLocalFrameClient::Create());
+    SetupPageWithClients(&clients,
+                         MakeGarbageCollected<StubLocalFrameClient>());
     video_ = HTMLVideoElement::Create(GetDocument());
     GetVideo().setAttribute(kControlsAttr, g_empty_atom);
     // Most tests should call GetDocument().body()->AppendChild(&GetVideo());
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/auto_canvas_draw_listener.cc b/third_party/blink/renderer/modules/mediacapturefromelement/auto_canvas_draw_listener.cc
index 7b172990..b3e522e 100644
--- a/third_party/blink/renderer/modules/mediacapturefromelement/auto_canvas_draw_listener.cc
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/auto_canvas_draw_listener.cc
@@ -12,10 +12,4 @@
     std::unique_ptr<WebCanvasCaptureHandler> handler)
     : CanvasDrawListener(std::move(handler)) {}
 
-// static
-AutoCanvasDrawListener* AutoCanvasDrawListener::Create(
-    std::unique_ptr<WebCanvasCaptureHandler> handler) {
-  return MakeGarbageCollected<AutoCanvasDrawListener>(std::move(handler));
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/auto_canvas_draw_listener.h b/third_party/blink/renderer/modules/mediacapturefromelement/auto_canvas_draw_listener.h
index 343731a0..886dc8e 100644
--- a/third_party/blink/renderer/modules/mediacapturefromelement/auto_canvas_draw_listener.h
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/auto_canvas_draw_listener.h
@@ -18,10 +18,7 @@
   USING_GARBAGE_COLLECTED_MIXIN(AutoCanvasDrawListener);
 
  public:
-  static AutoCanvasDrawListener* Create(
-      std::unique_ptr<WebCanvasCaptureHandler>);
-
-  AutoCanvasDrawListener(std::unique_ptr<WebCanvasCaptureHandler>);
+  explicit AutoCanvasDrawListener(std::unique_ptr<WebCanvasCaptureHandler>);
   ~AutoCanvasDrawListener() override = default;
 
   void Trace(blink::Visitor* visitor) override {}
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_media_stream_track.cc b/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_media_stream_track.cc
index 6f53c0f..3bf6ef9 100644
--- a/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_media_stream_track.cc
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_media_stream_track.cc
@@ -13,25 +13,6 @@
 
 namespace blink {
 
-CanvasCaptureMediaStreamTrack* CanvasCaptureMediaStreamTrack::Create(
-    MediaStreamComponent* component,
-    HTMLCanvasElement* element,
-    ExecutionContext* context,
-    std::unique_ptr<WebCanvasCaptureHandler> handler) {
-  return MakeGarbageCollected<CanvasCaptureMediaStreamTrack>(
-      component, element, context, std::move(handler));
-}
-
-CanvasCaptureMediaStreamTrack* CanvasCaptureMediaStreamTrack::Create(
-    MediaStreamComponent* component,
-    HTMLCanvasElement* element,
-    ExecutionContext* context,
-    std::unique_ptr<WebCanvasCaptureHandler> handler,
-    double frame_rate) {
-  return MakeGarbageCollected<CanvasCaptureMediaStreamTrack>(
-      component, element, context, std::move(handler), frame_rate);
-}
-
 HTMLCanvasElement* CanvasCaptureMediaStreamTrack::canvas() const {
   return canvas_element_.Get();
 }
@@ -71,7 +52,8 @@
     ExecutionContext* context,
     std::unique_ptr<WebCanvasCaptureHandler> handler)
     : MediaStreamTrack(context, component), canvas_element_(element) {
-  draw_listener_ = AutoCanvasDrawListener::Create(std::move(handler));
+  draw_listener_ =
+      MakeGarbageCollected<AutoCanvasDrawListener>(std::move(handler));
   canvas_element_->AddListener(draw_listener_.Get());
 }
 
@@ -83,7 +65,8 @@
     double frame_rate)
     : MediaStreamTrack(context, component), canvas_element_(element) {
   if (frame_rate == 0) {
-    draw_listener_ = OnRequestCanvasDrawListener::Create(std::move(handler));
+    draw_listener_ =
+        MakeGarbageCollected<OnRequestCanvasDrawListener>(std::move(handler));
   } else {
     draw_listener_ = TimedCanvasDrawListener::Create(std::move(handler),
                                                      frame_rate, context);
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_media_stream_track.h b/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_media_stream_track.h
index e2a24847..f45b82d 100644
--- a/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_media_stream_track.h
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_media_stream_track.h
@@ -20,18 +20,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static CanvasCaptureMediaStreamTrack* Create(
-      MediaStreamComponent*,
-      HTMLCanvasElement*,
-      ExecutionContext*,
-      std::unique_ptr<WebCanvasCaptureHandler>);
-  static CanvasCaptureMediaStreamTrack* Create(
-      MediaStreamComponent*,
-      HTMLCanvasElement*,
-      ExecutionContext*,
-      std::unique_ptr<WebCanvasCaptureHandler>,
-      double frame_rate);
-
   CanvasCaptureMediaStreamTrack(const CanvasCaptureMediaStreamTrack&,
                                 MediaStreamComponent*);
   CanvasCaptureMediaStreamTrack(MediaStreamComponent*,
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/html_canvas_element_capture.cc b/third_party/blink/renderer/modules/mediacapturefromelement/html_canvas_element_capture.cc
index d4a2845d..c4ca120 100644
--- a/third_party/blink/renderer/modules/mediacapturefromelement/html_canvas_element_capture.cc
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/html_canvas_element_capture.cc
@@ -75,10 +75,10 @@
   DCHECK(context);
   CanvasCaptureMediaStreamTrack* canvas_track;
   if (given_frame_rate) {
-    canvas_track = CanvasCaptureMediaStreamTrack::Create(
+    canvas_track = MakeGarbageCollected<CanvasCaptureMediaStreamTrack>(
         track, &element, context, std::move(handler), frame_rate);
   } else {
-    canvas_track = CanvasCaptureMediaStreamTrack::Create(
+    canvas_track = MakeGarbageCollected<CanvasCaptureMediaStreamTrack>(
         track, &element, context, std::move(handler));
   }
   // We want to capture a frame in the beginning.
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/on_request_canvas_draw_listener.cc b/third_party/blink/renderer/modules/mediacapturefromelement/on_request_canvas_draw_listener.cc
index aefa952..e914c3c 100644
--- a/third_party/blink/renderer/modules/mediacapturefromelement/on_request_canvas_draw_listener.cc
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/on_request_canvas_draw_listener.cc
@@ -14,12 +14,6 @@
 
 OnRequestCanvasDrawListener::~OnRequestCanvasDrawListener() = default;
 
-// static
-OnRequestCanvasDrawListener* OnRequestCanvasDrawListener::Create(
-    std::unique_ptr<WebCanvasCaptureHandler> handler) {
-  return MakeGarbageCollected<OnRequestCanvasDrawListener>(std::move(handler));
-}
-
 void OnRequestCanvasDrawListener::SendNewFrame(
     sk_sp<SkImage> image,
     base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider) {
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/on_request_canvas_draw_listener.h b/third_party/blink/renderer/modules/mediacapturefromelement/on_request_canvas_draw_listener.h
index 617b7cce..84e822a 100644
--- a/third_party/blink/renderer/modules/mediacapturefromelement/on_request_canvas_draw_listener.h
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/on_request_canvas_draw_listener.h
@@ -20,11 +20,10 @@
   USING_GARBAGE_COLLECTED_MIXIN(OnRequestCanvasDrawListener);
 
  public:
-  OnRequestCanvasDrawListener(std::unique_ptr<WebCanvasCaptureHandler>);
+  explicit OnRequestCanvasDrawListener(
+      std::unique_ptr<WebCanvasCaptureHandler>);
   ~OnRequestCanvasDrawListener() override;
 
-  static OnRequestCanvasDrawListener* Create(
-      std::unique_ptr<WebCanvasCaptureHandler>);
   void SendNewFrame(
       sk_sp<SkImage>,
       base::WeakPtr<WebGraphicsContext3DProviderWrapper>) override;
diff --git a/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc b/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc
index 98bdee2..b6aec7ff 100644
--- a/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc
+++ b/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc
@@ -360,8 +360,8 @@
 }
 
 void MediaRecorder::CreateBlobEvent(Blob* blob, double timecode) {
-  ScheduleDispatchEvent(
-      BlobEvent::Create(event_type_names::kDataavailable, blob, timecode));
+  ScheduleDispatchEvent(MakeGarbageCollected<BlobEvent>(
+      event_type_names::kDataavailable, blob, timecode));
 }
 
 void MediaRecorder::StopRecording() {
diff --git a/third_party/blink/renderer/modules/mediasession/media_session.cc b/third_party/blink/renderer/modules/mediasession/media_session.cc
index 1394c648..54fbccd 100644
--- a/third_party/blink/renderer/modules/mediasession/media_session.cc
+++ b/third_party/blink/renderer/modules/mediasession/media_session.cc
@@ -115,10 +115,6 @@
       playback_state_(mojom::blink::MediaSessionPlaybackState::NONE),
       client_binding_(this) {}
 
-MediaSession* MediaSession::Create(ExecutionContext* execution_context) {
-  return MakeGarbageCollected<MediaSession>(execution_context);
-}
-
 void MediaSession::Dispose() {
   client_binding_.Close();
 }
diff --git a/third_party/blink/renderer/modules/mediasession/media_session.h b/third_party/blink/renderer/modules/mediasession/media_session.h
index 081504c..eb455b8 100644
--- a/third_party/blink/renderer/modules/mediasession/media_session.h
+++ b/third_party/blink/renderer/modules/mediasession/media_session.h
@@ -30,8 +30,6 @@
   USING_PRE_FINALIZER(MediaSession, Dispose);
 
  public:
-  static MediaSession* Create(ExecutionContext*);
-
   explicit MediaSession(ExecutionContext*);
 
   void Dispose();
diff --git a/third_party/blink/renderer/modules/mediasession/navigator_media_session.cc b/third_party/blink/renderer/modules/mediasession/navigator_media_session.cc
index e9b0122b..54c7ea5 100644
--- a/third_party/blink/renderer/modules/mediasession/navigator_media_session.cc
+++ b/third_party/blink/renderer/modules/mediasession/navigator_media_session.cc
@@ -34,8 +34,10 @@
 MediaSession* NavigatorMediaSession::mediaSession(ScriptState* script_state,
                                                   Navigator& navigator) {
   NavigatorMediaSession& self = NavigatorMediaSession::From(navigator);
-  if (!self.session_)
-    self.session_ = MediaSession::Create(ExecutionContext::From(script_state));
+  if (!self.session_) {
+    self.session_ = MakeGarbageCollected<MediaSession>(
+        ExecutionContext::From(script_state));
+  }
   return self.session_.Get();
 }
 
diff --git a/third_party/blink/renderer/modules/mediasource/html_video_element_media_source.cc b/third_party/blink/renderer/modules/mediasource/html_video_element_media_source.cc
index 029dcbb2..8b308d4e 100644
--- a/third_party/blink/renderer/modules/mediasource/html_video_element_media_source.cc
+++ b/third_party/blink/renderer/modules/mediasource/html_video_element_media_source.cc
@@ -47,8 +47,8 @@
     corrupted = web_media_player->CorruptedFrameCount();
   }
 
-  return VideoPlaybackQuality::Create(video_element.GetDocument(), total,
-                                      dropped, corrupted);
+  return MakeGarbageCollected<VideoPlaybackQuality>(video_element.GetDocument(),
+                                                    total, dropped, corrupted);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/mediasource/media_source.cc b/third_party/blink/renderer/modules/mediasource/media_source.cc
index 8f3dadc..7f9c3745 100644
--- a/third_party/blink/renderer/modules/mediasource/media_source.cc
+++ b/third_party/blink/renderer/modules/mediasource/media_source.cc
@@ -114,11 +114,12 @@
           MakeGarbageCollected<EventQueue>(context,
                                            TaskType::kMediaElementEvent)),
       attached_element_(nullptr),
-      source_buffers_(SourceBufferList::Create(GetExecutionContext(),
-                                               async_event_queue_.Get())),
+      source_buffers_(
+          MakeGarbageCollected<SourceBufferList>(GetExecutionContext(),
+                                                 async_event_queue_.Get())),
       active_source_buffers_(
-          SourceBufferList::Create(GetExecutionContext(),
-                                   async_event_queue_.Get())),
+          MakeGarbageCollected<SourceBufferList>(GetExecutionContext(),
+                                                 async_event_queue_.Get())),
       live_seekable_range_(TimeRanges::Create()),
       added_to_registry_counter_(0) {
   DVLOG(1) << __func__ << " this=" << this;
diff --git a/third_party/blink/renderer/modules/mediasource/source_buffer.cc b/third_party/blink/renderer/modules/mediasource/source_buffer.cc
index bae97df8..c4a34dd3 100644
--- a/third_party/blink/renderer/modules/mediasource/source_buffer.cc
+++ b/third_party/blink/renderer/modules/mediasource/source_buffer.cc
@@ -116,7 +116,7 @@
     : ContextLifecycleObserver(source->GetExecutionContext()),
       web_source_buffer_(std::move(web_source_buffer)),
       source_(source),
-      track_defaults_(TrackDefaultList::Create()),
+      track_defaults_(MakeGarbageCollected<TrackDefaultList>()),
       async_event_queue_(async_event_queue),
       mode_(SegmentsKeyword()),
       updating_(false),
diff --git a/third_party/blink/renderer/modules/mediasource/source_buffer_list.h b/third_party/blink/renderer/modules/mediasource/source_buffer_list.h
index 45ead0f..f32ac78 100644
--- a/third_party/blink/renderer/modules/mediasource/source_buffer_list.h
+++ b/third_party/blink/renderer/modules/mediasource/source_buffer_list.h
@@ -46,11 +46,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(SourceBufferList);
 
  public:
-  static SourceBufferList* Create(ExecutionContext* context,
-                                  EventQueue* async_event_queue) {
-    return MakeGarbageCollected<SourceBufferList>(context, async_event_queue);
-  }
-
   SourceBufferList(ExecutionContext*, EventQueue*);
   ~SourceBufferList() override;
 
diff --git a/third_party/blink/renderer/modules/mediasource/track_default_list.cc b/third_party/blink/renderer/modules/mediasource/track_default_list.cc
index 5b8a0b11..dd6a828 100644
--- a/third_party/blink/renderer/modules/mediasource/track_default_list.cc
+++ b/third_party/blink/renderer/modules/mediasource/track_default_list.cc
@@ -10,10 +10,6 @@
 
 namespace blink {
 
-TrackDefaultList* TrackDefaultList::Create() {
-  return MakeGarbageCollected<TrackDefaultList>();
-}
-
 TrackDefaultList* TrackDefaultList::Create(
     const HeapVector<Member<TrackDefault>>& track_defaults,
     ExceptionState& exception_state) {
diff --git a/third_party/blink/renderer/modules/mediasource/track_default_list.h b/third_party/blink/renderer/modules/mediasource/track_default_list.h
index ba6f658..7dd5f0f 100644
--- a/third_party/blink/renderer/modules/mediasource/track_default_list.h
+++ b/third_party/blink/renderer/modules/mediasource/track_default_list.h
@@ -17,8 +17,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static TrackDefaultList* Create();  // Creates an empty TrackDefaultList.
-
   // Implement the IDL
   static TrackDefaultList* Create(const HeapVector<Member<TrackDefault>>&,
                                   ExceptionState&);
diff --git a/third_party/blink/renderer/modules/mediasource/video_playback_quality.cc b/third_party/blink/renderer/modules/mediasource/video_playback_quality.cc
index 60943da..d81bd335 100644
--- a/third_party/blink/renderer/modules/mediasource/video_playback_quality.cc
+++ b/third_party/blink/renderer/modules/mediasource/video_playback_quality.cc
@@ -37,16 +37,6 @@
 
 namespace blink {
 
-VideoPlaybackQuality* VideoPlaybackQuality::Create(
-    const Document& document,
-    unsigned total_video_frames,
-    unsigned dropped_video_frames,
-    unsigned corrupted_video_frames) {
-  return MakeGarbageCollected<VideoPlaybackQuality>(
-      document, total_video_frames, dropped_video_frames,
-      corrupted_video_frames);
-}
-
 VideoPlaybackQuality::VideoPlaybackQuality(const Document& document,
                                            unsigned total_video_frames,
                                            unsigned dropped_video_frames,
diff --git a/third_party/blink/renderer/modules/mediasource/video_playback_quality.h b/third_party/blink/renderer/modules/mediasource/video_playback_quality.h
index 53e9d47..ea038e5 100644
--- a/third_party/blink/renderer/modules/mediasource/video_playback_quality.h
+++ b/third_party/blink/renderer/modules/mediasource/video_playback_quality.h
@@ -42,11 +42,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static VideoPlaybackQuality* Create(const Document&,
-                                      unsigned total_video_frames,
-                                      unsigned dropped_video_frames,
-                                      unsigned corrupted_video_frames);
-
   VideoPlaybackQuality(const Document&,
                        unsigned total_video_frames,
                        unsigned dropped_video_frames,
diff --git a/third_party/blink/renderer/modules/mediastream/apply_constraints_request.cc b/third_party/blink/renderer/modules/mediastream/apply_constraints_request.cc
index 65752f51..c7d6a531 100644
--- a/third_party/blink/renderer/modules/mediastream/apply_constraints_request.cc
+++ b/third_party/blink/renderer/modules/mediastream/apply_constraints_request.cc
@@ -10,18 +10,11 @@
 
 namespace blink {
 
-ApplyConstraintsRequest* ApplyConstraintsRequest::Create(
-    const WebMediaStreamTrack& track,
-    const WebMediaConstraints& constraints,
-    ScriptPromiseResolver* resolver) {
-  return MakeGarbageCollected<ApplyConstraintsRequest>(track, constraints,
-                                                       resolver);
-}
-
 ApplyConstraintsRequest* ApplyConstraintsRequest::CreateForTesting(
     const WebMediaStreamTrack& track,
     const WebMediaConstraints& constraints) {
-  return Create(track, constraints, nullptr);
+  return MakeGarbageCollected<ApplyConstraintsRequest>(track, constraints,
+                                                       nullptr);
 }
 
 ApplyConstraintsRequest::ApplyConstraintsRequest(
@@ -47,8 +40,9 @@
 
 void ApplyConstraintsRequest::RequestFailed(const String& constraint,
                                             const String& message) {
-  if (resolver_)
+  if (resolver_) {
     resolver_->Reject(OverconstrainedError::Create(constraint, message));
+  }
   track_.Reset();
 }
 
diff --git a/third_party/blink/renderer/modules/mediastream/apply_constraints_request.h b/third_party/blink/renderer/modules/mediastream/apply_constraints_request.h
index 61b4d96..ab72823 100644
--- a/third_party/blink/renderer/modules/mediastream/apply_constraints_request.h
+++ b/third_party/blink/renderer/modules/mediastream/apply_constraints_request.h
@@ -18,9 +18,6 @@
 class MODULES_EXPORT ApplyConstraintsRequest final
     : public GarbageCollectedFinalized<ApplyConstraintsRequest> {
  public:
-  static ApplyConstraintsRequest* Create(const WebMediaStreamTrack&,
-                                         const WebMediaConstraints&,
-                                         ScriptPromiseResolver*);
   static ApplyConstraintsRequest* CreateForTesting(const WebMediaStreamTrack&,
                                                    const WebMediaConstraints&);
 
diff --git a/third_party/blink/renderer/modules/mediastream/media_device_info.cc b/third_party/blink/renderer/modules/mediastream/media_device_info.cc
index 325477cc..bddcf8c 100644
--- a/third_party/blink/renderer/modules/mediastream/media_device_info.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_device_info.cc
@@ -31,14 +31,6 @@
 
 namespace blink {
 
-MediaDeviceInfo* MediaDeviceInfo::Create(const String& device_id,
-                                         const String& label,
-                                         const String& group_id,
-                                         MediaDeviceType device_type) {
-  return MakeGarbageCollected<MediaDeviceInfo>(device_id, label, group_id,
-                                               device_type);
-}
-
 MediaDeviceInfo::MediaDeviceInfo(const String& device_id,
                                  const String& label,
                                  const String& group_id,
diff --git a/third_party/blink/renderer/modules/mediastream/media_device_info.h b/third_party/blink/renderer/modules/mediastream/media_device_info.h
index d91fa45..a2f807e 100644
--- a/third_party/blink/renderer/modules/mediastream/media_device_info.h
+++ b/third_party/blink/renderer/modules/mediastream/media_device_info.h
@@ -43,11 +43,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static MediaDeviceInfo* Create(const String& device_id,
-                                 const String& label,
-                                 const String& group_id,
-                                 MediaDeviceType);
-
   MediaDeviceInfo(const String& device_id,
                   const String& label,
                   const String& group_id,
diff --git a/third_party/blink/renderer/modules/mediastream/media_devices.cc b/third_party/blink/renderer/modules/mediastream/media_devices.cc
index 0d3912ce..a55f9f1 100644
--- a/third_party/blink/renderer/modules/mediastream/media_devices.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_devices.cc
@@ -32,10 +32,6 @@
 
 class PromiseResolverCallbacks final : public UserMediaRequest::Callbacks {
  public:
-  static PromiseResolverCallbacks* Create(ScriptPromiseResolver* resolver) {
-    return MakeGarbageCollected<PromiseResolverCallbacks>(resolver);
-  }
-
   explicit PromiseResolverCallbacks(ScriptPromiseResolver* resolver)
       : resolver_(resolver) {}
   ~PromiseResolverCallbacks() override = default;
@@ -60,10 +56,6 @@
 
 }  // namespace
 
-MediaDevices* MediaDevices::Create(ExecutionContext* context) {
-  return MakeGarbageCollected<MediaDevices>(context);
-}
-
 MediaDevices::MediaDevices(ExecutionContext* context)
     : ContextLifecycleObserver(context), stopped_(false), binding_(this) {}
 
@@ -110,8 +102,7 @@
     const MediaStreamConstraints* options,
     ExceptionState& exception_state) {
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
-  PromiseResolverCallbacks* callbacks =
-      PromiseResolverCallbacks::Create(resolver);
+  auto* callbacks = MakeGarbageCollected<PromiseResolverCallbacks>(resolver);
 
   Document* document = To<Document>(ExecutionContext::From(script_state));
   UserMediaController* user_media =
@@ -322,9 +313,9 @@
         }
         media_devices.push_back(input_device_info);
       } else {
-        media_devices.push_back(
-            MediaDeviceInfo::Create(device_info->device_id, device_info->label,
-                                    device_info->group_id, device_type));
+        media_devices.push_back(MakeGarbageCollected<MediaDeviceInfo>(
+            device_info->device_id, device_info->label, device_info->group_id,
+            device_type));
       }
     }
   }
diff --git a/third_party/blink/renderer/modules/mediastream/media_devices.h b/third_party/blink/renderer/modules/mediastream/media_devices.h
index 49de9b65..8a40990 100644
--- a/third_party/blink/renderer/modules/mediastream/media_devices.h
+++ b/third_party/blink/renderer/modules/mediastream/media_devices.h
@@ -37,8 +37,6 @@
   USING_PRE_FINALIZER(MediaDevices, Dispose);
 
  public:
-  static MediaDevices* Create(ExecutionContext*);
-
   explicit MediaDevices(ExecutionContext*);
   ~MediaDevices() override;
 
diff --git a/third_party/blink/renderer/modules/mediastream/media_devices_test.cc b/third_party/blink/renderer/modules/mediastream/media_devices_test.cc
index 4e9b05c..f3efdbe 100644
--- a/third_party/blink/renderer/modules/mediastream/media_devices_test.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_devices_test.cc
@@ -214,7 +214,7 @@
 
   MediaDevices* GetMediaDevices(ExecutionContext* context) {
     if (!media_devices_) {
-      media_devices_ = MediaDevices::Create(context);
+      media_devices_ = MakeGarbageCollected<MediaDevices>(context);
       media_devices_->SetDispatcherHostForTesting(
           dispatcher_host_->CreateInterfacePtrAndBind());
     }
@@ -232,7 +232,7 @@
   void DevicesEnumerated(const MediaDeviceInfoVector& device_infos) {
     devices_enumerated_ = true;
     for (wtf_size_t i = 0; i < device_infos.size(); i++) {
-      device_infos_->push_back(MediaDeviceInfo::Create(
+      device_infos_->push_back(MakeGarbageCollected<MediaDeviceInfo>(
           device_infos[i]->deviceId(), device_infos[i]->label(),
           device_infos[i]->groupId(), device_infos[i]->DeviceType()));
     }
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream.cc b/third_party/blink/renderer/modules/mediastream/media_stream.cc
index 2296ede..7b8d778 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream.cc
@@ -31,6 +31,7 @@
 #include "third_party/blink/renderer/modules/mediastream/media_stream_track_event.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/mediastream/media_stream_center.h"
 #include "third_party/blink/renderer/platform/mediastream/media_stream_source.h"
 
@@ -185,8 +186,8 @@
     video_components.push_back((*iter)->Component());
   }
 
-  descriptor_ =
-      MediaStreamDescriptor::Create(audio_components, video_components);
+  descriptor_ = MakeGarbageCollected<MediaStreamDescriptor>(audio_components,
+                                                            video_components);
   descriptor_->SetClient(this);
 
   audio_tracks_ = audio_tracks;
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_track.cc b/third_party/blink/renderer/modules/mediastream/media_stream_track.cc
index 6a2ba35..07f4c759 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_track.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_track.cc
@@ -624,8 +624,8 @@
     return promise;
   }
 
-  user_media->ApplyConstraints(
-      ApplyConstraintsRequest::Create(Component(), web_constraints, resolver));
+  user_media->ApplyConstraints(MakeGarbageCollected<ApplyConstraintsRequest>(
+      Component(), web_constraints, resolver));
   return promise;
 }
 
diff --git a/third_party/blink/renderer/modules/mediastream/navigator_user_media.cc b/third_party/blink/renderer/modules/mediastream/navigator_user_media.cc
index 8782de1e..35e49dd 100644
--- a/third_party/blink/renderer/modules/mediastream/navigator_user_media.cc
+++ b/third_party/blink/renderer/modules/mediastream/navigator_user_media.cc
@@ -14,7 +14,7 @@
 
 NavigatorUserMedia::NavigatorUserMedia(Navigator& navigator)
     : Supplement<Navigator>(navigator),
-      media_devices_(MediaDevices::Create(
+      media_devices_(MakeGarbageCollected<MediaDevices>(
           navigator.GetFrame() ? navigator.GetFrame()->GetDocument()
                                : nullptr)) {}
 
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_request.cc b/third_party/blink/renderer/modules/mediastream/user_media_request.cc
index ec6d7b6..dd100dc4 100644
--- a/third_party/blink/renderer/modules/mediastream/user_media_request.cc
+++ b/third_party/blink/renderer/modules/mediastream/user_media_request.cc
@@ -295,12 +295,6 @@
 
 class UserMediaRequest::V8Callbacks final : public UserMediaRequest::Callbacks {
  public:
-  static V8Callbacks* Create(
-      V8NavigatorUserMediaSuccessCallback* success_callback,
-      V8NavigatorUserMediaErrorCallback* error_callback) {
-    return MakeGarbageCollected<V8Callbacks>(success_callback, error_callback);
-  }
-
   V8Callbacks(V8NavigatorUserMediaSuccessCallback* success_callback,
               V8NavigatorUserMediaErrorCallback* error_callback)
       : success_callback_(ToV8PersistentCallbackFunction(success_callback)),
@@ -418,9 +412,10 @@
     V8NavigatorUserMediaSuccessCallback* success_callback,
     V8NavigatorUserMediaErrorCallback* error_callback,
     MediaErrorState& error_state) {
-  return Create(context, controller, WebUserMediaRequest::MediaType::kUserMedia,
-                options, V8Callbacks::Create(success_callback, error_callback),
-                error_state);
+  return Create(
+      context, controller, WebUserMediaRequest::MediaType::kUserMedia, options,
+      MakeGarbageCollected<V8Callbacks>(success_callback, error_callback),
+      error_state);
 }
 
 UserMediaRequest* UserMediaRequest::CreateForTesting(
diff --git a/third_party/blink/renderer/modules/modules_initializer.cc b/third_party/blink/renderer/modules/modules_initializer.cc
index bb7c448..8b29287e 100644
--- a/third_party/blink/renderer/modules/modules_initializer.cc
+++ b/third_party/blink/renderer/modules/modules_initializer.cc
@@ -182,7 +182,7 @@
   ProvideLocalFileSystemTo(frame, std::make_unique<LocalFileSystemClient>());
   NavigatorContentUtils::ProvideTo(
       *frame.DomWindow()->navigator(),
-      NavigatorContentUtilsClient::Create(web_frame));
+      MakeGarbageCollected<NavigatorContentUtilsClient>(web_frame));
 
   ScreenOrientationControllerImpl::ProvideTo(frame);
   if (RuntimeEnabledFeatures::PresentationEnabled())
diff --git a/third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils_client.cc b/third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils_client.cc
index 47c9692..6731062 100644
--- a/third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils_client.cc
+++ b/third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils_client.cc
@@ -10,11 +10,6 @@
 
 namespace blink {
 
-NavigatorContentUtilsClient* NavigatorContentUtilsClient::Create(
-    WebLocalFrameImpl* web_frame) {
-  return MakeGarbageCollected<NavigatorContentUtilsClient>(web_frame);
-}
-
 NavigatorContentUtilsClient::NavigatorContentUtilsClient(
     WebLocalFrameImpl* web_frame)
     : web_frame_(web_frame) {}
diff --git a/third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils_client.h b/third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils_client.h
index be6ef18..98f1abb 100644
--- a/third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils_client.h
+++ b/third_party/blink/renderer/modules/navigatorcontentutils/navigator_content_utils_client.h
@@ -17,8 +17,6 @@
 class MODULES_EXPORT NavigatorContentUtilsClient
     : public GarbageCollectedFinalized<NavigatorContentUtilsClient> {
  public:
-  static NavigatorContentUtilsClient* Create(WebLocalFrameImpl*);
-
   explicit NavigatorContentUtilsClient(WebLocalFrameImpl*);
   virtual ~NavigatorContentUtilsClient() = default;
 
diff --git a/third_party/blink/renderer/modules/netinfo/navigator_network_information.cc b/third_party/blink/renderer/modules/netinfo/navigator_network_information.cc
index 0b2e261..98c4dad0 100644
--- a/third_party/blink/renderer/modules/netinfo/navigator_network_information.cc
+++ b/third_party/blink/renderer/modules/netinfo/navigator_network_information.cc
@@ -42,7 +42,7 @@
 NetworkInformation* NavigatorNetworkInformation::connection() {
   if (!connection_ && GetFrame()) {
     DCHECK(GetFrame()->DomWindow());
-    connection_ = NetworkInformation::Create(
+    connection_ = MakeGarbageCollected<NetworkInformation>(
         GetFrame()->DomWindow()->GetExecutionContext());
   }
   return connection_.Get();
diff --git a/third_party/blink/renderer/modules/netinfo/network_information.cc b/third_party/blink/renderer/modules/netinfo/network_information.cc
index 4d82f39..e9d40b74 100644
--- a/third_party/blink/renderer/modules/netinfo/network_information.cc
+++ b/third_party/blink/renderer/modules/netinfo/network_information.cc
@@ -73,10 +73,6 @@
 
 }  // namespace
 
-NetworkInformation* NetworkInformation::Create(ExecutionContext* context) {
-  return MakeGarbageCollected<NetworkInformation>(context);
-}
-
 NetworkInformation::~NetworkInformation() {
   DCHECK(!IsObserving());
 }
diff --git a/third_party/blink/renderer/modules/netinfo/network_information.h b/third_party/blink/renderer/modules/netinfo/network_information.h
index 6d53d4f..22fe139 100644
--- a/third_party/blink/renderer/modules/netinfo/network_information.h
+++ b/third_party/blink/renderer/modules/netinfo/network_information.h
@@ -27,8 +27,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static NetworkInformation* Create(ExecutionContext*);
-
   explicit NetworkInformation(ExecutionContext*);
   ~NetworkInformation() override;
 
diff --git a/third_party/blink/renderer/modules/netinfo/worker_navigator_network_information.cc b/third_party/blink/renderer/modules/netinfo/worker_navigator_network_information.cc
index cca89bee..ad29ae8 100644
--- a/third_party/blink/renderer/modules/netinfo/worker_navigator_network_information.cc
+++ b/third_party/blink/renderer/modules/netinfo/worker_navigator_network_information.cc
@@ -57,7 +57,7 @@
     ExecutionContext* context) {
   DCHECK(context);
   if (!connection_)
-    connection_ = NetworkInformation::Create(context);
+    connection_ = MakeGarbageCollected<NetworkInformation>(context);
   return connection_.Get();
 }
 
diff --git a/third_party/blink/renderer/modules/payments/BUILD.gn b/third_party/blink/renderer/modules/payments/BUILD.gn
index d9fa9400..8c22515 100644
--- a/third_party/blink/renderer/modules/payments/BUILD.gn
+++ b/third_party/blink/renderer/modules/payments/BUILD.gn
@@ -49,8 +49,6 @@
     "payment_state_resolver.h",
     "payments_validators.cc",
     "payments_validators.h",
-    "update_payment_details_function.cc",
-    "update_payment_details_function.h",
   ]
 
   deps = [
diff --git a/third_party/blink/renderer/modules/payments/payment_request.cc b/third_party/blink/renderer/modules/payments/payment_request.cc
index 83fb32e..3895841 100644
--- a/third_party/blink/renderer/modules/payments/payment_request.cc
+++ b/third_party/blink/renderer/modules/payments/payment_request.cc
@@ -54,7 +54,6 @@
 #include "third_party/blink/renderer/modules/payments/payment_shipping_option.h"
 #include "third_party/blink/renderer/modules/payments/payment_validation_errors.h"
 #include "third_party/blink/renderer/modules/payments/payments_validators.h"
-#include "third_party/blink/renderer/modules/payments/update_payment_details_function.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/mojo/mojo_helper.h"
@@ -211,6 +210,10 @@
 namespace blink {
 namespace {
 
+// If the website does not call complete() 60 seconds after show() has been
+// resolved, then behave as if the website called complete("fail").
+constexpr TimeDelta kCompleteTimeout = TimeDelta::FromSeconds(60);
+
 // Validates ShippingOption or PaymentItem, which happen to have identical
 // fields, except for "id", which is present only in ShippingOption.
 template <typename T>
@@ -788,11 +791,6 @@
 PaymentRequest::~PaymentRequest() = default;
 
 ScriptPromise PaymentRequest::show(ScriptState* script_state) {
-  return show(script_state, ScriptPromise());
-}
-
-ScriptPromise PaymentRequest::show(ScriptState* script_state,
-                                   ScriptPromise details_promise) {
   if (!script_state->ContextIsValid() || !LocalDOMWindow::From(script_state) ||
       !LocalDOMWindow::From(script_state)->GetFrame()) {
     return ScriptPromise::RejectWithDOMException(
@@ -822,22 +820,7 @@
                                            "Page popups are suppressed"));
   }
 
-  is_waiting_for_show_promise_to_resolve_ = !details_promise.IsEmpty();
-  payment_provider_->Show(is_user_gesture,
-                          is_waiting_for_show_promise_to_resolve_);
-  if (is_waiting_for_show_promise_to_resolve_) {
-    // If the website does not calculate the final shopping cart contents within
-    // 10 seconds, abort payment.
-    update_payment_details_timer_.StartOneShot(TimeDelta::FromSeconds(10),
-                                               FROM_HERE);
-    details_promise.Then(
-        UpdatePaymentDetailsFunction::CreateFunction(
-            script_state, this,
-            UpdatePaymentDetailsFunction::ResolveType::kFulfill),
-        UpdatePaymentDetailsFunction::CreateFunction(
-            script_state, this,
-            UpdatePaymentDetailsFunction::ResolveType::kReject));
-  }
+  payment_provider_->Show(is_user_gesture);
 
   accept_resolver_ = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
   return accept_resolver_->Promise();
@@ -1055,13 +1038,8 @@
 
 void PaymentRequest::OnUpdatePaymentDetails(
     const ScriptValue& details_script_value) {
-  ScriptPromiseResolver* resolver = GetPendingAcceptPromiseResolver();
-  if (!resolver || !payment_provider_ ||
-      !update_payment_details_timer_.IsActive()) {
+  if (!GetPendingAcceptPromiseResolver() || !payment_provider_)
     return;
-  }
-
-  update_payment_details_timer_.Stop();
 
   PaymentDetailsUpdate* details = PaymentDetailsUpdate::Create();
   ExceptionState exception_state(v8::Isolate::GetCurrent(),
@@ -1070,6 +1048,7 @@
   V8PaymentDetailsUpdate::ToImpl(details_script_value.GetIsolate(),
                                  details_script_value.V8Value(), details,
                                  exception_state);
+  ScriptPromiseResolver* resolver = GetPendingAcceptPromiseResolver();
   if (exception_state.HadException()) {
     resolver->Reject(exception_state.GetException());
     ClearResolversAndCloseMojoConnection();
@@ -1090,36 +1069,10 @@
   if (!options_->requestShipping())
     validated_details->shipping_options = base::nullopt;
 
-  if (is_waiting_for_show_promise_to_resolve_) {
-    is_waiting_for_show_promise_to_resolve_ = false;
-
-    if (!validated_details->total) {
-      resolver->Reject(
-          DOMException::Create(DOMExceptionCode::kInvalidStateError,
-                               "Must specify 'total' when resolving the "
-                               "promise passed into PaymentRequest.show()"));
-      ClearResolversAndCloseMojoConnection();
-      return;
-    }
-
-    if (!validated_details->error.IsEmpty()) {
-      resolver->Reject(
-          DOMException::Create(DOMExceptionCode::kInvalidStateError,
-                               "Cannot specify 'error' when resolving the "
-                               "promise passed into PaymentRequest.show()"));
-      ClearResolversAndCloseMojoConnection();
-      return;
-    }
-  }
-
   payment_provider_->UpdateWith(std::move(validated_details));
 }
 
 void PaymentRequest::OnUpdatePaymentDetailsFailure(const String& error) {
-  if (!payment_provider_)
-    return;
-  if (update_payment_details_timer_.IsActive())
-    update_payment_details_timer_.Stop();
   ScriptPromiseResolver* resolver = GetPendingAcceptPromiseResolver();
   if (resolver) {
     resolver->Reject(
@@ -1155,11 +1108,6 @@
   OnCompleteTimeout(nullptr);
 }
 
-void PaymentRequest::OnUpdatePaymentDetailsTimeoutForTesting() {
-  update_payment_details_timer_.Stop();
-  OnUpdatePaymentDetailsTimeout(nullptr);
-}
-
 PaymentRequest::PaymentRequest(
     ExecutionContext* execution_context,
     const HeapVector<Member<PaymentMethodData>>& method_data,
@@ -1172,12 +1120,7 @@
       complete_timer_(
           execution_context->GetTaskRunner(TaskType::kMiscPlatformAPI),
           this,
-          &PaymentRequest::OnCompleteTimeout),
-      update_payment_details_timer_(
-          execution_context->GetTaskRunner(TaskType::kMiscPlatformAPI),
-          this,
-          &PaymentRequest::OnUpdatePaymentDetailsTimeout),
-      is_waiting_for_show_promise_to_resolve_(false) {
+          &PaymentRequest::OnCompleteTimeout) {
   DCHECK(GetExecutionContext()->IsSecureContext());
 
   if (!AllowedToUsePaymentRequest(execution_context)) {
@@ -1364,9 +1307,7 @@
     return;
   }
 
-  // If the website does not call complete() 60 seconds after show() has been
-  // resolved, then behave as if the website called complete("fail").
-  complete_timer_.StartOneShot(TimeDelta::FromSeconds(60), FROM_HERE);
+  complete_timer_.StartOneShot(kCompleteTimeout, FROM_HERE);
 
   if (retry_resolver_) {
     DCHECK(payment_response_);
@@ -1574,14 +1515,6 @@
   ClearResolversAndCloseMojoConnection();
 }
 
-void PaymentRequest::OnUpdatePaymentDetailsTimeout(TimerBase*) {
-  OnUpdatePaymentDetailsFailure(
-      is_waiting_for_show_promise_to_resolve_
-          ? "Timed out waiting for a PaymentRequest.show(promise) to resolve."
-          : "Timed out waiting for a "
-            "PaymentRequestUpdateEvent.updateWith(promise) to resolve.");
-}
-
 void PaymentRequest::ClearResolversAndCloseMojoConnection() {
   complete_timer_.Stop();
   complete_resolver_.Clear();
@@ -1604,21 +1537,15 @@
     PaymentRequestUpdateEvent* event) {
   event->SetTarget(event_target);
   event->SetPaymentRequest(this);
-
-  // If the website does not calculate the updated shopping cart contents
-  // within 60 seconds, abort payment.
-  update_payment_details_timer_.StartOneShot(TimeDelta::FromSeconds(60),
-                                             FROM_HERE);
-
   event_target->DispatchEvent(*event);
   if (!event->is_waiting_for_update()) {
     // DispatchEvent runs synchronously. The method is_waiting_for_update()
-    // returns false if the merchant did not call event.updateWith() within the
-    // event handler, which is optional, so the renderer sends a message to the
-    // browser to re-enable UI interactions.
+    // returns true if the merchant called event.updateWith() within the event
+    // handler. Calling this method is optional. If the method is not called,
+    // the renderer sends a message to the browser to re-enable UI interactions.
     const String& message = String::Format(
-        "No updateWith() call in '%s' event handler. User may see outdated "
-        "line items and total.",
+        "No updateWith() call in '%s' event handler. User "
+        "may see outdated line items and total.",
         event->type().Ascii().data());
     GetExecutionContext()->AddConsoleMessage(
         ConsoleMessage::Create(mojom::ConsoleMessageSource::kJavaScript,
diff --git a/third_party/blink/renderer/modules/payments/payment_request.h b/third_party/blink/renderer/modules/payments/payment_request.h
index 49a5dde27..b7f7cc2 100644
--- a/third_party/blink/renderer/modules/payments/payment_request.h
+++ b/third_party/blink/renderer/modules/payments/payment_request.h
@@ -67,7 +67,6 @@
   ~PaymentRequest() override;
 
   ScriptPromise show(ScriptState*);
-  ScriptPromise show(ScriptState*, ScriptPromise details_promise);
   ScriptPromise abort(ScriptState*);
 
   const String& id() const { return id_; }
@@ -101,7 +100,6 @@
   void Trace(blink::Visitor*) override;
 
   void OnCompleteTimeoutForTesting();
-  void OnUpdatePaymentDetailsTimeoutForTesting();
 
   enum {
     // Implementation defined constants controlling the allowed list length
@@ -134,7 +132,6 @@
   void WarnNoFavicon() override;
 
   void OnCompleteTimeout(TimerBase*);
-  void OnUpdatePaymentDetailsTimeout(TimerBase*);
 
   // Clears the promise resolvers and closes the Mojo connection.
   void ClearResolversAndCloseMojoConnection();
@@ -166,8 +163,6 @@
   payments::mojom::blink::PaymentRequestPtr payment_provider_;
   mojo::Binding<payments::mojom::blink::PaymentRequestClient> client_binding_;
   TaskRunnerTimer<PaymentRequest> complete_timer_;
-  TaskRunnerTimer<PaymentRequest> update_payment_details_timer_;
-  bool is_waiting_for_show_promise_to_resolve_;
 
   DISALLOW_COPY_AND_ASSIGN(PaymentRequest);
 };
diff --git a/third_party/blink/renderer/modules/payments/payment_request.idl b/third_party/blink/renderer/modules/payments/payment_request.idl
index 97b3655..e2a1c83d 100644
--- a/third_party/blink/renderer/modules/payments/payment_request.idl
+++ b/third_party/blink/renderer/modules/payments/payment_request.idl
@@ -14,7 +14,7 @@
     Exposed=Window,
     ActiveScriptWrappable
 ] interface PaymentRequest : EventTarget {
-    [CallWith=ScriptState, NewObject] Promise<PaymentResponse> show(optional Promise<PaymentDetailsUpdate> detailsPromise);
+    [CallWith=ScriptState, NewObject] Promise<PaymentResponse> show();
     [CallWith=ScriptState, NewObject] Promise<void> abort();
     [CallWith=ScriptState, HighEntropy, Measure, NewObject] Promise<boolean> canMakePayment();
     [CallWith=ScriptState, HighEntropy, Measure, NewObject, RuntimeEnabled=PaymentRequestHasEnrolledInstrument] Promise<boolean> hasEnrolledInstrument();
diff --git a/third_party/blink/renderer/modules/payments/payment_request_delegate.h b/third_party/blink/renderer/modules/payments/payment_request_delegate.h
index 91abd7d..49dd9ad 100644
--- a/third_party/blink/renderer/modules/payments/payment_request_delegate.h
+++ b/third_party/blink/renderer/modules/payments/payment_request_delegate.h
@@ -13,21 +13,11 @@
 
 class ScriptValue;
 
-// The interface for updating the payment details (shopping cart, shipping
-// options, total) in response to shipping address or option change, or through
-// the promise passed into the PaymentRequest.show() method.
 class MODULES_EXPORT PaymentRequestDelegate : public GarbageCollectedMixin {
  public:
-  // Updates the payment details in response to a change in, e.g., shipping
-  // address. This stops the spinner in the UI.
   virtual void OnUpdatePaymentDetails(
       const ScriptValue& details_script_value) = 0;
-
-  // Called when the merchant failed to update the payment details in response
-  // to a change in, e.g., shipping address. This will abort the payment.
   virtual void OnUpdatePaymentDetailsFailure(const String& error) = 0;
-
-  // Whether the PaymentRequest.show() or PaymentResponse.retry() is ongoing.
   virtual bool IsInteractive() const = 0;
 
  protected:
diff --git a/third_party/blink/renderer/modules/payments/payment_request_test.cc b/third_party/blink/renderer/modules/payments/payment_request_test.cc
index 8f6e899b502..2be918d 100644
--- a/third_party/blink/renderer/modules/payments/payment_request_test.cc
+++ b/third_party/blink/renderer/modules/payments/payment_request_test.cc
@@ -370,8 +370,6 @@
   request->show(scope.GetScriptState())
       .Then(funcs.ExpectNoCall(), funcs.ExpectCall(&error_message));
 
-  static_cast<payments::mojom::blink::PaymentRequestClient*>(request)
-      ->OnShippingAddressChange(BuildPaymentAddressForTest());
   request->OnUpdatePaymentDetailsFailure("oops");
 
   v8::MicrotasksScope::PerformCheckpoint(scope.GetScriptState()->GetIsolate());
@@ -407,8 +405,6 @@
   request->show(scope.GetScriptState())
       .Then(funcs.ExpectNoCall(), funcs.ExpectCall());
 
-  static_cast<payments::mojom::blink::PaymentRequestClient*>(request)
-      ->OnShippingAddressChange(BuildPaymentAddressForTest());
   request->OnUpdatePaymentDetails(
       ScriptValue::From(scope.GetScriptState(), "NotPaymentDetails"));
 }
@@ -425,8 +421,6 @@
   request->show(scope.GetScriptState())
       .Then(funcs.ExpectNoCall(), funcs.ExpectCall());
 
-  static_cast<payments::mojom::blink::PaymentRequestClient*>(request)
-      ->OnShippingAddressChange(BuildPaymentAddressForTest());
   request->OnUpdatePaymentDetails(
       ScriptValue::From(
           scope.GetScriptState(),
@@ -452,8 +446,6 @@
   EXPECT_TRUE(request->shippingOption().IsNull());
   request->show(scope.GetScriptState())
       .Then(funcs.ExpectNoCall(), funcs.ExpectNoCall());
-  static_cast<payments::mojom::blink::PaymentRequestClient*>(request)
-      ->OnShippingAddressChange(BuildPaymentAddressForTest());
   String detail_with_shipping_options =
       "{\"total\": {\"label\": \"Total\", \"amount\": {\"currency\": \"USD\", "
       "\"value\": \"5.00\"}},"
@@ -468,8 +460,6 @@
                                        scope.GetExceptionState())));
   EXPECT_FALSE(scope.GetExceptionState().HadException());
   EXPECT_EQ("standardShippingOption", request->shippingOption());
-  static_cast<payments::mojom::blink::PaymentRequestClient*>(request)
-      ->OnShippingAddressChange(BuildPaymentAddressForTest());
   String detail_without_shipping_options =
       "{\"total\": {\"label\": \"Total\", \"amount\": {\"currency\": \"USD\", "
       "\"value\": \"5.00\"}}}";
@@ -529,8 +519,6 @@
   EXPECT_FALSE(scope.GetExceptionState().HadException());
   request->show(scope.GetScriptState())
       .Then(funcs.ExpectNoCall(), funcs.ExpectNoCall());
-  static_cast<payments::mojom::blink::PaymentRequestClient*>(request)
-      ->OnShippingAddressChange(BuildPaymentAddressForTest());
   String detail =
       "{\"total\": {\"label\": \"Total\", \"amount\": {\"currency\": \"USD\", "
       "\"value\": \"5.00\"}},"
diff --git a/third_party/blink/renderer/modules/payments/payment_request_update_event.cc b/third_party/blink/renderer/modules/payments/payment_request_update_event.cc
index 7af3e8c..44fafee 100644
--- a/third_party/blink/renderer/modules/payments/payment_request_update_event.cc
+++ b/third_party/blink/renderer/modules/payments/payment_request_update_event.cc
@@ -11,11 +11,71 @@
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/modules/payments/payment_request_delegate.h"
-#include "third_party/blink/renderer/modules/payments/update_payment_details_function.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
+namespace {
+
+// Reject the payment request if the page does not resolve the promise from
+// updateWith within 60 seconds.
+constexpr TimeDelta kAbortTimeout = TimeDelta::FromSeconds(60);
+
+}  // anonymous namespace
+
+class PaymentRequestUpdateEvent::UpdatePaymentDetailsFunction final
+    : public ScriptFunction {
+ public:
+  enum class ResolveType {
+    kFulfilled,
+    kRejected,
+  };
+
+  static v8::Local<v8::Function> CreateFunction(
+      ScriptState* script_state,
+      ResolveType resolve_type,
+      PaymentRequestUpdateEvent* event) {
+    UpdatePaymentDetailsFunction* self =
+        MakeGarbageCollected<UpdatePaymentDetailsFunction>(script_state,
+                                                           resolve_type, event);
+    return self->BindToV8Function();
+  }
+
+  UpdatePaymentDetailsFunction(ScriptState* script_state,
+                               ResolveType resolve_type,
+                               PaymentRequestUpdateEvent* event)
+      : ScriptFunction(script_state),
+        resolve_type_(resolve_type),
+        event_(event) {
+    DCHECK(event_);
+  }
+
+  void Trace(blink::Visitor* visitor) override {
+    visitor->Trace(event_);
+    ScriptFunction::Trace(visitor);
+  }
+
+ private:
+  ScriptValue Call(ScriptValue value) override {
+    if (!event_ || !event_->request_)
+      return ScriptValue();
+
+    event_->abort_timer_.Stop();
+    if (resolve_type_ == ResolveType::kFulfilled) {
+      event_->request_->OnUpdatePaymentDetails(value);
+    } else if (resolve_type_ == ResolveType::kRejected) {
+      event_->request_->OnUpdatePaymentDetailsFailure(
+          ToCoreString(value.V8Value()
+                           ->ToString(GetScriptState()->GetContext())
+                           .ToLocalChecked()));
+    }
+    event_->SetPaymentRequest(nullptr);
+    return ScriptValue();
+  }
+
+  ResolveType resolve_type_;
+  Member<PaymentRequestUpdateEvent> event_;
+};
 
 PaymentRequestUpdateEvent::~PaymentRequestUpdateEvent() = default;
 
@@ -62,12 +122,15 @@
   stopImmediatePropagation();
   wait_for_update_ = true;
 
+  DCHECK(!abort_timer_.IsActive());
+  abort_timer_.StartOneShot(kAbortTimeout, FROM_HERE);
+
   promise.Then(UpdatePaymentDetailsFunction::CreateFunction(
-                   script_state, request_,
-                   UpdatePaymentDetailsFunction::ResolveType::kFulfill),
+                   script_state,
+                   UpdatePaymentDetailsFunction::ResolveType::kFulfilled, this),
                UpdatePaymentDetailsFunction::CreateFunction(
-                   script_state, request_,
-                   UpdatePaymentDetailsFunction::ResolveType::kReject));
+                   script_state,
+                   UpdatePaymentDetailsFunction::ResolveType::kRejected, this));
 }
 
 void PaymentRequestUpdateEvent::Trace(blink::Visitor* visitor) {
@@ -75,10 +138,27 @@
   Event::Trace(visitor);
 }
 
+void PaymentRequestUpdateEvent::OnUpdateEventTimeoutForTesting() {
+  OnUpdateEventTimeout(nullptr);
+}
+
 PaymentRequestUpdateEvent::PaymentRequestUpdateEvent(
     ExecutionContext* execution_context,
     const AtomicString& type,
     const PaymentRequestUpdateEventInit* init)
-    : Event(type, init), wait_for_update_(false) {}
+    : Event(type, init),
+      wait_for_update_(false),
+      abort_timer_(execution_context->GetTaskRunner(TaskType::kUserInteraction),
+                   this,
+                   &PaymentRequestUpdateEvent::OnUpdateEventTimeout) {}
+
+void PaymentRequestUpdateEvent::OnUpdateEventTimeout(TimerBase*) {
+  if (!request_)
+    return;
+  abort_timer_.Stop();
+  request_->OnUpdatePaymentDetailsFailure(
+      "Timed out waiting for a response to a '" + type() + "' event");
+  SetPaymentRequest(nullptr);
+}
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/payments/payment_request_update_event.h b/third_party/blink/renderer/modules/payments/payment_request_update_event.h
index f3e5e046..24dea88 100644
--- a/third_party/blink/renderer/modules/payments/payment_request_update_event.h
+++ b/third_party/blink/renderer/modules/payments/payment_request_update_event.h
@@ -46,11 +46,20 @@
 
   void Trace(blink::Visitor*) override;
 
+  void OnUpdateEventTimeoutForTesting();
+
  private:
+  // This class is declared here because it requires privileges to access some
+  // PaymentRequestUpdateEvent's member fields, such as request_, abort_timer_.
+  class UpdatePaymentDetailsFunction;
+
+  void OnUpdateEventTimeout(TimerBase*);
+
   // True after event.updateWith() was called.
   bool wait_for_update_;
 
   Member<PaymentRequestDelegate> request_;
+  TaskRunnerTimer<PaymentRequestUpdateEvent> abort_timer_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/payments/payment_request_update_event_test.cc b/third_party/blink/renderer/modules/payments/payment_request_update_event_test.cc
index ca4d769..ddd7fab1 100644
--- a/third_party/blink/renderer/modules/payments/payment_request_update_event_test.cc
+++ b/third_party/blink/renderer/modules/payments/payment_request_update_event_test.cc
@@ -151,14 +151,12 @@
   request->show(scope.GetScriptState())
       .Then(funcs.ExpectNoCall(), funcs.ExpectCall(&error_message));
 
-  static_cast<payments::mojom::blink::PaymentRequestClient*>(request)
-      ->OnShippingAddressChange(BuildPaymentAddressForTest());
-  request->OnUpdatePaymentDetailsTimeoutForTesting();
+  event->OnUpdateEventTimeoutForTesting();
 
   v8::MicrotasksScope::PerformCheckpoint(scope.GetScriptState()->GetIsolate());
   EXPECT_EQ(
-      "AbortError: Timed out waiting for a "
-      "PaymentRequestUpdateEvent.updateWith(promise) to resolve.",
+      "AbortError: Timed out waiting for a response to a "
+      "'shippingaddresschange' event",
       error_message);
 
   event->updateWith(
@@ -167,9 +165,7 @@
           ->Promise(),
       scope.GetExceptionState());
 
-  EXPECT_TRUE(scope.GetExceptionState().HadException());
-  EXPECT_EQ("PaymentRequest is no longer interactive",
-            scope.GetExceptionState().Message());
+  EXPECT_FALSE(scope.GetExceptionState().HadException());
 }
 
 TEST(PaymentRequestUpdateEventTest, OptionChangeUpdateWithTimeout) {
@@ -189,14 +185,12 @@
   request->show(scope.GetScriptState())
       .Then(funcs.ExpectNoCall(), funcs.ExpectCall(&error_message));
 
-  static_cast<payments::mojom::blink::PaymentRequestClient*>(request)
-      ->OnShippingAddressChange(BuildPaymentAddressForTest());
-  request->OnUpdatePaymentDetailsTimeoutForTesting();
+  event->OnUpdateEventTimeoutForTesting();
 
   v8::MicrotasksScope::PerformCheckpoint(scope.GetScriptState()->GetIsolate());
   EXPECT_EQ(
-      "AbortError: Timed out waiting for a "
-      "PaymentRequestUpdateEvent.updateWith(promise) to resolve.",
+      "AbortError: Timed out waiting for a response to a "
+      "'shippingoptionchange' event",
       error_message);
 
   event->updateWith(
@@ -205,9 +199,7 @@
           ->Promise(),
       scope.GetExceptionState());
 
-  EXPECT_TRUE(scope.GetExceptionState().HadException());
-  EXPECT_EQ("PaymentRequest is no longer interactive",
-            scope.GetExceptionState().Message());
+  EXPECT_FALSE(scope.GetExceptionState().HadException());
 }
 
 TEST(PaymentRequestUpdateEventTest, AddressChangePromiseTimeout) {
@@ -223,23 +215,21 @@
   event->SetTrusted(true);
   event->SetPaymentRequest(request);
   event->SetEventPhase(Event::kCapturingPhase);
+  auto* payment_details =
+      MakeGarbageCollected<ScriptPromiseResolver>(scope.GetScriptState());
   String error_message;
   request->show(scope.GetScriptState())
       .Then(funcs.ExpectNoCall(), funcs.ExpectCall(&error_message));
-  static_cast<payments::mojom::blink::PaymentRequestClient*>(request)
-      ->OnShippingAddressChange(BuildPaymentAddressForTest());
-  auto* payment_details =
-      MakeGarbageCollected<ScriptPromiseResolver>(scope.GetScriptState());
   event->updateWith(scope.GetScriptState(), payment_details->Promise(),
                     scope.GetExceptionState());
   EXPECT_FALSE(scope.GetExceptionState().HadException());
 
-  request->OnUpdatePaymentDetailsTimeoutForTesting();
+  event->OnUpdateEventTimeoutForTesting();
 
   v8::MicrotasksScope::PerformCheckpoint(scope.GetScriptState()->GetIsolate());
   EXPECT_EQ(
-      "AbortError: Timed out waiting for a "
-      "PaymentRequestUpdateEvent.updateWith(promise) to resolve.",
+      "AbortError: Timed out waiting for a response to a "
+      "'shippingaddresschange' event",
       error_message);
 
   payment_details->Resolve("foo");
@@ -258,23 +248,21 @@
   event->SetTrusted(true);
   event->SetPaymentRequest(request);
   event->SetEventPhase(Event::kCapturingPhase);
+  auto* payment_details =
+      MakeGarbageCollected<ScriptPromiseResolver>(scope.GetScriptState());
   String error_message;
   request->show(scope.GetScriptState())
       .Then(funcs.ExpectNoCall(), funcs.ExpectCall(&error_message));
-  static_cast<payments::mojom::blink::PaymentRequestClient*>(request)
-      ->OnShippingAddressChange(BuildPaymentAddressForTest());
-  auto* payment_details =
-      MakeGarbageCollected<ScriptPromiseResolver>(scope.GetScriptState());
   event->updateWith(scope.GetScriptState(), payment_details->Promise(),
                     scope.GetExceptionState());
   EXPECT_FALSE(scope.GetExceptionState().HadException());
 
-  request->OnUpdatePaymentDetailsTimeoutForTesting();
+  event->OnUpdateEventTimeoutForTesting();
 
   v8::MicrotasksScope::PerformCheckpoint(scope.GetScriptState()->GetIsolate());
   EXPECT_EQ(
-      "AbortError: Timed out waiting for a "
-      "PaymentRequestUpdateEvent.updateWith(promise) to resolve.",
+      "AbortError: Timed out waiting for a response to a "
+      "'shippingoptionchange' event",
       error_message);
 
   payment_details->Resolve("foo");
diff --git a/third_party/blink/renderer/modules/payments/payment_test_helper.cc b/third_party/blink/renderer/modules/payments/payment_test_helper.cc
index e4126f5a..2b206afb 100644
--- a/third_party/blink/renderer/modules/payments/payment_test_helper.cc
+++ b/third_party/blink/renderer/modules/payments/payment_test_helper.cc
@@ -205,13 +205,6 @@
   return result;
 }
 
-payments::mojom::blink::PaymentAddressPtr BuildPaymentAddressForTest() {
-  payments::mojom::blink::PaymentAddressPtr result =
-      payments::mojom::blink::PaymentAddress::New();
-  result->country = "US";
-  return result;
-}
-
 void MakePaymentRequestOriginSecure(Document& document) {
   document.SetSecurityOrigin(
       SecurityOrigin::Create(KURL("https://www.example.com/")));
diff --git a/third_party/blink/renderer/modules/payments/payment_test_helper.h b/third_party/blink/renderer/modules/payments/payment_test_helper.h
index 1042389..b9bd4fad 100644
--- a/third_party/blink/renderer/modules/payments/payment_test_helper.h
+++ b/third_party/blink/renderer/modules/payments/payment_test_helper.h
@@ -85,8 +85,6 @@
 
 payments::mojom::blink::PaymentResponsePtr BuildPaymentResponseForTest();
 
-payments::mojom::blink::PaymentAddressPtr BuildPaymentAddressForTest();
-
 void MakePaymentRequestOriginSecure(Document&);
 
 class PaymentRequestMockFunctionScope {
diff --git a/third_party/blink/renderer/modules/payments/update_payment_details_function.cc b/third_party/blink/renderer/modules/payments/update_payment_details_function.cc
deleted file mode 100644
index 3cdf2fb..0000000
--- a/third_party/blink/renderer/modules/payments/update_payment_details_function.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-// 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 "third_party/blink/renderer/modules/payments/update_payment_details_function.h"
-
-#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
-#include "third_party/blink/renderer/modules/payments/payment_request_delegate.h"
-
-namespace blink {
-
-// static
-v8::Local<v8::Function> UpdatePaymentDetailsFunction::CreateFunction(
-    ScriptState* script_state,
-    PaymentRequestDelegate* delegate,
-    ResolveType resolve_type) {
-  UpdatePaymentDetailsFunction* self =
-      MakeGarbageCollected<UpdatePaymentDetailsFunction>(script_state, delegate,
-                                                         resolve_type);
-  return self->BindToV8Function();
-}
-
-UpdatePaymentDetailsFunction::UpdatePaymentDetailsFunction(
-    ScriptState* script_state,
-    PaymentRequestDelegate* delegate,
-    ResolveType resolve_type)
-    : ScriptFunction(script_state),
-      delegate_(delegate),
-      resolve_type_(resolve_type) {
-  DCHECK(delegate_);
-}
-
-void UpdatePaymentDetailsFunction::Trace(blink::Visitor* visitor) {
-  visitor->Trace(delegate_);
-  ScriptFunction::Trace(visitor);
-}
-
-ScriptValue UpdatePaymentDetailsFunction::Call(ScriptValue value) {
-  if (!delegate_)
-    return ScriptValue();
-
-  switch (resolve_type_) {
-    case ResolveType::kFulfill:
-      delegate_->OnUpdatePaymentDetails(value);
-      break;
-    case ResolveType::kReject:
-      delegate_->OnUpdatePaymentDetailsFailure(
-          ToCoreString(value.V8Value()
-                           ->ToString(GetScriptState()->GetContext())
-                           .ToLocalChecked()));
-      break;
-  }
-  delegate_ = nullptr;
-  return ScriptValue();
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/payments/update_payment_details_function.h b/third_party/blink/renderer/modules/payments/update_payment_details_function.h
deleted file mode 100644
index 11d32ba1..0000000
--- a/third_party/blink/renderer/modules/payments/update_payment_details_function.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_PAYMENTS_UPDATE_PAYMENT_DETAILS_FUNCTION_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PAYMENTS_UPDATE_PAYMENT_DETAILS_FUNCTION_H_
-
-#include "third_party/blink/renderer/bindings/core/v8/script_function.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
-
-namespace blink {
-
-class PaymentRequestDelegate;
-class ScriptState;
-class ScriptValue;
-
-class UpdatePaymentDetailsFunction : public ScriptFunction {
- public:
-  enum class ResolveType {
-    kFulfill,
-    kReject,
-  };
-
-  static v8::Local<v8::Function> CreateFunction(ScriptState*,
-                                                PaymentRequestDelegate*,
-                                                ResolveType);
-
-  UpdatePaymentDetailsFunction(ScriptState*,
-                               PaymentRequestDelegate*,
-                               ResolveType);
-  void Trace(blink::Visitor*) override;
-  ScriptValue Call(ScriptValue) override;
-
- private:
-  Member<PaymentRequestDelegate> delegate_;
-  ResolveType resolve_type_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PAYMENTS_UPDATE_PAYMENT_DETAILS_FUNCTION_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.cc b/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.cc
index 4cacbec..934facd 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.cc
@@ -197,15 +197,6 @@
     blink_channel_->OnMessage(std::move(buffer));
 }
 
-RTCDataChannel* RTCDataChannel::Create(
-    ExecutionContext* context,
-    scoped_refptr<webrtc::DataChannelInterface> channel,
-    WebRTCPeerConnectionHandler* peer_connection_handler) {
-  DCHECK(channel);
-  return MakeGarbageCollected<RTCDataChannel>(context, channel,
-                                              peer_connection_handler);
-}
-
 RTCDataChannel::RTCDataChannel(
     ExecutionContext* context,
     scoped_refptr<webrtc::DataChannelInterface> channel,
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.h b/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.h
index 0d3c4f26..fee0a31 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.h
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.h
@@ -55,11 +55,6 @@
   USING_PRE_FINALIZER(RTCDataChannel, Dispose);
 
  public:
-  static RTCDataChannel* Create(
-      ExecutionContext*,
-      scoped_refptr<webrtc::DataChannelInterface> channel,
-      WebRTCPeerConnectionHandler* peer_connection_handler);
-
   RTCDataChannel(ExecutionContext*,
                  scoped_refptr<webrtc::DataChannelInterface> channel,
                  WebRTCPeerConnectionHandler* peer_connection_handler);
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_data_channel_test.cc b/third_party/blink/renderer/modules/peerconnection/rtc_data_channel_test.cc
index 564ea77..86e80b0 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_data_channel_test.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_data_channel_test.cc
@@ -219,9 +219,9 @@
 
   std::unique_ptr<MockPeerConnectionHandler> pc(
       new MockPeerConnectionHandler(signaling_thread()));
-  RTCDataChannel* channel =
-      RTCDataChannel::Create(MakeGarbageCollected<NullExecutionContext>(),
-                             webrtc_channel.get(), pc.get());
+  auto* channel = MakeGarbageCollected<RTCDataChannel>(
+      MakeGarbageCollected<NullExecutionContext>(), webrtc_channel.get(),
+      pc.get());
 
   // In RTCDataChannel::Create, the state change update is posted from the
   // signaling thread to the main thread. Wait for posted the task to be
@@ -237,9 +237,9 @@
       new rtc::RefCountedObject<MockDataChannel>(signaling_thread()));
   std::unique_ptr<MockPeerConnectionHandler> pc(
       new MockPeerConnectionHandler(signaling_thread()));
-  RTCDataChannel* channel =
-      RTCDataChannel::Create(MakeGarbageCollected<NullExecutionContext>(),
-                             webrtc_channel.get(), pc.get());
+  auto* channel = MakeGarbageCollected<RTCDataChannel>(
+      MakeGarbageCollected<NullExecutionContext>(), webrtc_channel.get(),
+      pc.get());
   webrtc_channel->ChangeState(webrtc::DataChannelInterface::kOpen);
 
   String message(std::string(100, 'A').c_str());
@@ -252,9 +252,9 @@
       new rtc::RefCountedObject<MockDataChannel>(signaling_thread()));
   std::unique_ptr<MockPeerConnectionHandler> pc(
       new MockPeerConnectionHandler(signaling_thread()));
-  RTCDataChannel* channel =
-      RTCDataChannel::Create(MakeGarbageCollected<NullExecutionContext>(),
-                             webrtc_channel.get(), pc.get());
+  auto* channel = MakeGarbageCollected<RTCDataChannel>(
+      MakeGarbageCollected<NullExecutionContext>(), webrtc_channel.get(),
+      pc.get());
   webrtc_channel->ChangeState(webrtc::DataChannelInterface::kOpen);
 
   channel->setBufferedAmountLowThreshold(1);
@@ -272,9 +272,9 @@
       new rtc::RefCountedObject<MockDataChannel>(signaling_thread()));
   std::unique_ptr<MockPeerConnectionHandler> pc(
       new MockPeerConnectionHandler(signaling_thread()));
-  RTCDataChannel* channel =
-      RTCDataChannel::Create(MakeGarbageCollected<NullExecutionContext>(),
-                             webrtc_channel.get(), pc.get());
+  auto* channel = MakeGarbageCollected<RTCDataChannel>(
+      MakeGarbageCollected<NullExecutionContext>(), webrtc_channel.get(),
+      pc.get());
   channel->OnStateChange(webrtc::DataChannelInterface::kOpen);
   ASSERT_EQ(1U, channel->scheduled_events_.size());
   EXPECT_EQ(
@@ -287,9 +287,9 @@
       new rtc::RefCountedObject<MockDataChannel>(signaling_thread()));
   std::unique_ptr<MockPeerConnectionHandler> pc(
       new MockPeerConnectionHandler(signaling_thread()));
-  RTCDataChannel* channel =
-      RTCDataChannel::Create(MakeGarbageCollected<NullExecutionContext>(),
-                             webrtc_channel.get(), pc.get());
+  auto* channel = MakeGarbageCollected<RTCDataChannel>(
+      MakeGarbageCollected<NullExecutionContext>(), webrtc_channel.get(),
+      pc.get());
   channel->OnStateChange(webrtc::DataChannelInterface::kClosed);
   ASSERT_EQ(1U, channel->scheduled_events_.size());
   EXPECT_EQ(
@@ -302,9 +302,9 @@
       new rtc::RefCountedObject<MockDataChannel>(signaling_thread()));
   std::unique_ptr<MockPeerConnectionHandler> pc(
       new MockPeerConnectionHandler(signaling_thread()));
-  RTCDataChannel* channel =
-      RTCDataChannel::Create(MakeGarbageCollected<NullExecutionContext>(),
-                             webrtc_channel.get(), pc.get());
+  auto* channel = MakeGarbageCollected<RTCDataChannel>(
+      MakeGarbageCollected<NullExecutionContext>(), webrtc_channel.get(),
+      pc.get());
 
   std::unique_ptr<webrtc::DataBuffer> message(new webrtc::DataBuffer("A"));
   channel->OnMessage(std::move(message));
@@ -319,9 +319,9 @@
       new rtc::RefCountedObject<MockDataChannel>(signaling_thread()));
   std::unique_ptr<MockPeerConnectionHandler> pc(
       new MockPeerConnectionHandler(signaling_thread()));
-  RTCDataChannel* channel =
-      RTCDataChannel::Create(MakeGarbageCollected<NullExecutionContext>(),
-                             webrtc_channel.get(), pc.get());
+  auto* channel = MakeGarbageCollected<RTCDataChannel>(
+      MakeGarbageCollected<NullExecutionContext>(), webrtc_channel.get(),
+      pc.get());
   webrtc_channel->ChangeState(webrtc::DataChannelInterface::kOpen);
 
   channel->ContextDestroyed(nullptr);
@@ -338,9 +338,9 @@
       new rtc::RefCountedObject<MockDataChannel>(signaling_thread()));
   std::unique_ptr<MockPeerConnectionHandler> pc(
       new MockPeerConnectionHandler(signaling_thread()));
-  RTCDataChannel* channel =
-      RTCDataChannel::Create(MakeGarbageCollected<NullExecutionContext>(),
-                             webrtc_channel.get(), pc.get());
+  auto* channel = MakeGarbageCollected<RTCDataChannel>(
+      MakeGarbageCollected<NullExecutionContext>(), webrtc_channel.get(),
+      pc.get());
   webrtc_channel->ChangeState(webrtc::DataChannelInterface::kOpen);
 
   channel->ContextDestroyed(nullptr);
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_dtmf_sender.cc b/third_party/blink/renderer/modules/peerconnection/rtc_dtmf_sender.cc
index cd60d6e..c70275eb 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_dtmf_sender.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_dtmf_sender.cc
@@ -137,7 +137,7 @@
   // TODO(crbug.com/891638): Add check on transceiver's "stopped"
   // and "currentDirection" attributes as per spec.
   if (tone_buffer_.IsEmpty()) {
-    Member<Event> event = RTCDTMFToneChangeEvent::Create("");
+    Member<Event> event = MakeGarbageCollected<RTCDTMFToneChangeEvent>("");
     DispatchEvent(*event.Release());
     return;
   }
@@ -151,7 +151,7 @@
     return;
   }
   playout_task_is_scheduled_ = true;
-  Member<Event> event = RTCDTMFToneChangeEvent::Create(this_tone);
+  Member<Event> event = MakeGarbageCollected<RTCDTMFToneChangeEvent>(this_tone);
   DispatchEvent(*event.Release());
 }
 
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_legacy_stats_report.cc b/third_party/blink/renderer/modules/peerconnection/rtc_legacy_stats_report.cc
index ac3110ba..5987836 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_legacy_stats_report.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_legacy_stats_report.cc
@@ -27,12 +27,6 @@
 
 namespace blink {
 
-RTCLegacyStatsReport* RTCLegacyStatsReport::Create(const String& id,
-                                                   const String& type,
-                                                   double timestamp) {
-  return MakeGarbageCollected<RTCLegacyStatsReport>(id, type, timestamp);
-}
-
 RTCLegacyStatsReport::RTCLegacyStatsReport(const String& id,
                                            const String& type,
                                            double timestamp)
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_legacy_stats_report.h b/third_party/blink/renderer/modules/peerconnection/rtc_legacy_stats_report.h
index d784ee0..ae0e80f 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_legacy_stats_report.h
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_legacy_stats_report.h
@@ -37,10 +37,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static RTCLegacyStatsReport* Create(const String& id,
-                                      const String& type,
-                                      double timestamp);
-
   RTCLegacyStatsReport(const String& id, const String& type, double timestamp);
 
   double timestamp() const { return timestamp_; }
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
index 480a24e..9345d832 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
@@ -113,6 +113,7 @@
 #include "third_party/blink/renderer/platform/bindings/microtask.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/instance_counters.h"
 #include "third_party/blink/renderer/platform/peerconnection/rtc_answer_options_platform.h"
 #include "third_party/blink/renderer/platform/peerconnection/rtc_offer_options_platform.h"
@@ -1211,7 +1212,7 @@
                                  *session_description_init);
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
   ScriptPromise promise = resolver->Promise();
-  RTCVoidRequest* request = RTCVoidRequestPromiseImpl::Create(
+  auto* request = MakeGarbageCollected<RTCVoidRequestPromiseImpl>(
       GetRTCVoidRequestOperationType(SetSdpOperationType::kSetLocalDescription,
                                      *session_description_init),
       this, resolver, "RTCPeerConnection", "setLocalDescription");
@@ -1257,7 +1258,7 @@
 
   NoteCallSetupStateEventPending(SetSdpOperationType::kSetLocalDescription,
                                  *session_description_init);
-  RTCVoidRequest* request = RTCVoidRequestImpl::Create(
+  auto* request = MakeGarbageCollected<RTCVoidRequestImpl>(
       GetExecutionContext(),
       GetRTCVoidRequestOperationType(SetSdpOperationType::kSetLocalDescription,
                                      *session_description_init),
@@ -1312,7 +1313,7 @@
                                  *session_description_init);
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
   ScriptPromise promise = resolver->Promise();
-  RTCVoidRequest* request = RTCVoidRequestPromiseImpl::Create(
+  auto* request = MakeGarbageCollected<RTCVoidRequestPromiseImpl>(
       GetRTCVoidRequestOperationType(SetSdpOperationType::kSetRemoteDescription,
                                      *session_description_init),
       this, resolver, "RTCPeerConnection", "setRemoteDescription");
@@ -1353,7 +1354,7 @@
 
   NoteCallSetupStateEventPending(SetSdpOperationType::kSetRemoteDescription,
                                  *session_description_init);
-  RTCVoidRequest* request = RTCVoidRequestImpl::Create(
+  auto* request = MakeGarbageCollected<RTCVoidRequestImpl>(
       GetExecutionContext(),
       GetRTCVoidRequestOperationType(SetSdpOperationType::kSetRemoteDescription,
                                      *session_description_init),
@@ -1679,7 +1680,7 @@
 
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
   ScriptPromise promise = resolver->Promise();
-  RTCVoidRequest* request = RTCVoidRequestPromiseImpl::Create(
+  auto* request = MakeGarbageCollected<RTCVoidRequestPromiseImpl>(
       base::nullopt, this, resolver, "RTCPeerConnection", "addIceCandidate");
   scoped_refptr<WebRTCICECandidate> web_candidate = ConvertToWebRTCIceCandidate(
       ExecutionContext::From(script_state), candidate);
@@ -1712,9 +1713,9 @@
     return ScriptPromise();
   }
 
-  RTCVoidRequest* request =
-      RTCVoidRequestImpl::Create(GetExecutionContext(), base::nullopt, this,
-                                 success_callback, error_callback);
+  auto* request = MakeGarbageCollected<RTCVoidRequestImpl>(
+      GetExecutionContext(), base::nullopt, this, success_callback,
+      error_callback);
   scoped_refptr<WebRTCICECandidate> web_candidate = ConvertToWebRTCIceCandidate(
       ExecutionContext::From(script_state), candidate);
   bool implemented =
@@ -1975,7 +1976,7 @@
 
   UseCounter::Count(context,
                     WebFeature::kRTCPeerConnectionGetStatsLegacyNonCompliant);
-  RTCStatsRequest* stats_request = RTCStatsRequestImpl::Create(
+  auto* stats_request = MakeGarbageCollected<RTCStatsRequestImpl>(
       GetExecutionContext(), this, success_callback, selector);
   // FIXME: Add passing selector as part of the statsRequest.
   peer_handler_->GetStats(stats_request);
@@ -2292,7 +2293,7 @@
                                       "RTCDataChannel creation failed");
     return nullptr;
   }
-  RTCDataChannel* channel = RTCDataChannel::Create(
+  auto* channel = MakeGarbageCollected<RTCDataChannel>(
       GetExecutionContext(), std::move(webrtc_channel), peer_handler_.get());
   has_data_channels_ = true;
 
@@ -2659,7 +2660,7 @@
         video_track_components.push_back(track->Component());
         video_tracks.push_back(track);
       }
-      MediaStreamDescriptor* descriptor = MediaStreamDescriptor::Create(
+      auto* descriptor = MakeGarbageCollected<MediaStreamDescriptor>(
           stream_id, std::move(audio_track_components),
           std::move(video_track_components));
       stream =
@@ -2865,8 +2866,10 @@
     }
     if (!curr_stream) {
       curr_stream = MediaStream::Create(
-          GetExecutionContext(), MediaStreamDescriptor::Create(
-                                     static_cast<String>(stream_id), {}, {}));
+          GetExecutionContext(),
+          MakeGarbageCollected<MediaStreamDescriptor>(
+              static_cast<String>(stream_id), MediaStreamComponentVector(),
+              MediaStreamComponentVector()));
     }
     streams.push_back(curr_stream);
   }
@@ -2896,9 +2899,9 @@
       webrtc::PeerConnectionInterface::SignalingState::kClosed)
     return;
 
-  RTCDataChannel* blink_channel = RTCDataChannel::Create(
+  auto* blink_channel = MakeGarbageCollected<RTCDataChannel>(
       GetExecutionContext(), std::move(channel), peer_handler_.get());
-  ScheduleDispatchEvent(RTCDataChannelEvent::Create(
+  ScheduleDispatchEvent(MakeGarbageCollected<RTCDataChannelEvent>(
       event_type_names::kDatachannel, blink_channel));
   has_data_channels_ = true;
 }
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc
index d198e82..61df391 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc
@@ -30,6 +30,7 @@
 #include "third_party/blink/renderer/modules/peerconnection/rtc_ice_server.h"
 #include "third_party/blink/renderer/modules/peerconnection/rtc_offer_options.h"
 #include "third_party/blink/renderer/modules/peerconnection/rtc_session_description_init.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
 #include "third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.h"
@@ -391,9 +392,9 @@
   MediaStreamTrack* CreateTrack(V8TestingScope& scope,
                                 MediaStreamSource::StreamType type,
                                 String id) {
-    MediaStreamSource* source =
-        MediaStreamSource::Create("sourceId", type, "sourceName", false);
-    MediaStreamComponent* component = MediaStreamComponent::Create(id, source);
+    auto* source = MakeGarbageCollected<MediaStreamSource>("sourceId", type,
+                                                           "sourceName", false);
+    auto* component = MakeGarbageCollected<MediaStreamComponent>(id, source);
     return MediaStreamTrack::Create(scope.GetExecutionContext(), component);
   }
 
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc b/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc
index 4e1cd1e..c124295 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc
@@ -389,7 +389,7 @@
 
 void RTCQuicTransport::OnStream(QuicStreamProxy* stream_proxy) {
   RTCQuicStream* stream = AddStream(stream_proxy);
-  DispatchEvent(*RTCQuicStreamEvent::Create(stream));
+  DispatchEvent(*MakeGarbageCollected<RTCQuicStreamEvent>(stream));
 }
 
 static RTCQuicTransportStats* CreateRTCQuicTransportStats(
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_stats_request_impl.cc b/third_party/blink/renderer/modules/peerconnection/rtc_stats_request_impl.cc
index 3bcc1ef5..d3d6601 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_stats_request_impl.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_stats_request_impl.cc
@@ -29,14 +29,6 @@
 
 namespace blink {
 
-RTCStatsRequestImpl* RTCStatsRequestImpl::Create(ExecutionContext* context,
-                                                 RTCPeerConnection* requester,
-                                                 V8RTCStatsCallback* callback,
-                                                 MediaStreamTrack* selector) {
-  return MakeGarbageCollected<RTCStatsRequestImpl>(context, requester, callback,
-                                                   selector);
-}
-
 RTCStatsRequestImpl::RTCStatsRequestImpl(ExecutionContext* context,
                                          RTCPeerConnection* requester,
                                          V8RTCStatsCallback* callback,
@@ -51,7 +43,7 @@
 RTCStatsRequestImpl::~RTCStatsRequestImpl() = default;
 
 RTCStatsResponseBase* RTCStatsRequestImpl::CreateResponse() {
-  return RTCStatsResponse::Create();
+  return MakeGarbageCollected<RTCStatsResponse>();
 }
 
 bool RTCStatsRequestImpl::HasSelector() {
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_stats_request_impl.h b/third_party/blink/renderer/modules/peerconnection/rtc_stats_request_impl.h
index 0187671f..3f3b7304 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_stats_request_impl.h
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_stats_request_impl.h
@@ -43,11 +43,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(RTCStatsRequestImpl);
 
  public:
-  static RTCStatsRequestImpl* Create(ExecutionContext*,
-                                     RTCPeerConnection*,
-                                     V8RTCStatsCallback*,
-                                     MediaStreamTrack*);
-
   RTCStatsRequestImpl(ExecutionContext*,
                       RTCPeerConnection*,
                       V8RTCStatsCallback*,
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_stats_response.cc b/third_party/blink/renderer/modules/peerconnection/rtc_stats_response.cc
index f7f3f4e..bc02571f8 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_stats_response.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_stats_response.cc
@@ -26,10 +26,6 @@
 
 namespace blink {
 
-RTCStatsResponse* RTCStatsResponse::Create() {
-  return MakeGarbageCollected<RTCStatsResponse>();
-}
-
 RTCStatsResponse::RTCStatsResponse() = default;
 
 RTCLegacyStatsReport* RTCStatsResponse::namedItem(const AtomicString& name) {
@@ -39,8 +35,8 @@
 }
 
 void RTCStatsResponse::AddStats(const WebRTCLegacyStats& stats) {
-  result_.push_back(RTCLegacyStatsReport::Create(stats.Id(), stats.GetType(),
-                                                 stats.Timestamp()));
+  result_.push_back(MakeGarbageCollected<RTCLegacyStatsReport>(
+      stats.Id(), stats.GetType(), stats.Timestamp()));
   idmap_.insert(stats.Id(), result_.size() - 1);
   RTCLegacyStatsReport* report = result_[result_.size() - 1].Get();
 
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_stats_response.h b/third_party/blink/renderer/modules/peerconnection/rtc_stats_response.h
index b3b6d94..72d6b406 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_stats_response.h
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_stats_response.h
@@ -39,8 +39,6 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static RTCStatsResponse* Create();
-
   RTCStatsResponse();
 
   const HeapVector<Member<RTCLegacyStatsReport>>& result() const {
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_void_request_impl.cc b/third_party/blink/renderer/modules/peerconnection/rtc_void_request_impl.cc
index 11c6c25..6607e58d 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_void_request_impl.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_void_request_impl.cc
@@ -36,17 +36,6 @@
 
 namespace blink {
 
-RTCVoidRequestImpl* RTCVoidRequestImpl::Create(
-    ExecutionContext* context,
-    base::Optional<RTCSetSessionDescriptionOperation> operation,
-    RTCPeerConnection* requester,
-    V8VoidFunction* success_callback,
-    V8RTCPeerConnectionErrorCallback* error_callback) {
-  return MakeGarbageCollected<RTCVoidRequestImpl>(context, std::move(operation),
-                                                  requester, success_callback,
-                                                  error_callback);
-}
-
 RTCVoidRequestImpl::RTCVoidRequestImpl(
     ExecutionContext* context,
     base::Optional<RTCSetSessionDescriptionOperation> operation,
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_void_request_impl.h b/third_party/blink/renderer/modules/peerconnection/rtc_void_request_impl.h
index b775d0ec..18ac9c64 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_void_request_impl.h
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_void_request_impl.h
@@ -51,13 +51,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(RTCVoidRequestImpl);
 
  public:
-  static RTCVoidRequestImpl* Create(
-      ExecutionContext*,
-      base::Optional<RTCSetSessionDescriptionOperation>,
-      RTCPeerConnection*,
-      V8VoidFunction*,
-      V8RTCPeerConnectionErrorCallback*);
-
   RTCVoidRequestImpl(ExecutionContext*,
                      base::Optional<RTCSetSessionDescriptionOperation>,
                      RTCPeerConnection*,
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_void_request_promise_impl.cc b/third_party/blink/renderer/modules/peerconnection/rtc_void_request_promise_impl.cc
index 4e8dd213..dd3b6b8 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_void_request_promise_impl.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_void_request_promise_impl.cc
@@ -11,16 +11,6 @@
 
 namespace blink {
 
-RTCVoidRequestPromiseImpl* RTCVoidRequestPromiseImpl::Create(
-    base::Optional<RTCSetSessionDescriptionOperation> operation,
-    RTCPeerConnection* requester,
-    ScriptPromiseResolver* resolver,
-    const char* interface_name,
-    const char* property_name) {
-  return MakeGarbageCollected<RTCVoidRequestPromiseImpl>(
-      std::move(operation), requester, resolver, interface_name, property_name);
-}
-
 RTCVoidRequestPromiseImpl::RTCVoidRequestPromiseImpl(
     base::Optional<RTCSetSessionDescriptionOperation> operation,
     RTCPeerConnection* requester,
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_void_request_promise_impl.h b/third_party/blink/renderer/modules/peerconnection/rtc_void_request_promise_impl.h
index 2757d437..5c85a85f 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_void_request_promise_impl.h
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_void_request_promise_impl.h
@@ -20,13 +20,6 @@
 // shared code as to not repeat the majority of the implementations.
 class RTCVoidRequestPromiseImpl final : public RTCVoidRequest {
  public:
-  static RTCVoidRequestPromiseImpl* Create(
-      base::Optional<RTCSetSessionDescriptionOperation>,
-      RTCPeerConnection*,
-      ScriptPromiseResolver*,
-      const char* interface_name,
-      const char* property_name);
-
   RTCVoidRequestPromiseImpl(base::Optional<RTCSetSessionDescriptionOperation>,
                             RTCPeerConnection*,
                             ScriptPromiseResolver*,
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_void_request_script_promise_resolver_impl.cc b/third_party/blink/renderer/modules/peerconnection/rtc_void_request_script_promise_resolver_impl.cc
index 43db1d2f..946fb97c 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_void_request_script_promise_resolver_impl.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_void_request_script_promise_resolver_impl.cc
@@ -10,14 +10,6 @@
 
 namespace blink {
 
-RTCVoidRequestScriptPromiseResolverImpl*
-RTCVoidRequestScriptPromiseResolverImpl::Create(ScriptPromiseResolver* resolver,
-                                                const char* interface_name,
-                                                const char* property_name) {
-  return MakeGarbageCollected<RTCVoidRequestScriptPromiseResolverImpl>(
-      resolver, interface_name, property_name);
-}
-
 RTCVoidRequestScriptPromiseResolverImpl::
     RTCVoidRequestScriptPromiseResolverImpl(ScriptPromiseResolver* resolver,
                                             const char* interface_name,
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_void_request_script_promise_resolver_impl.h b/third_party/blink/renderer/modules/peerconnection/rtc_void_request_script_promise_resolver_impl.h
index 20d9d22..eca84459 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_void_request_script_promise_resolver_impl.h
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_void_request_script_promise_resolver_impl.h
@@ -14,11 +14,6 @@
 
 class RTCVoidRequestScriptPromiseResolverImpl : public RTCVoidRequest {
  public:
-  static RTCVoidRequestScriptPromiseResolverImpl* Create(
-      ScriptPromiseResolver*,
-      const char* interface_name,
-      const char* property_name);
-
   RTCVoidRequestScriptPromiseResolverImpl(ScriptPromiseResolver*,
                                           const char* interface_name,
                                           const char* property_name);
diff --git a/third_party/blink/renderer/modules/quota/deprecated_storage_info.cc b/third_party/blink/renderer/modules/quota/deprecated_storage_info.cc
index 4be8a8c..c1ae9128 100644
--- a/third_party/blink/renderer/modules/quota/deprecated_storage_info.cc
+++ b/third_party/blink/renderer/modules/quota/deprecated_storage_info.cc
@@ -81,14 +81,16 @@
     int storage_type) {
   switch (storage_type) {
     case kTemporary:
-      if (!temporary_storage_)
-        temporary_storage_ =
-            DeprecatedStorageQuota::Create(DeprecatedStorageQuota::kTemporary);
+      if (!temporary_storage_) {
+        temporary_storage_ = MakeGarbageCollected<DeprecatedStorageQuota>(
+            DeprecatedStorageQuota::kTemporary);
+      }
       return temporary_storage_.Get();
     case kPersistent:
-      if (!persistent_storage_)
-        persistent_storage_ =
-            DeprecatedStorageQuota::Create(DeprecatedStorageQuota::kPersistent);
+      if (!persistent_storage_) {
+        persistent_storage_ = MakeGarbageCollected<DeprecatedStorageQuota>(
+            DeprecatedStorageQuota::kPersistent);
+      }
       return persistent_storage_.Get();
   }
   return nullptr;
diff --git a/third_party/blink/renderer/modules/quota/deprecated_storage_info.h b/third_party/blink/renderer/modules/quota/deprecated_storage_info.h
index 17352c5..2d75ef57 100644
--- a/third_party/blink/renderer/modules/quota/deprecated_storage_info.h
+++ b/third_party/blink/renderer/modules/quota/deprecated_storage_info.h
@@ -52,10 +52,6 @@
     kPersistent,
   };
 
-  static DeprecatedStorageInfo* Create() {
-    return MakeGarbageCollected<DeprecatedStorageInfo>();
-  }
-
   DeprecatedStorageInfo();
 
   void queryUsageAndQuota(ScriptState*,
diff --git a/third_party/blink/renderer/modules/quota/deprecated_storage_quota.h b/third_party/blink/renderer/modules/quota/deprecated_storage_quota.h
index 56dff84..4f0661b 100644
--- a/third_party/blink/renderer/modules/quota/deprecated_storage_quota.h
+++ b/third_party/blink/renderer/modules/quota/deprecated_storage_quota.h
@@ -53,10 +53,6 @@
     kPersistent,
   };
 
-  static DeprecatedStorageQuota* Create(Type type) {
-    return MakeGarbageCollected<DeprecatedStorageQuota>(type);
-  }
-
   static void EnqueueStorageErrorCallback(ScriptState*,
                                           V8StorageErrorCallback*,
                                           DOMExceptionCode);
diff --git a/third_party/blink/renderer/modules/quota/dom_window_quota.cc b/third_party/blink/renderer/modules/quota/dom_window_quota.cc
index c8730c81..50319ee2 100644
--- a/third_party/blink/renderer/modules/quota/dom_window_quota.cc
+++ b/third_party/blink/renderer/modules/quota/dom_window_quota.cc
@@ -61,7 +61,7 @@
 
 DeprecatedStorageInfo* DOMWindowQuota::webkitStorageInfo() const {
   if (!storage_info_)
-    storage_info_ = DeprecatedStorageInfo::Create();
+    storage_info_ = MakeGarbageCollected<DeprecatedStorageInfo>();
   return storage_info_.Get();
 }
 
diff --git a/third_party/blink/renderer/modules/quota/navigator_storage_quota.cc b/third_party/blink/renderer/modules/quota/navigator_storage_quota.cc
index 0c9e97b3..b3443454 100644
--- a/third_party/blink/renderer/modules/quota/navigator_storage_quota.cc
+++ b/third_party/blink/renderer/modules/quota/navigator_storage_quota.cc
@@ -67,16 +67,18 @@
 }
 
 DeprecatedStorageQuota* NavigatorStorageQuota::webkitTemporaryStorage() const {
-  if (!temporary_storage_)
-    temporary_storage_ =
-        DeprecatedStorageQuota::Create(DeprecatedStorageQuota::kTemporary);
+  if (!temporary_storage_) {
+    temporary_storage_ = MakeGarbageCollected<DeprecatedStorageQuota>(
+        DeprecatedStorageQuota::kTemporary);
+  }
   return temporary_storage_.Get();
 }
 
 DeprecatedStorageQuota* NavigatorStorageQuota::webkitPersistentStorage() const {
-  if (!persistent_storage_)
-    persistent_storage_ =
-        DeprecatedStorageQuota::Create(DeprecatedStorageQuota::kPersistent);
+  if (!persistent_storage_) {
+    persistent_storage_ = MakeGarbageCollected<DeprecatedStorageQuota>(
+        DeprecatedStorageQuota::kPersistent);
+  }
   return persistent_storage_.Get();
 }
 
diff --git a/third_party/blink/renderer/modules/serial/navigator_serial.cc b/third_party/blink/renderer/modules/serial/navigator_serial.cc
index aaaa503d..4ad2760 100644
--- a/third_party/blink/renderer/modules/serial/navigator_serial.cc
+++ b/third_party/blink/renderer/modules/serial/navigator_serial.cc
@@ -35,7 +35,8 @@
     : Supplement<Navigator>(navigator) {
   if (navigator.GetFrame()) {
     DCHECK(navigator.GetFrame()->GetDocument());
-    serial_ = Serial::Create(*navigator.GetFrame()->GetDocument());
+    serial_ =
+        MakeGarbageCollected<Serial>(*navigator.GetFrame()->GetDocument());
   }
 }
 
diff --git a/third_party/blink/renderer/modules/serial/serial.cc b/third_party/blink/renderer/modules/serial/serial.cc
index 25f99f1..abeb880 100644
--- a/third_party/blink/renderer/modules/serial/serial.cc
+++ b/third_party/blink/renderer/modules/serial/serial.cc
@@ -34,11 +34,6 @@
 
 }  // namespace
 
-// static
-Serial* Serial::Create(ExecutionContext& execution_context) {
-  return MakeGarbageCollected<Serial>(execution_context);
-}
-
 Serial::Serial(ExecutionContext& execution_context)
     : ContextLifecycleObserver(&execution_context) {}
 
diff --git a/third_party/blink/renderer/modules/serial/serial.h b/third_party/blink/renderer/modules/serial/serial.h
index 195ec073..c44191a 100644
--- a/third_party/blink/renderer/modules/serial/serial.h
+++ b/third_party/blink/renderer/modules/serial/serial.h
@@ -28,8 +28,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(Serial);
 
  public:
-  static Serial* Create(ExecutionContext& executionContext);
-
   explicit Serial(ExecutionContext&);
 
   // EventTarget
diff --git a/third_party/blink/renderer/modules/serial/worker_navigator_serial.cc b/third_party/blink/renderer/modules/serial/worker_navigator_serial.cc
index 25e60bb7..8c1951ab 100644
--- a/third_party/blink/renderer/modules/serial/worker_navigator_serial.cc
+++ b/third_party/blink/renderer/modules/serial/worker_navigator_serial.cc
@@ -33,7 +33,7 @@
     // TODO(https://crbug.com/839117): Remove this check once the Exposed
     // attribute is fixed to only expose this property in dedicated workers.
     if (execution_context->IsDedicatedWorkerGlobalScope())
-      serial_ = Serial::Create(*execution_context);
+      serial_ = MakeGarbageCollected<Serial>(*execution_context);
   }
   return serial_;
 }
diff --git a/third_party/blink/renderer/modules/webaudio/media_stream_audio_destination_node.cc b/third_party/blink/renderer/modules/webaudio/media_stream_audio_destination_node.cc
index b4660f2..8276797 100644
--- a/third_party/blink/renderer/modules/webaudio/media_stream_audio_destination_node.cc
+++ b/third_party/blink/renderer/modules/webaudio/media_stream_audio_destination_node.cc
@@ -32,6 +32,7 @@
 #include "third_party/blink/renderer/modules/webaudio/base_audio_context.h"
 #include "third_party/blink/renderer/platform/bindings/exception_messages.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/mediastream/media_stream_center.h"
 #include "third_party/blink/renderer/platform/uuid.h"
 #include "third_party/blink/renderer/platform/wtf/locker.h"
@@ -132,15 +133,15 @@
     AudioContext& context,
     uint32_t number_of_channels)
     : AudioBasicInspectorNode(context),
-      source_(
-          MediaStreamSource::Create("WebAudio-" + CreateCanonicalUUIDString(),
-                                    MediaStreamSource::kTypeAudio,
-                                    "MediaStreamAudioDestinationNode",
-                                    false,
-                                    MediaStreamSource::kReadyStateLive,
-                                    true)),
+      source_(MakeGarbageCollected<MediaStreamSource>(
+          "WebAudio-" + CreateCanonicalUUIDString(),
+          MediaStreamSource::kTypeAudio,
+          "MediaStreamAudioDestinationNode",
+          false,
+          MediaStreamSource::kReadyStateLive,
+          true)),
       stream_(MediaStream::Create(context.GetExecutionContext(),
-                                  MediaStreamDescriptor::Create(
+                                  MakeGarbageCollected<MediaStreamDescriptor>(
                                       MediaStreamSourceVector({source_.Get()}),
                                       MediaStreamSourceVector()))) {
   MediaStreamCenter::Instance().DidCreateMediaStreamAndTracks(
diff --git a/third_party/blink/renderer/platform/exported/DEPS b/third_party/blink/renderer/platform/exported/DEPS
index c2bd6b1..457e9ece 100644
--- a/third_party/blink/renderer/platform/exported/DEPS
+++ b/third_party/blink/renderer/platform/exported/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+    "+net/base/load_flags.h",
     "+net/cookies/canonical_cookie.h",
     "+net/cookies/cookie_constants.h",
 ]
diff --git a/third_party/blink/renderer/platform/exported/web_media_stream.cc b/third_party/blink/renderer/platform/exported/web_media_stream.cc
index 839af49e..cd532c63 100644
--- a/third_party/blink/renderer/platform/exported/web_media_stream.cc
+++ b/third_party/blink/renderer/platform/exported/web_media_stream.cc
@@ -28,6 +28,7 @@
 #include "third_party/blink/public/platform/web_media_stream_source.h"
 #include "third_party/blink/public/platform/web_media_stream_track.h"
 #include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/mediastream/media_stream_component.h"
 #include "third_party/blink/renderer/platform/mediastream/media_stream_descriptor.h"
 #include "third_party/blink/renderer/platform/mediastream/media_stream_source.h"
@@ -143,7 +144,7 @@
     MediaStreamComponent* component = video_tracks[i];
     video.push_back(component);
   }
-  private_ = MediaStreamDescriptor::Create(label, audio, video);
+  private_ = MakeGarbageCollected<MediaStreamDescriptor>(label, audio, video);
 }
 
 void WebMediaStream::Assign(const WebMediaStream& other) {
diff --git a/third_party/blink/renderer/platform/exported/web_media_stream_source.cc b/third_party/blink/renderer/platform/exported/web_media_stream_source.cc
index 396ba52..75a6efcc 100644
--- a/third_party/blink/renderer/platform/exported/web_media_stream_source.cc
+++ b/third_party/blink/renderer/platform/exported/web_media_stream_source.cc
@@ -38,6 +38,7 @@
 #include "third_party/blink/public/platform/web_media_constraints.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/renderer/platform/audio/audio_bus.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/mediastream/media_stream_source.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
@@ -69,7 +70,7 @@
                                       Type type,
                                       const WebString& name,
                                       bool remote) {
-  private_ = MediaStreamSource::Create(
+  private_ = MakeGarbageCollected<MediaStreamSource>(
       id, static_cast<MediaStreamSource::StreamType>(type), name, remote);
 }
 
diff --git a/third_party/blink/renderer/platform/exported/web_media_stream_track.cc b/third_party/blink/renderer/platform/exported/web_media_stream_track.cc
index 1718e0c..4e51ff1 100644
--- a/third_party/blink/renderer/platform/exported/web_media_stream_track.cc
+++ b/third_party/blink/renderer/platform/exported/web_media_stream_track.cc
@@ -33,6 +33,7 @@
 #include "third_party/blink/public/platform/web_media_stream.h"
 #include "third_party/blink/public/platform/web_media_stream_source.h"
 #include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/mediastream/media_stream_component.h"
 #include "third_party/blink/renderer/platform/mediastream/media_stream_source.h"
 
@@ -52,12 +53,12 @@
 }
 
 void WebMediaStreamTrack::Initialize(const WebMediaStreamSource& source) {
-  private_ = MediaStreamComponent::Create(source);
+  private_ = MakeGarbageCollected<MediaStreamComponent>(source);
 }
 
 void WebMediaStreamTrack::Initialize(const WebString& id,
                                      const WebMediaStreamSource& source) {
-  private_ = MediaStreamComponent::Create(id, source);
+  private_ = MakeGarbageCollected<MediaStreamComponent>(id, source);
 }
 
 void WebMediaStreamTrack::Reset() {
diff --git a/third_party/blink/renderer/platform/exported/web_url_request.cc b/third_party/blink/renderer/platform/exported/web_url_request.cc
index 45a83e3..53bbb5918 100644
--- a/third_party/blink/renderer/platform/exported/web_url_request.cc
+++ b/third_party/blink/renderer/platform/exported/web_url_request.cc
@@ -33,6 +33,8 @@
 #include <memory>
 
 #include "base/time/time.h"
+#include "net/base/load_flags.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
 #include "third_party/blink/public/platform/web_http_body.h"
 #include "third_party/blink/public/platform/web_http_header_visitor.h"
 #include "third_party/blink/public/platform/web_security_origin.h"
@@ -42,6 +44,8 @@
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 
+using blink::mojom::FetchCacheMode;
+
 namespace blink {
 
 // The purpose of this struct is to permit allocating a ResourceRequest on the
@@ -432,6 +436,55 @@
   resource_request_->SetFetchWindowId(id);
 }
 
+int WebURLRequest::GetLoadFlagsForWebURLRequest() const {
+  int load_flags = net::LOAD_NORMAL;
+
+  switch (resource_request_->GetCacheMode()) {
+    case FetchCacheMode::kNoStore:
+      load_flags |= net::LOAD_DISABLE_CACHE;
+      break;
+    case FetchCacheMode::kValidateCache:
+      load_flags |= net::LOAD_VALIDATE_CACHE;
+      break;
+    case FetchCacheMode::kBypassCache:
+      load_flags |= net::LOAD_BYPASS_CACHE;
+      break;
+    case FetchCacheMode::kForceCache:
+      load_flags |= net::LOAD_SKIP_CACHE_VALIDATION;
+      break;
+    case FetchCacheMode::kOnlyIfCached:
+      load_flags |= net::LOAD_ONLY_FROM_CACHE | net::LOAD_SKIP_CACHE_VALIDATION;
+      break;
+    case FetchCacheMode::kUnspecifiedOnlyIfCachedStrict:
+      load_flags |= net::LOAD_ONLY_FROM_CACHE;
+      break;
+    case FetchCacheMode::kDefault:
+      break;
+    case FetchCacheMode::kUnspecifiedForceCacheMiss:
+      load_flags |= net::LOAD_ONLY_FROM_CACHE | net::LOAD_BYPASS_CACHE;
+      break;
+  }
+
+  if (!resource_request_->AllowStoredCredentials()) {
+    load_flags |= net::LOAD_DO_NOT_SAVE_COOKIES;
+    load_flags |= net::LOAD_DO_NOT_SEND_COOKIES;
+    load_flags |= net::LOAD_DO_NOT_SEND_AUTH_DATA;
+  }
+
+  if (resource_request_->GetRequestContext() ==
+      blink::mojom::RequestContextType::PREFETCH)
+    load_flags |= net::LOAD_PREFETCH;
+
+  if (resource_request_->GetExtraData()) {
+    if (resource_request_->GetExtraData()->is_for_no_state_prefetch())
+      load_flags |= net::LOAD_PREFETCH;
+  }
+  if (resource_request_->AllowsStaleResponse())
+    load_flags |= net::LOAD_SUPPORT_ASYNC_REVALIDATION;
+
+  return load_flags;
+}
+
 const ResourceRequest& WebURLRequest::ToResourceRequest() const {
   DCHECK(resource_request_);
   return *resource_request_;
diff --git a/third_party/blink/renderer/platform/loader/fetch/memory_cache.cc b/third_party/blink/renderer/platform/loader/fetch/memory_cache.cc
index e547cf7..eb34884 100644
--- a/third_party/blink/renderer/platform/loader/fetch/memory_cache.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/memory_cache.cc
@@ -22,9 +22,12 @@
 
 #include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h"
 
+#include <utility>
+
 #include "base/auto_reset.h"
 #include "base/bind.h"
 #include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_loading_log.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
@@ -48,8 +51,9 @@
 MemoryCache* GetMemoryCache() {
   DCHECK(WTF::IsMainThread());
   if (!g_memory_cache) {
-    g_memory_cache = new Persistent<MemoryCache>(
-        MemoryCache::Create(Thread::MainThread()->GetTaskRunner()));
+    g_memory_cache =
+        new Persistent<MemoryCache>(MakeGarbageCollected<MemoryCache>(
+            Thread::MainThread()->GetTaskRunner()));
   }
   return g_memory_cache->Get();
 }
@@ -75,7 +79,7 @@
   resource_.Clear();
 }
 
-inline MemoryCache::MemoryCache(
+MemoryCache::MemoryCache(
     scoped_refptr<base::SingleThreadTaskRunner> task_runner)
     : in_prune_resources_(false),
       prune_pending_(false),
@@ -92,11 +96,6 @@
     MemoryPressureListenerRegistry::Instance().RegisterClient(this);
 }
 
-MemoryCache* MemoryCache::Create(
-    scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
-  return MakeGarbageCollected<MemoryCache>(std::move(task_runner));
-}
-
 MemoryCache::~MemoryCache() = default;
 
 void MemoryCache::Trace(blink::Visitor* visitor) {
@@ -135,7 +134,7 @@
 void MemoryCache::Add(Resource* resource) {
   DCHECK(resource);
   ResourceMap* resources = EnsureResourceMap(resource->CacheIdentifier());
-  AddInternal(resources, MemoryCacheEntry::Create(resource));
+  AddInternal(resources, MakeGarbageCollected<MemoryCacheEntry>(resource));
   RESOURCE_LOADING_DVLOG(1)
       << "MemoryCache::add Added " << resource->Url().GetString()
       << ", resource " << resource;
diff --git a/third_party/blink/renderer/platform/loader/fetch/memory_cache.h b/third_party/blink/renderer/platform/loader/fetch/memory_cache.h
index 13d42d3..2a0f089 100644
--- a/third_party/blink/renderer/platform/loader/fetch/memory_cache.h
+++ b/third_party/blink/renderer/platform/loader/fetch/memory_cache.h
@@ -49,10 +49,6 @@
 // when the prefinalizer is executed.
 class MemoryCacheEntry final : public GarbageCollected<MemoryCacheEntry> {
  public:
-  static MemoryCacheEntry* Create(Resource* resource) {
-    return MakeGarbageCollected<MemoryCacheEntry>(resource);
-  }
-
   explicit MemoryCacheEntry(Resource* resource) : resource_(resource) {}
 
   void Trace(blink::Visitor*);
@@ -73,11 +69,9 @@
   USING_GARBAGE_COLLECTED_MIXIN(MemoryCache);
 
  public:
-  static MemoryCache* Create(
-      scoped_refptr<base::SingleThreadTaskRunner> task_runner);
-
   explicit MemoryCache(scoped_refptr<base::SingleThreadTaskRunner> task_runner);
   ~MemoryCache() override;
+
   void Trace(blink::Visitor*) override;
 
   struct TypeStatistic {
diff --git a/third_party/blink/renderer/platform/loader/fetch/memory_cache_correctness_test.cc b/third_party/blink/renderer/platform/loader/fetch/memory_cache_correctness_test.cc
index e44330c..c986aa2 100644
--- a/third_party/blink/renderer/platform/loader/fetch/memory_cache_correctness_test.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/memory_cache_correctness_test.cc
@@ -31,6 +31,7 @@
 #include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/loader/fetch/fetch_context.h"
 #include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h"
 #include "third_party/blink/renderer/platform/loader/fetch/raw_resource.h"
@@ -63,7 +64,7 @@
       response.SetCurrentRequestUrl(KURL(kResourceURL));
     ResourceRequest request(response.CurrentRequestUrl());
     request.SetRequestorOrigin(GetSecurityOrigin());
-    MockResource* resource = MockResource::Create(request);
+    auto* resource = MakeGarbageCollected<MockResource>(request);
     resource->SetResponse(response);
     resource->FinishForTest();
     AddResourceToMemoryCache(resource);
@@ -73,7 +74,7 @@
   MockResource* ResourceFromResourceRequest(ResourceRequest request) {
     if (request.Url().IsNull())
       request.SetURL(KURL(kResourceURL));
-    MockResource* resource = MockResource::Create(request);
+    auto* resource = MakeGarbageCollected<MockResource>(request);
     ResourceResponse response(KURL{kResourceURL});
     response.SetMimeType("text/html");
     resource->SetResponse(response);
@@ -111,7 +112,7 @@
   void SetUp() override {
     // Save the global memory cache to restore it upon teardown.
     global_memory_cache_ = ReplaceMemoryCacheForTesting(
-        MemoryCache::Create(platform_->test_task_runner()));
+        MakeGarbageCollected<MemoryCache>(platform_->test_task_runner()));
 
     security_origin_ = SecurityOrigin::CreateUniqueOpaque();
     MockFetchContext* context = MakeGarbageCollected<MockFetchContext>();
@@ -376,7 +377,7 @@
 
   ResourceRequest request(redirect_url);
   request.SetRequestorOrigin(GetSecurityOrigin());
-  MockResource* first_resource = MockResource::Create(request);
+  auto* first_resource = MakeGarbageCollected<MockResource>(request);
 
   ResourceResponse fresh301_response(redirect_url);
   fresh301_response.SetHttpStatusCode(301);
@@ -417,7 +418,7 @@
 
   ResourceRequest request(redirect_url);
   request.SetRequestorOrigin(GetSecurityOrigin());
-  MockResource* first_resource = MockResource::Create(request);
+  auto* first_resource = MakeGarbageCollected<MockResource>(request);
 
   ResourceResponse stale301_response(redirect_url);
   stale301_response.SetHttpStatusCode(301);
@@ -513,7 +514,7 @@
 
   ResourceRequest request(redirect_url);
   request.SetRequestorOrigin(GetSecurityOrigin());
-  MockResource* first_resource = MockResource::Create(request);
+  auto* first_resource = MakeGarbageCollected<MockResource>(request);
 
   ResourceResponse fresh302_response(redirect_url);
   fresh302_response.SetHttpStatusCode(302);
@@ -554,7 +555,7 @@
 
   ResourceRequest request(redirect_url);
   request.SetRequestorOrigin(GetSecurityOrigin());
-  MockResource* first_resource = MockResource::Create(request);
+  auto* first_resource = MakeGarbageCollected<MockResource>(request);
 
   ResourceResponse fresh302_response(redirect_url);
   fresh302_response.SetHttpStatusCode(302);
diff --git a/third_party/blink/renderer/platform/loader/fetch/memory_cache_test.cc b/third_party/blink/renderer/platform/loader/fetch/memory_cache_test.cc
index 9031a51..7100d42 100644
--- a/third_party/blink/renderer/platform/loader/fetch/memory_cache_test.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/memory_cache_test.cc
@@ -33,6 +33,7 @@
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/loader/fetch/raw_resource.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
@@ -84,15 +85,10 @@
  public:
   class FakeResource final : public Resource {
    public:
-    static FakeResource* Create(const char* url, ResourceType type) {
-      return Create(KURL(url), type);
-    }
-    static FakeResource* Create(const KURL& url, ResourceType type) {
-      ResourceRequest request(url);
-      ResourceLoaderOptions options;
-      return MakeGarbageCollected<FakeResource>(request, type, options);
-    }
-
+    FakeResource(const char* url, ResourceType type)
+        : FakeResource(KURL(url), type) {}
+    FakeResource(const KURL& url, ResourceType type)
+        : FakeResource(ResourceRequest(url), type, ResourceLoaderOptions()) {}
     FakeResource(const ResourceRequest& request,
                  ResourceType type,
                  const ResourceLoaderOptions& options)
@@ -103,7 +99,7 @@
   void SetUp() override {
     // Save the global memory cache to restore it upon teardown.
     global_memory_cache_ = ReplaceMemoryCacheForTesting(
-        MemoryCache::Create(platform_->test_task_runner()));
+        MakeGarbageCollected<MemoryCache>(platform_->test_task_runner()));
     auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
     fetcher_ = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
         *properties, MakeGarbageCollected<MockFetchContext>(),
@@ -363,19 +359,19 @@
 }
 
 TEST_F(MemoryCacheTest, RemoveDuringRevalidation) {
-  FakeResource* resource1 =
-      FakeResource::Create("http://test/resource", ResourceType::kRaw);
+  auto* resource1 = MakeGarbageCollected<FakeResource>("http://test/resource",
+                                                       ResourceType::kRaw);
   GetMemoryCache()->Add(resource1);
 
-  FakeResource* resource2 =
-      FakeResource::Create("http://test/resource", ResourceType::kRaw);
+  auto* resource2 = MakeGarbageCollected<FakeResource>("http://test/resource",
+                                                       ResourceType::kRaw);
   GetMemoryCache()->Remove(resource1);
   GetMemoryCache()->Add(resource2);
   EXPECT_TRUE(GetMemoryCache()->Contains(resource2));
   EXPECT_FALSE(GetMemoryCache()->Contains(resource1));
 
-  FakeResource* resource3 =
-      FakeResource::Create("http://test/resource", ResourceType::kRaw);
+  auto* resource3 = MakeGarbageCollected<FakeResource>("http://test/resource",
+                                                       ResourceType::kRaw);
   GetMemoryCache()->Remove(resource2);
   GetMemoryCache()->Add(resource3);
   EXPECT_TRUE(GetMemoryCache()->Contains(resource3));
@@ -383,12 +379,12 @@
 }
 
 TEST_F(MemoryCacheTest, ResourceMapIsolation) {
-  FakeResource* resource1 =
-      FakeResource::Create("http://test/resource", ResourceType::kRaw);
+  auto* resource1 = MakeGarbageCollected<FakeResource>("http://test/resource",
+                                                       ResourceType::kRaw);
   GetMemoryCache()->Add(resource1);
 
-  FakeResource* resource2 =
-      FakeResource::Create("http://test/resource", ResourceType::kRaw);
+  auto* resource2 = MakeGarbageCollected<FakeResource>("http://test/resource",
+                                                       ResourceType::kRaw);
   resource2->SetCacheIdentifier("foo");
   GetMemoryCache()->Add(resource2);
   EXPECT_TRUE(GetMemoryCache()->Contains(resource1));
@@ -401,8 +397,8 @@
   EXPECT_EQ(resource2, GetMemoryCache()->ResourceForURL(url, "foo"));
   EXPECT_EQ(nullptr, GetMemoryCache()->ResourceForURL(NullURL()));
 
-  FakeResource* resource3 =
-      FakeResource::Create("http://test/resource", ResourceType::kRaw);
+  auto* resource3 = MakeGarbageCollected<FakeResource>("http://test/resource",
+                                                       ResourceType::kRaw);
   resource3->SetCacheIdentifier("foo");
   GetMemoryCache()->Remove(resource2);
   GetMemoryCache()->Add(resource3);
@@ -421,7 +417,7 @@
 
 TEST_F(MemoryCacheTest, FragmentIdentifier) {
   const KURL url1 = KURL("http://test/resource#foo");
-  FakeResource* resource = FakeResource::Create(url1, ResourceType::kRaw);
+  auto* resource = MakeGarbageCollected<FakeResource>(url1, ResourceType::kRaw);
   GetMemoryCache()->Add(resource);
   EXPECT_TRUE(GetMemoryCache()->Contains(resource));
 
@@ -434,7 +430,7 @@
 TEST_F(MemoryCacheTest, RemoveURLFromCache) {
   const KURL url1 = KURL("http://test/resource1");
   Persistent<FakeResource> resource1 =
-      FakeResource::Create(url1, ResourceType::kRaw);
+      MakeGarbageCollected<FakeResource>(url1, ResourceType::kRaw);
   GetMemoryCache()->Add(resource1);
   EXPECT_TRUE(GetMemoryCache()->Contains(resource1));
 
@@ -442,7 +438,8 @@
   EXPECT_FALSE(GetMemoryCache()->Contains(resource1));
 
   const KURL url2 = KURL("http://test/resource2#foo");
-  FakeResource* resource2 = FakeResource::Create(url2, ResourceType::kRaw);
+  auto* resource2 =
+      MakeGarbageCollected<FakeResource>(url2, ResourceType::kRaw);
   GetMemoryCache()->Add(resource2);
   EXPECT_TRUE(GetMemoryCache()->Contains(resource2));
 
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
index fa977e6..6eab68b 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -40,6 +40,7 @@
 #include "third_party/blink/public/platform/web_url.h"
 #include "third_party/blink/public/platform/web_url_request.h"
 #include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/histogram.h"
 #include "third_party/blink/renderer/platform/instance_counters.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
@@ -1860,7 +1861,8 @@
       inflight_keepalive_bytes_ += size;
     }
 
-    loader = ResourceLoader::Create(this, scheduler_, resource, size);
+    loader =
+        MakeGarbageCollected<ResourceLoader>(this, scheduler_, resource, size);
     if (resource->ShouldBlockLoadEvent())
       loaders_.insert(loader);
     else
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
index 451f1c5..d0061eea 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
@@ -339,14 +339,6 @@
   }
 }
 
-ResourceLoader* ResourceLoader::Create(ResourceFetcher* fetcher,
-                                       ResourceLoadScheduler* scheduler,
-                                       Resource* resource,
-                                       uint32_t inflight_keepalive_bytes) {
-  return MakeGarbageCollected<ResourceLoader>(fetcher, scheduler, resource,
-                                              inflight_keepalive_bytes);
-}
-
 ResourceLoader::ResourceLoader(ResourceFetcher* fetcher,
                                ResourceLoadScheduler* scheduler,
                                Resource* resource,
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader.h b/third_party/blink/renderer/platform/loader/fetch/resource_loader.h
index f1dc3265..8b7c96c1 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.h
@@ -69,16 +69,11 @@
   USING_PRE_FINALIZER(ResourceLoader, Dispose);
 
  public:
-  static ResourceLoader* Create(ResourceFetcher*,
-                                ResourceLoadScheduler*,
-                                Resource*,
-                                uint32_t inflight_keepalive_bytes = 0);
-
   // Assumes ResourceFetcher and Resource are non-null.
   ResourceLoader(ResourceFetcher*,
                  ResourceLoadScheduler*,
                  Resource*,
-                 uint32_t inflight_keepalive_bytes);
+                 uint32_t inflight_keepalive_bytes = 0);
   ~ResourceLoader() override;
   void Trace(blink::Visitor*) override;
 
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_test.cc b/third_party/blink/renderer/platform/loader/fetch/resource_test.cc
index cdac072..c743e4de28 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_test.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_test.cc
@@ -65,7 +65,7 @@
   ResourceRequest request(response.CurrentRequestUrl());
   request.SetRequestorOrigin(
       SecurityOrigin::Create(response.CurrentRequestUrl()));
-  MockResource* resource = MockResource::Create(request);
+  auto* resource = MakeGarbageCollected<MockResource>(request);
   resource->SetResponse(response);
   resource->SendCachedMetadata(kTestData, sizeof(kTestData));
   return;
@@ -147,7 +147,7 @@
   KURL url("http://127.0.0.1:8000/foo.html");
   ResourceResponse response(url);
   response.SetHttpStatusCode(200);
-  MockResource* resource = MockResource::Create(url);
+  auto* resource = MakeGarbageCollected<MockResource>(url);
   resource->ResponseReceived(response);
   resource->FinishForTest();
 
@@ -166,7 +166,7 @@
   ResourceResponse response(url);
   response.SetHttpStatusCode(200);
 
-  MockResource* resource = MockResource::Create(url);
+  auto* resource = MakeGarbageCollected<MockResource>(url);
   resource->ResponseReceived(response);
   resource->FinishForTest();
 
@@ -192,7 +192,7 @@
   ResourceRequest old_request(url);
   old_request.SetHttpHeaderField(http_names::kUserAgent, "something");
   old_request.SetHttpHeaderField(http_names::kReferer, "http://foo.com");
-  resource = MockResource::Create(old_request);
+  resource = MakeGarbageCollected<MockResource>(old_request);
   resource->ResponseReceived(response);
   resource->FinishForTest();
 
@@ -220,7 +220,7 @@
   ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler>
       platform_;
   const KURL url("http://test.example.com/");
-  MockResource* resource = MockResource::Create(ResourceRequest(url));
+  auto* resource = MakeGarbageCollected<MockResource>(url);
   ResourceResponse response(url);
   response.SetHttpStatusCode(200);
   resource->ResponseReceived(response);
@@ -268,7 +268,7 @@
   ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler>
       platform_;
   const KURL url("http://test.example.com/");
-  MockResource* resource = MockResource::Create(ResourceRequest(url));
+  auto* resource = MakeGarbageCollected<MockResource>(url);
   ResourceResponse response(url);
   response.SetHttpStatusCode(200);
   resource->ResponseReceived(response);
@@ -310,7 +310,7 @@
   ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler>
       platform_;
   const KURL url("http://test.example.com/");
-  Resource* resource = MockResource::Create(ResourceRequest(url));
+  auto* resource = MakeGarbageCollected<MockResource>(url);
   ResourceResponse response(url);
   response.SetHttpStatusCode(200);
   resource->ResponseReceived(response);
@@ -342,7 +342,7 @@
   ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler>
       platform_;
   const KURL url("http://test.example.com/");
-  Resource* resource = MockResource::Create(ResourceRequest(url));
+  auto* resource = MakeGarbageCollected<MockResource>(url);
   ResourceResponse response(url);
   response.SetHttpStatusCode(200);
   response.AddHttpHeaderField("keep-alive", "keep-alive value");
@@ -420,7 +420,7 @@
   const KURL url("http://test.example.com/1");
   const KURL redirect_target_url("http://test.example.com/2");
 
-  MockResource* resource = MockResource::Create(ResourceRequest(url));
+  auto* resource = MakeGarbageCollected<MockResource>(url);
   ResourceResponse response(url);
   response.SetHttpStatusCode(200);
   resource->ResponseReceived(response);
@@ -508,7 +508,7 @@
   response.SetHttpHeaderField(http_names::kCacheControl,
                               "max-age=0, stale-while-revalidate=40");
 
-  MockResource* resource = MockResource::Create(url);
+  auto* resource = MakeGarbageCollected<MockResource>(url);
   resource->ResponseReceived(response);
   resource->FinishForTest();
 
@@ -545,7 +545,7 @@
   redirect_response.SetAsyncRevalidationRequested(true);
   ResourceRequest redirected_revalidating_request(redirect_target_url);
 
-  MockResource* resource = MockResource::Create(url);
+  auto* resource = MakeGarbageCollected<MockResource>(url);
   resource->WillFollowRedirect(redirected_revalidating_request,
                                redirect_response);
   resource->ResponseReceived(response);
diff --git a/third_party/blink/renderer/platform/loader/testing/mock_resource.cc b/third_party/blink/renderer/platform/loader/testing/mock_resource.cc
index 7648bfa..4ea7e6a 100644
--- a/third_party/blink/renderer/platform/loader/testing/mock_resource.cc
+++ b/third_party/blink/renderer/platform/loader/testing/mock_resource.cc
@@ -34,17 +34,10 @@
       fetcher->RequestResource(params, MockResourceFactory(), client));
 }
 
-// static
-MockResource* MockResource::Create(const ResourceRequest& request) {
-  ResourceLoaderOptions options;
-  return MakeGarbageCollected<MockResource>(request, options);
-}
-
-MockResource* MockResource::Create(const KURL& url) {
-  ResourceRequest request(url);
-  return Create(request);
-}
-
+MockResource::MockResource(const KURL& url)
+    : MockResource(ResourceRequest(url)) {}
+MockResource::MockResource(const ResourceRequest& request)
+    : MockResource(request, ResourceLoaderOptions()) {}
 MockResource::MockResource(const ResourceRequest& request,
                            const ResourceLoaderOptions& options)
     : Resource(request, ResourceType::kMock, options) {}
diff --git a/third_party/blink/renderer/platform/loader/testing/mock_resource.h b/third_party/blink/renderer/platform/loader/testing/mock_resource.h
index da535a14..9f677ec 100644
--- a/third_party/blink/renderer/platform/loader/testing/mock_resource.h
+++ b/third_party/blink/renderer/platform/loader/testing/mock_resource.h
@@ -45,8 +45,8 @@
   static MockResource* Fetch(FetchParameters&,
                              ResourceFetcher*,
                              ResourceClient*);
-  static MockResource* Create(const ResourceRequest&);
-  static MockResource* Create(const KURL&);
+  explicit MockResource(const KURL&);
+  explicit MockResource(const ResourceRequest&);
   MockResource(const ResourceRequest&, const ResourceLoaderOptions&);
 
   CachedMetadataHandler* CreateCachedMetadataHandler(
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_component.cc b/third_party/blink/renderer/platform/mediastream/media_stream_component.cc
index 58335b9..662358b 100644
--- a/third_party/blink/renderer/platform/mediastream/media_stream_component.cc
+++ b/third_party/blink/renderer/platform/mediastream/media_stream_component.cc
@@ -34,6 +34,7 @@
 #include "third_party/blink/public/platform/web_audio_source_provider.h"
 #include "third_party/blink/public/platform/web_media_stream_track.h"
 #include "third_party/blink/renderer/platform/audio/audio_bus.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/mediastream/media_stream_center.h"
 #include "third_party/blink/renderer/platform/mediastream/media_stream_source.h"
 #include "third_party/blink/renderer/platform/uuid.h"
@@ -51,16 +52,8 @@
   return ++g_unique_media_stream_component_id;
 }
 
-MediaStreamComponent* MediaStreamComponent::Create(MediaStreamSource* source) {
-  return MakeGarbageCollected<MediaStreamComponent>(CreateCanonicalUUIDString(),
-                                                    source);
-}
-
-MediaStreamComponent* MediaStreamComponent::Create(const String& id,
-                                                   MediaStreamSource* source) {
-  return MakeGarbageCollected<MediaStreamComponent>(id, source);
-}
-
+MediaStreamComponent::MediaStreamComponent(MediaStreamSource* source)
+    : MediaStreamComponent(CreateCanonicalUUIDString(), source) {}
 MediaStreamComponent::MediaStreamComponent(const String& id,
                                            MediaStreamSource* source)
     : source_(source), id_(id), unique_id_(GenerateUniqueId()) {
@@ -69,9 +62,7 @@
 }
 
 MediaStreamComponent* MediaStreamComponent::Clone() const {
-  MediaStreamComponent* cloned_component =
-      MakeGarbageCollected<MediaStreamComponent>(CreateCanonicalUUIDString(),
-                                                 Source());
+  auto* cloned_component = MakeGarbageCollected<MediaStreamComponent>(Source());
   cloned_component->SetEnabled(enabled_);
   cloned_component->SetMuted(muted_);
   cloned_component->SetContentHint(content_hint_);
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_component.h b/third_party/blink/renderer/platform/mediastream/media_stream_component.h
index 11e9149f..ade35b4 100644
--- a/third_party/blink/renderer/platform/mediastream/media_stream_component.h
+++ b/third_party/blink/renderer/platform/mediastream/media_stream_component.h
@@ -59,9 +59,7 @@
   static int GenerateUniqueId();
 
  public:
-  static MediaStreamComponent* Create(MediaStreamSource*);
-  static MediaStreamComponent* Create(const String& id, MediaStreamSource*);
-
+  MediaStreamComponent(MediaStreamSource*);
   MediaStreamComponent(const String& id, MediaStreamSource*);
 
   MediaStreamComponent* Clone() const;
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_descriptor.cc b/third_party/blink/renderer/platform/mediastream/media_stream_descriptor.cc
index 3c702126..b113929f 100644
--- a/third_party/blink/renderer/platform/mediastream/media_stream_descriptor.cc
+++ b/third_party/blink/renderer/platform/mediastream/media_stream_descriptor.cc
@@ -32,6 +32,7 @@
 #include "third_party/blink/renderer/platform/mediastream/media_stream_descriptor.h"
 
 #include "third_party/blink/public/platform/web_media_stream.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/uuid.h"
 
 namespace blink {
@@ -47,28 +48,6 @@
   return ++g_unique_media_stream_descriptor_id;
 }
 
-MediaStreamDescriptor* MediaStreamDescriptor::Create(
-    const MediaStreamSourceVector& audio_sources,
-    const MediaStreamSourceVector& video_sources) {
-  return MakeGarbageCollected<MediaStreamDescriptor>(
-      CreateCanonicalUUIDString(), audio_sources, video_sources);
-}
-
-MediaStreamDescriptor* MediaStreamDescriptor::Create(
-    const MediaStreamComponentVector& audio_components,
-    const MediaStreamComponentVector& video_components) {
-  return MakeGarbageCollected<MediaStreamDescriptor>(
-      CreateCanonicalUUIDString(), audio_components, video_components);
-}
-
-MediaStreamDescriptor* MediaStreamDescriptor::Create(
-    const String& id,
-    const MediaStreamComponentVector& audio_components,
-    const MediaStreamComponentVector& video_components) {
-  return MakeGarbageCollected<MediaStreamDescriptor>(id, audio_components,
-                                                     video_components);
-}
-
 void MediaStreamDescriptor::AddComponent(MediaStreamComponent* component) {
   switch (component->Source()->GetType()) {
     case MediaStreamSource::kTypeAudio:
@@ -145,19 +124,37 @@
 }
 
 MediaStreamDescriptor::MediaStreamDescriptor(
+    const MediaStreamSourceVector& audio_sources,
+    const MediaStreamSourceVector& video_sources)
+    : MediaStreamDescriptor(CreateCanonicalUUIDString(),
+                            audio_sources,
+                            video_sources) {}
+
+MediaStreamDescriptor::MediaStreamDescriptor(
     const String& id,
     const MediaStreamSourceVector& audio_sources,
     const MediaStreamSourceVector& video_sources)
     : client_(nullptr), id_(id), unique_id_(GenerateUniqueId()), active_(true) {
   DCHECK(id_.length());
-  for (MediaStreamSource* source : audio_sources)
-    audio_components_.push_back(MediaStreamComponent::Create(source));
+  for (MediaStreamSource* source : audio_sources) {
+    audio_components_.push_back(
+        MakeGarbageCollected<MediaStreamComponent>(source));
+  }
 
-  for (MediaStreamSource* source : video_sources)
-    video_components_.push_back(MediaStreamComponent::Create(source));
+  for (MediaStreamSource* source : video_sources) {
+    video_components_.push_back(
+        MakeGarbageCollected<MediaStreamComponent>(source));
+  }
 }
 
 MediaStreamDescriptor::MediaStreamDescriptor(
+    const MediaStreamComponentVector& audio_components,
+    const MediaStreamComponentVector& video_components)
+    : MediaStreamDescriptor(CreateCanonicalUUIDString(),
+                            audio_components,
+                            video_components) {}
+
+MediaStreamDescriptor::MediaStreamDescriptor(
     const String& id,
     const MediaStreamComponentVector& audio_components,
     const MediaStreamComponentVector& video_components)
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_descriptor.h b/third_party/blink/renderer/platform/mediastream/media_stream_descriptor.h
index d7d0c01..0f007d6 100644
--- a/third_party/blink/renderer/platform/mediastream/media_stream_descriptor.h
+++ b/third_party/blink/renderer/platform/mediastream/media_stream_descriptor.h
@@ -61,22 +61,13 @@
 
  public:
   // Only used for AudioDestinationNode.
-  static MediaStreamDescriptor* Create(
-      const MediaStreamSourceVector& audio_sources,
-      const MediaStreamSourceVector& video_sources);
-
-  static MediaStreamDescriptor* Create(
-      const MediaStreamComponentVector& audio_components,
-      const MediaStreamComponentVector& video_components);
-
-  static MediaStreamDescriptor* Create(
-      const String& id,
-      const MediaStreamComponentVector& audio_components,
-      const MediaStreamComponentVector& video_components);
-
+  MediaStreamDescriptor(const MediaStreamSourceVector& audio_sources,
+                        const MediaStreamSourceVector& video_sources);
   MediaStreamDescriptor(const String& id,
                         const MediaStreamSourceVector& audio_sources,
                         const MediaStreamSourceVector& video_sources);
+  MediaStreamDescriptor(const MediaStreamComponentVector& audio_components,
+                        const MediaStreamComponentVector& video_components);
   MediaStreamDescriptor(const String& id,
                         const MediaStreamComponentVector& audio_components,
                         const MediaStreamComponentVector& video_components);
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_source.cc b/third_party/blink/renderer/platform/mediastream/media_stream_source.cc
index ca58bd38..639c7b4 100644
--- a/third_party/blink/renderer/platform/mediastream/media_stream_source.cc
+++ b/third_party/blink/renderer/platform/mediastream/media_stream_source.cc
@@ -35,16 +35,6 @@
 
 namespace blink {
 
-MediaStreamSource* MediaStreamSource::Create(const String& id,
-                                             StreamType type,
-                                             const String& name,
-                                             bool remote,
-                                             ReadyState ready_state,
-                                             bool requires_consumer) {
-  return MakeGarbageCollected<MediaStreamSource>(
-      id, type, name, remote, ready_state, requires_consumer);
-}
-
 MediaStreamSource::MediaStreamSource(const String& id,
                                      StreamType type,
                                      const String& name,
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_source.h b/third_party/blink/renderer/platform/mediastream/media_stream_source.h
index 5071f3a..7f03e8d 100644
--- a/third_party/blink/renderer/platform/mediastream/media_stream_source.h
+++ b/third_party/blink/renderer/platform/mediastream/media_stream_source.h
@@ -68,19 +68,12 @@
 
   enum class EchoCancellationMode { kDisabled, kBrowser, kAec3, kSystem };
 
-  static MediaStreamSource* Create(const String& id,
-                                   StreamType,
-                                   const String& name,
-                                   bool remote,
-                                   ReadyState = kReadyStateLive,
-                                   bool requires_consumer = false);
-
   MediaStreamSource(const String& id,
                     StreamType,
                     const String& name,
                     bool remote,
-                    ReadyState,
-                    bool requires_consumer);
+                    ReadyState = kReadyStateLive,
+                    bool requires_consumer = false);
 
   const String& Id() const { return id_; }
   StreamType GetType() const { return type_; }
diff --git a/third_party/blink/renderer/platform/transforms/transformation_matrix.cc b/third_party/blink/renderer/platform/transforms/transformation_matrix.cc
index 7a63f9d..1bea01b 100644
--- a/third_party/blink/renderer/platform/transforms/transformation_matrix.cc
+++ b/third_party/blink/renderer/platform/transforms/transformation_matrix.cc
@@ -2080,7 +2080,10 @@
 
 SkMatrix44 TransformationMatrix::ToSkMatrix44(
     const TransformationMatrix& matrix) {
-  SkMatrix44 ret(SkMatrix44::kUninitialized_Constructor);
+  // TODO(masonfreed): Replace this with an explicit 16-element constructor
+  // on SkMatrix44, once that's available. This code does a *lot* of extra
+  // work, because each call to setDouble re-calculates the matrix type.
+  SkMatrix44 ret(SkMatrix44::kIdentity_Constructor);
   ret.setDouble(0, 0, matrix.M11());
   ret.setDouble(0, 1, matrix.M21());
   ret.setDouble(0, 2, matrix.M31());
@@ -2102,7 +2105,10 @@
 
 gfx::Transform TransformationMatrix::ToTransform(
     const TransformationMatrix& matrix) {
-  return gfx::Transform(TransformationMatrix::ToSkMatrix44(matrix));
+  return gfx::Transform(matrix.M11(), matrix.M21(), matrix.M31(), matrix.M41(),
+                        matrix.M12(), matrix.M22(), matrix.M32(), matrix.M42(),
+                        matrix.M13(), matrix.M23(), matrix.M33(), matrix.M43(),
+                        matrix.M14(), matrix.M24(), matrix.M34(), matrix.M44());
 }
 
 String TransformationMatrix::ToString(bool as_matrix) const {
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-features=NetworkService b/third_party/blink/web_tests/FlagExpectations/disable-features=NetworkService
index e50180c..e688a21 100644
--- a/third_party/blink/web_tests/FlagExpectations/disable-features=NetworkService
+++ b/third_party/blink/web_tests/FlagExpectations/disable-features=NetworkService
@@ -18,6 +18,9 @@
 crbug.com/933880 external/wpt/FileAPI/url/url-with-fetch.any.html [ Failure ]
 crbug.com/933880 external/wpt/FileAPI/url/url-with-xhr.any.html [ Failure ]
 
+crbug.com/950412 [ Linux Debug ] http/tests/inspector-protocol/network/request-interception-request-id.js [ Failure ]
+crbug.com/950412 [ Linux Debug ] virtual/nobinary-for-http-inspector-protocol/http/tests/inspector-protocol/network/request-interception-request-id.js [ Failure ]
+
 # This passes in content_shell but not in chrome with network service disabled,
 # because content_shell does not add the about: handler. With network service
 # enabled this fails in both content_shell and chrome.
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 7c4e8ab..d8ee1f1 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -6246,3 +6246,8 @@
 
 # Sheriff 2019-04-05
 crbug.com/ [ Win7 ] virtual/streams-native/http/tests/fetch/serviceworker/referrer-base-https-other-https.html [ Pass Timeout ]
+
+# Sheriff 2019-04-08
+crbug.com/946701 [ Win7 ] virtual/streams-native/http/tests/fetch/serviceworker-proxied/thorough/auth-base-https-other-https.html [ Pass Timeout ]
+crbug.com/950222 [ Win7 ] virtual/streams-native/http/tests/fetch/serviceworker-proxied/thorough/auth.html [ Pass Timeout ]
+crbug.com/947670 [ Win7 ] virtual/streams-native/http/tests/fetch/serviceworker-proxied/thorough/cors-preflight2-base-https-other-https.html [ Pass Timeout ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
index ba86f88..1112f43 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
@@ -58229,6 +58229,18 @@
      {}
     ]
    ],
+   "css/css-pseudo/marker-display-dynamic-001.html": [
+    [
+     "/css/css-pseudo/marker-display-dynamic-001.html",
+     [
+      [
+       "/css/css-pseudo/marker-color-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-pseudo/marker-font-properties.html": [
     [
      "/css/css-pseudo/marker-font-properties.html",
@@ -114672,6 +114684,18 @@
      ],
      {}
     ]
+   ],
+   "xhtml/adopt-while-parsing-001.html": [
+    [
+     "/xhtml/adopt-while-parsing-001.html",
+     [
+      [
+       "/xhtml/adopt-while-parsing-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
    ]
   },
   "reftest_node": {
@@ -162981,6 +163005,31 @@
      {}
     ]
    ],
+   "feature-policy/parameters/feature-parameters-inf.html": [
+    [
+     {}
+    ]
+   ],
+   "feature-policy/parameters/feature-parameters-inf.html.headers": [
+    [
+     {}
+    ]
+   ],
+   "feature-policy/parameters/feature-parameters.html.headers": [
+    [
+     {}
+    ]
+   ],
+   "feature-policy/parameters/resources/feature-parameters-frame.html": [
+    [
+     {}
+    ]
+   ],
+   "feature-policy/parameters/resources/sample-1.png": [
+    [
+     {}
+    ]
+   ],
    "feature-policy/payment-allowed-by-feature-policy.https.sub.html.headers": [
     [
      {}
@@ -204680,6 +204729,16 @@
     [
      {}
     ]
+   ],
+   "xhtml/adopt-while-parsing-001-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "xhtml/adopt-while-parsing.xhtml": [
+    [
+     {}
+    ]
    ]
   },
   "testharness": {
@@ -213415,6 +213474,12 @@
      {}
     ]
    ],
+   "animation-worklet/stateful-animator.https.html": [
+    [
+     "/animation-worklet/stateful-animator.https.html",
+     {}
+    ]
+   ],
    "animation-worklet/worklet-animation-creation.https.html": [
     [
      "/animation-worklet/worklet-animation-creation.https.html",
@@ -246015,6 +246080,18 @@
      {}
     ]
    ],
+   "feature-policy/parameters/feature-parameters-with-frames.html": [
+    [
+     "/feature-policy/parameters/feature-parameters-with-frames.html",
+     {}
+    ]
+   ],
+   "feature-policy/parameters/feature-parameters.html": [
+    [
+     "/feature-policy/parameters/feature-parameters.html",
+     {}
+    ]
+   ],
    "feature-policy/payment-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html": [
     [
      "/feature-policy/payment-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html",
@@ -321977,6 +322054,10 @@
    "761e66e7d76f4aaf64c7744d0d04a06e3ba16cd1",
    "testharness"
   ],
+  "animation-worklet/stateful-animator.https.html": [
+   "c4b6301fd9dc2e5cf021cb79ddb05032679010f9",
+   "testharness"
+  ],
   "animation-worklet/worklet-animation-cancel-ref.html": [
    "d44927374703ef2b38d3ed0c9570609b62baec65",
    "support"
@@ -370265,6 +370346,10 @@
    "d45c76696eca826456988d7884adcaa52bfad9cd",
    "reftest"
   ],
+  "css/css-pseudo/marker-display-dynamic-001.html": [
+   "c06da7ca803455559a7a12b915d9083b32106cd1",
+   "reftest"
+  ],
   "css/css-pseudo/marker-font-properties-ref.html": [
    "a8fb980ff09cf8e326e6728976ac6dd8230866f3",
    "support"
@@ -397870,7 +397955,7 @@
    "testharness"
   ],
   "css/cssom-view/scrollintoview.html": [
-   "c69025b4943accd4c0b34e74dbd7862af2521849",
+   "584ab4b60329d7cd1081edac93a375b7069634ea",
    "testharness"
   ],
   "css/cssom-view/support/1x1-green.png": [
@@ -413213,6 +413298,34 @@
    "33bbe3c14ffe28d961cc4c71c0b367028ff8d2df",
    "testharness"
   ],
+  "feature-policy/parameters/feature-parameters-inf.html": [
+   "db21427c8ed9f3c2f8e8b8ba9d91d4fd230fc2ff",
+   "support"
+  ],
+  "feature-policy/parameters/feature-parameters-inf.html.headers": [
+   "1ec003431b3f090dbb596f6973b84f81de27ace0",
+   "support"
+  ],
+  "feature-policy/parameters/feature-parameters-with-frames.html": [
+   "de0a3ab1e3963e3e7c8da1e6bec35d454b1a9fdb",
+   "testharness"
+  ],
+  "feature-policy/parameters/feature-parameters.html": [
+   "9830f93eb4dcac9aaa2dfe6d209c452df5f94701",
+   "testharness"
+  ],
+  "feature-policy/parameters/feature-parameters.html.headers": [
+   "b4fa805c5696ab5ef8171508aeccf200e9d95df3",
+   "support"
+  ],
+  "feature-policy/parameters/resources/feature-parameters-frame.html": [
+   "4f01f85795da8114e762cb0ddc271cefdd02da1f",
+   "support"
+  ],
+  "feature-policy/parameters/resources/sample-1.png": [
+   "92901925c6082b7fb01fade09f87356308218a47",
+   "support"
+  ],
   "feature-policy/payment-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html": [
    "daa2aa182daed73bd51bf32cf7981a805e3956c8",
    "testharness"
@@ -413638,7 +413751,7 @@
    "support"
   ],
   "feature-policy/resources/featurepolicy.js": [
-   "e2577f35c3fb53abda3934274c3e6a281ba617d9",
+   "744c4c62069508061567d8ac758920beab8e1335",
    "support"
   ],
   "feature-policy/resources/picture-in-picture.js": [
@@ -415250,7 +415363,7 @@
    "testharness"
   ],
   "fetch/sec-metadata/iframe.tentative.https.sub.html": [
-   "461d9f28fa1e8987e3b05c48cb10fa6f4f8bf326",
+   "b916e3aa70b9b05cd899f1da0c3252ca64c12626",
    "testharness"
   ],
   "fetch/sec-metadata/iframe.tentative.sub.html": [
@@ -415374,7 +415487,7 @@
    "testharness"
   ],
   "fetch/sec-metadata/window-open.tentative.https.sub.html": [
-   "0be9f2ce577d5cdd590e0326ed650455d87f1ee4",
+   "df13d55cf1ed6f206c9db7f681f56a3f0f834ef3",
    "testharness"
   ],
   "fetch/sec-metadata/worker.tentative.https.sub.html": [
@@ -480298,11 +480411,11 @@
    "testharness"
   ],
   "webrtc/RTCPeerConnection-addIceCandidate-expected.txt": [
-   "9d7cf8b11965a4efd93c495101fa5421f5d79719",
+   "592494363d83d09691ad5d81ef62291e6fe7d149",
    "support"
   ],
   "webrtc/RTCPeerConnection-addIceCandidate.html": [
-   "51a5677699fd635335ede3f7e41ec48b17d3e60c",
+   "3641252a13de00ef05248ade299a98c578fab448",
    "testharness"
   ],
   "webrtc/RTCPeerConnection-addTrack.https.html": [
@@ -489188,6 +489301,18 @@
   "xhr/xmlhttprequest-unsent.htm": [
    "eb52d63eef971895f69f1b0151baa457250dd452",
    "testharness"
+  ],
+  "xhtml/adopt-while-parsing-001-ref.html": [
+   "5b512e72f5a1f3780c9c38be79968b095c277a39",
+   "support"
+  ],
+  "xhtml/adopt-while-parsing-001.html": [
+   "74018b4ad0f342aa5b38ad337ce9329e6d92545d",
+   "reftest"
+  ],
+  "xhtml/adopt-while-parsing.xhtml": [
+   "2d85d21558b1778e17376d12424f81c703c0c262",
+   "support"
   ]
  },
  "url_base": "/",
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-display-dynamic-001.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-display-dynamic-001.html
new file mode 100644
index 0000000..c06da7c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-display-dynamic-001.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Test: ::marker is created dynamically properly</title>
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="match" href="marker-color-ref.html">
+<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#marker-pseudo">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1538589">
+<style>
+li {
+  color: green;
+  font-size: 40px;
+  list-style-type: square;
+}
+::marker {
+  display: none;
+}
+.tweak::marker {
+  display: initial;
+}
+</style>
+<ol>
+    <li><!-- The list marker should be a green square.--></li>
+</ol>
+<script>
+  onload = function() {
+    let li = document.querySelector("li");
+    li.offsetTop;
+    li.classList.add("tweak");
+  }
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom-view/scrollintoview.html b/third_party/blink/web_tests/external/wpt/css/cssom-view/scrollintoview.html
index c69025b..584ab4b 100644
--- a/third_party/blink/web_tests/external/wpt/css/cssom-view/scrollintoview.html
+++ b/third_party/blink/web_tests/external/wpt/css/cssom-view/scrollintoview.html
@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <title>CSSOM View - scrollIntoView</title>
 <meta charset="utf-8">
+<meta name="viewport" content="initial-scale=1">
 <link rel="author" title="Chris Wu" href="mailto:pwx.frontend@gmail.com">
 <link rel="help" href="https://drafts.csswg.org/cssom-view/#dom-element-scrollintoview">
 <link rel="help" href="https://heycam.github.io/webidl/#es-operations">
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-addIceCandidate-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-addIceCandidate-expected.txt
index 9d7cf8b..592494363 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-addIceCandidate-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-addIceCandidate-expected.txt
@@ -4,9 +4,9 @@
 FAIL addIceCandidate(undefined) should work, and add a=end-of-candidates to both m-sections promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': 1 argument required, but only 0 present."
 FAIL addIceCandidate(null) should work, and add a=end-of-candidates to both m-sections promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': 1 argument required, but only 0 present."
 FAIL addIceCandidate({}) should work, and add a=end-of-candidates to both m-sections promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': 1 argument required, but only 0 present."
-FAIL addIceCandidate({usernameFragment: usernameFragment1}) should work, and add a=end-of-candidates to the first m-section promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': Candidate missing values for both sdpMid and sdpMLineIndex"
-FAIL addIceCandidate({usernameFragment: usernameFragment2}) should work, and add a=end-of-candidates to the first m-section promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': Candidate missing values for both sdpMid and sdpMLineIndex"
-FAIL addIceCandidate({usernameFragment: "no such ufrag"}) should work, but not add a=end-of-candidates promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': Candidate missing values for both sdpMid and sdpMLineIndex"
+FAIL addIceCandidate({usernameFragment: usernameFragment1, sdpMid: sdpMid1}) should work, and add a=end-of-candidates to the first m-section promise_test: Unhandled rejection with value: object "OperationError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': Error processing ICE candidate"
+FAIL addIceCandidate({usernameFragment: usernameFragment2, sdpMLineIndex: 1}) should work, and add a=end-of-candidates to the first m-section promise_test: Unhandled rejection with value: object "OperationError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': Error processing ICE candidate"
+FAIL addIceCandidate({usernameFragment: "no such ufrag"}) should not work assert_throws: function "function() { throw e }" threw object "TypeError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': Candidate missing values for both sdpMid and sdpMLineIndex" that is not a DOMException OperationError: property "code" is equal to undefined, expected 0
 PASS Add ICE candidate after setting remote description should succeed
 PASS Add ICE candidate with RTCIceCandidate should succeed
 PASS Add candidate with only valid sdpMid should succeed
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-addIceCandidate.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-addIceCandidate.html
index 51a5677..3641252 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-addIceCandidate.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-addIceCandidate.html
@@ -176,12 +176,15 @@
     t.add_cleanup(() => pc.close());
 
     await pc.setRemoteDescription(sessionDesc);
-    await pc.addIceCandidate({usernameFragment: usernameFragment1});
+    await pc.addIceCandidate({
+      usernameFragment: usernameFragment1,
+      sdpMid: sdpMid1
+    });
     assert_candidate_line_between(pc.remoteDescription.sdp,
       mediaLine1, endOfCandidateLine, mediaLine2);
     assert_false(is_candidate_line_after(pc.remoteDescription.sdp,
       mediaLine2, endOfCandidateLine));
-  }, 'addIceCandidate({usernameFragment: usernameFragment1}) should work, and add a=end-of-candidates to the first m-section');
+  }, 'addIceCandidate({usernameFragment: usernameFragment1, sdpMid: sdpMid1}) should work, and add a=end-of-candidates to the first m-section');
 
   promise_test(async t => {
     const pc = new RTCPeerConnection();
@@ -189,12 +192,15 @@
     t.add_cleanup(() => pc.close());
 
     await pc.setRemoteDescription(sessionDesc);
-    await pc.addIceCandidate({usernameFragment: usernameFragment2});
+    await pc.addIceCandidate({
+      usernameFragment: usernameFragment2,
+      sdpMLineIndex: 1
+    });
     assert_false(is_candidate_line_between(pc.remoteDescription.sdp,
       mediaLine1, endOfCandidateLine, mediaLine2));
     assert_true(is_candidate_line_after(pc.remoteDescription.sdp,
       mediaLine2, endOfCandidateLine));
-  }, 'addIceCandidate({usernameFragment: usernameFragment2}) should work, and add a=end-of-candidates to the first m-section');
+  }, 'addIceCandidate({usernameFragment: usernameFragment2, sdpMLineIndex: 1}) should work, and add a=end-of-candidates to the first m-section');
 
   promise_test(async t => {
     const pc = new RTCPeerConnection();
@@ -202,12 +208,9 @@
     t.add_cleanup(() => pc.close());
 
     await pc.setRemoteDescription(sessionDesc);
-    await pc.addIceCandidate({usernameFragment: "no such ufrag"});
-    assert_false(is_candidate_line_between(pc.remoteDescription.sdp,
-      mediaLine1, endOfCandidateLine, mediaLine2));
-    assert_false(is_candidate_line_after(pc.remoteDescription.sdp,
-      mediaLine2, endOfCandidateLine));
-  }, 'addIceCandidate({usernameFragment: "no such ufrag"}) should work, but not add a=end-of-candidates');
+    await promise_rejects(t, 'OperationError',
+      pc.addIceCandidate({usernameFragment: "no such ufrag"}));
+  }, 'addIceCandidate({usernameFragment: "no such ufrag"}) should not work');
 
   promise_test(t => {
     const pc = new RTCPeerConnection();
@@ -316,7 +319,7 @@
       candidate: candidateStr1,
       sdpMid: sdpMid1,
       sdpMLineIndex: sdpMLineIndex1,
-      ufrag: null
+      usernameFragment: null
     }))
     .then(() => {
       assert_candidate_line_between(pc.remoteDescription.sdp,
@@ -539,7 +542,7 @@
           candidate: candidateStr1,
           sdpMid: sdpMid1,
           sdpMLineIndex: sdpMLineIndex1,
-          ufrag: 'invalid'
+          usernameFragment: 'invalid'
         })));
   }, 'Add candidate with invalid usernameFragment should reject with OperationError');
 
@@ -578,7 +581,7 @@
           candidate: candidateStr2,
           sdpMid: sdpMid2,
           sdpMLineIndex: sdpMLineIndex2,
-          usernameFragement: usernameFragment1
+          usernameFragment: usernameFragment1
         })));
   }, 'Add candidate with sdpMid belonging to different usernameFragment should reject with OperationError');
 
diff --git a/third_party/blink/web_tests/external/wpt/xhtml/adopt-while-parsing-001-ref.html b/third_party/blink/web_tests/external/wpt/xhtml/adopt-while-parsing-001-ref.html
new file mode 100644
index 0000000..5b512e7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/xhtml/adopt-while-parsing-001-ref.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<title>Test reference</title>
+<style>
+  html, body { margin: 0 }
+</style>
+<iframe src="about:blank"></iframe>
+<div>
+  PASS
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/xhtml/adopt-while-parsing-001.html b/third_party/blink/web_tests/external/wpt/xhtml/adopt-while-parsing-001.html
new file mode 100644
index 0000000..74018b4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/xhtml/adopt-while-parsing-001.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<title>Appending from the parser after adopting in an XML document doesn't miss notifications</title>
+<link rel="match" href="adopt-while-parsing-001-ref.html">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1511329">
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<style>
+  html, body { margin: 0 }
+</style>
+<script>
+  // If we don't get notified of the <div> insertion, the PASS text will never appear.
+  function parsingInterrupted() {
+    let frameDoc = document.querySelector("iframe").contentDocument;
+    let root = frameDoc.documentElement;
+    document.documentElement.appendChild(root);
+    root.offsetTop;
+  }
+</script>
+<iframe src="adopt-while-parsing.xhtml"></iframe>
diff --git a/third_party/blink/web_tests/external/wpt/xhtml/adopt-while-parsing.xhtml b/third_party/blink/web_tests/external/wpt/xhtml/adopt-while-parsing.xhtml
new file mode 100644
index 0000000..2d85d21
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/xhtml/adopt-while-parsing.xhtml
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<body>
+  <script>
+    window.parent.parsingInterrupted();
+  </script>
+  <div>
+    PASS
+  </div>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-addIceCandidate-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-addIceCandidate-expected.txt
new file mode 100644
index 0000000..592494363
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-addIceCandidate-expected.txt
@@ -0,0 +1,30 @@
+This is a testharness.js-based test.
+FAIL Add ICE candidate before setting remote description should reject with InvalidStateError assert_throws: function "function() { throw e }" threw object "OperationError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': Error processing ICE candidate" that is not a DOMException InvalidStateError: property "code" is equal to 0, expected 11
+FAIL addIceCandidate({"candidate":"","sdpMid":null,"sdpMLineIndex":null}) should work, and add a=end-of-candidates to both m-sections promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': 1 argument required, but only 0 present."
+FAIL addIceCandidate(undefined) should work, and add a=end-of-candidates to both m-sections promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': 1 argument required, but only 0 present."
+FAIL addIceCandidate(null) should work, and add a=end-of-candidates to both m-sections promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': 1 argument required, but only 0 present."
+FAIL addIceCandidate({}) should work, and add a=end-of-candidates to both m-sections promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': 1 argument required, but only 0 present."
+FAIL addIceCandidate({usernameFragment: usernameFragment1, sdpMid: sdpMid1}) should work, and add a=end-of-candidates to the first m-section promise_test: Unhandled rejection with value: object "OperationError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': Error processing ICE candidate"
+FAIL addIceCandidate({usernameFragment: usernameFragment2, sdpMLineIndex: 1}) should work, and add a=end-of-candidates to the first m-section promise_test: Unhandled rejection with value: object "OperationError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': Error processing ICE candidate"
+FAIL addIceCandidate({usernameFragment: "no such ufrag"}) should not work assert_throws: function "function() { throw e }" threw object "TypeError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': Candidate missing values for both sdpMid and sdpMLineIndex" that is not a DOMException OperationError: property "code" is equal to undefined, expected 0
+PASS Add ICE candidate after setting remote description should succeed
+PASS Add ICE candidate with RTCIceCandidate should succeed
+PASS Add candidate with only valid sdpMid should succeed
+PASS Add candidate with only valid sdpMLineIndex should succeed
+PASS addIceCandidate with first sdpMid and sdpMLineIndex add candidate to first media stream
+PASS addIceCandidate with second sdpMid and sdpMLineIndex should add candidate to second media stream
+PASS Add candidate for first media stream with null usernameFragment should add candidate to first media stream
+PASS Adding multiple candidates should add candidates to their corresponding media stream
+FAIL Add with empty candidate string (end of candidate) should succeed promise_test: Unhandled rejection with value: object "OperationError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': Error processing ICE candidate"
+PASS Add candidate with both sdpMid and sdpMLineIndex manually set to null should reject with TypeError
+PASS Add candidate with only valid candidate string should reject with TypeError
+PASS Add candidate with invalid candidate string and both sdpMid and sdpMLineIndex null should reject with TypeError
+PASS Add candidate with invalid sdpMid should reject with OperationError
+PASS Add candidate with invalid sdpMLineIndex should reject with OperationError
+FAIL Invalid sdpMLineIndex should be ignored if valid sdpMid is provided promise_test: Unhandled rejection with value: object "OperationError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': Error processing ICE candidate"
+PASS Add candidate for media stream 2 with null usernameFragment should succeed
+FAIL Add candidate with invalid usernameFragment should reject with OperationError assert_unreached: Should have rejected: undefined Reached unreachable code
+PASS Add candidate with invalid candidate string should reject with OperationError
+FAIL Add candidate with sdpMid belonging to different usernameFragment should reject with OperationError assert_unreached: Should have rejected: undefined Reached unreachable code
+Harness: the test ran to completion.
+
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 21209e72..d5f4e40 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -23741,6 +23741,10 @@
   <int value="13" label="Manage Linux sharing menu"/>
   <int value="14" label="Manage Linux sharing toast"/>
   <int value="15" label="Manage Linux sharing toast startup"/>
+  <int value="16" label="Share with Plugin VM"/>
+  <int value="17" label="Manage Plugin VM sharing menu"/>
+  <int value="18" label="Manage Plugin VM sharing toast"/>
+  <int value="19" label="Manage Plugin VM sharing toast startup"/>
 </enum>
 
 <enum name="FileManagerQuickViewWayToOpen">
@@ -32206,6 +32210,7 @@
   <int value="-1832575380" label="show-saved-copy"/>
   <int value="-1832221649" label="disable-out-of-process-pac"/>
   <int value="-1826649921" label="ContextualSuggestionsButton:disabled"/>
+  <int value="-1826309726" label="ArcCustomTabsExperiment:disabled"/>
   <int value="-1821058653" label="enable-delay-agnostic-aec"/>
   <int value="-1818947212" label="OutOfBlinkCors:disabled"/>
   <int value="-1818040592" label="InSessionPasswordChange:enabled"/>
@@ -33232,6 +33237,7 @@
   <int value="-192919826" label="ViewsSimplifiedFullscreenUI:enabled"/>
   <int value="-192389983" label="NoStatePrefetch:enabled"/>
   <int value="-191256027" label="AvoidFlashBetweenNavigation:disabled"/>
+  <int value="-189478545" label="ArcCustomTabsExperiment:enabled"/>
   <int value="-185162926" label="IncreaseInputAudioBufferSize:enabled"/>
   <int value="-184091779"
       label="OmniboxUIExperimentWhiteBackgroundOnBlur:enabled"/>
@@ -47691,6 +47697,7 @@
       label="IDC_CONTENT_CONTEXT_ACCESSIBILITY_LABELS_TOGGLE_ONCE"/>
   <int value="101" label="IDC_CONTENT_CONTEXT_ACCESSIBILITY_LABELS"/>
   <int value="102" label="IDC_SEND_TO_MY_DEVICES"/>
+  <int value="103" label="IDC_CONTENT_LINK_SEND_TAB_TO_SELF"/>
 </enum>
 
 <enum name="ReopenTabPromoStepAtDismissal">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 5badbd820..cd630a0 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -120450,7 +120450,7 @@
 </histogram>
 
 <histogram name="Sync.ModelTypeStoreCommitCount" enum="SyncModelTypes"
-    expires_after="2019-03-01">
+    expires_after="2019-07-19">
   <owner>mastiz@chromium.org</owner>
   <summary>
     Records the number of write batches committed to leveldb
diff --git a/ui/chromeos/file_manager_strings.grdp b/ui/chromeos/file_manager_strings.grdp
index 38d65a42..e191c58 100644
--- a/ui/chromeos/file_manager_strings.grdp
+++ b/ui/chromeos/file_manager_strings.grdp
@@ -543,6 +543,12 @@
   <message name="IDS_FILE_BROWSER_MANAGE_LINUX_SHARING_BUTTON_LABEL" desc="Label for menu that will take users to the settings page where they can manage which files and folders are shared with the crostini Linux container.">
     Manage Linux sharing
   </message>
+  <message name="IDS_FILE_BROWSER_SHARE_WITH_PLUGIN_VM_BUTTON_LABEL" desc="Label for menu that will share a folder with the Plugin VM.">
+    Share with Plugin VM
+  </message>
+  <message name="IDS_FILE_BROWSER_MANAGE_PLUGIN_VM_SHARING_BUTTON_LABEL" desc="Label for menu that will take users to the settings page where they can manage which files and folders are shared with the Plugin VM.">
+    Manage Plugin VM sharing
+  </message>
   <message name="IDS_FILE_BROWSER_TOGGLE_HIDDEN_FILES_COMMAND_LABEL" desc="Label for menu or button with checkmark that toggles visibility of hidden files.">
     Show hidden files
   </message>
@@ -1078,6 +1084,12 @@
   <message name="IDS_FILE_BROWSER_FOLDER_SHARED_WITH_CROSTINI_PLURAL" desc="Confirmation message shown when a user shares more than 1 folder with the crostini container.">
     <ph name="NUMBER_OF_ITEMS">$1<ex>3</ex></ph> folders shared with Linux
   </message>
+  <message name="IDS_FILE_BROWSER_FOLDER_SHARED_WITH_PLUGIN_VM" desc="Confirmation message shown when a user shares a folder with the Plugin VM.">
+    1 folder shared with Plugin VM
+  </message>
+  <message name="IDS_FILE_BROWSER_FOLDER_SHARED_WITH_PLUGIN_VM_PLURAL" desc="Confirmation message shown when a user shares more than 1 folder with the Plugin VM.">
+    <ph name="NUMBER_OF_ITEMS">$1<ex>3</ex></ph> folders shared with Plugin VM
+  </message>
 
   <message name="IDS_FILE_BROWSER_FOLDER" desc="Folder entry type">
     Folder
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_FOLDER_SHARED_WITH_PLUGIN_VM.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_FOLDER_SHARED_WITH_PLUGIN_VM.png.sha1
new file mode 100644
index 0000000..f01b08b
--- /dev/null
+++ b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_FOLDER_SHARED_WITH_PLUGIN_VM.png.sha1
@@ -0,0 +1 @@
+5d9c950adff3876f332a672cfff1e95a59ae6291
\ No newline at end of file
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_FOLDER_SHARED_WITH_PLUGIN_VM_PLURAL.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_FOLDER_SHARED_WITH_PLUGIN_VM_PLURAL.png.sha1
new file mode 100644
index 0000000..f575279
--- /dev/null
+++ b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_FOLDER_SHARED_WITH_PLUGIN_VM_PLURAL.png.sha1
@@ -0,0 +1 @@
+10f6eb2c0b3fda88e5e437aa7e1481140077f54d
\ No newline at end of file
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_MANAGE_PLUGIN_VM_SHARING_BUTTON_LABEL.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_MANAGE_PLUGIN_VM_SHARING_BUTTON_LABEL.png.sha1
new file mode 100644
index 0000000..c1361d4
--- /dev/null
+++ b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_MANAGE_PLUGIN_VM_SHARING_BUTTON_LABEL.png.sha1
@@ -0,0 +1 @@
+265d61c47b5336e378e6ad256999db2d1eb08f36
\ No newline at end of file
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_SHARE_WITH_PLUGIN_VM_BUTTON_LABEL.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_SHARE_WITH_PLUGIN_VM_BUTTON_LABEL.png.sha1
new file mode 100644
index 0000000..675f16e
--- /dev/null
+++ b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_SHARE_WITH_PLUGIN_VM_BUTTON_LABEL.png.sha1
@@ -0,0 +1 @@
+48dfca6f7bfe238339d951318b922c6080c89348
\ No newline at end of file
diff --git a/ui/file_manager/externs/background/crostini.js b/ui/file_manager/externs/background/crostini.js
index d1bf7c6..51da35f 100644
--- a/ui/file_manager/externs/background/crostini.js
+++ b/ui/file_manager/externs/background/crostini.js
@@ -21,16 +21,18 @@
 Crostini.prototype.listen = function() {};
 
 /**
- * Set from feature 'crostini-files'.
+ * Set whether the specified VM is enabled.
+ * @param {string} vmName
  * @param {boolean} enabled
  */
-Crostini.prototype.setEnabled = function(enabled) {};
+Crostini.prototype.setEnabled = function(vmName, enabled) {};
 
 /**
- * Returns true if crostini is enabled.
+ * Returns true if the specified VM is enabled.
+ * @param {string} vmName
  * @return {boolean}
  */
-Crostini.prototype.isEnabled = function() {};
+Crostini.prototype.isEnabled = function(vmName) {};
 
 /**
  * Registers an entry as a shared path for the specified VM.
diff --git a/ui/file_manager/file_manager/background/js/crostini.js b/ui/file_manager/file_manager/background/js/crostini.js
index d86877ea2..0f1acb2 100644
--- a/ui/file_manager/file_manager/background/js/crostini.js
+++ b/ui/file_manager/file_manager/background/js/crostini.js
@@ -10,10 +10,10 @@
  */
 function CrostiniImpl() {
   /**
-   * True if crostini is enabled.
-   * @private {boolean}
+   * True if VM is enabled.
+   * @private {Object<boolean>}
    */
-  this.enabled_ = false;
+  this.enabled_ = {};
 
   /**
    * Maintains a list of paths shared with VMs.
@@ -30,6 +30,12 @@
 CrostiniImpl.DEFAULT_VM = 'termina';
 
 /**
+ * Plugin VM 'PluginVm'.
+ * @const
+ */
+CrostiniImpl.PLUGIN_VM = 'PluginVm';
+
+/**
  * Keep in sync with histograms.xml:FileBrowserCrostiniSharedPathsDepth
  * histogram_suffix.
  * @type {!Map<VolumeManagerCommon.RootType, string>}
@@ -80,19 +86,21 @@
 };
 
 /**
- * Set from feature 'crostini-files'.
+ * Set whether the specified VM is enabled.
+ * @param {string} vmName
  * @param {boolean} enabled
  */
-CrostiniImpl.prototype.setEnabled = function(enabled) {
-  this.enabled_ = enabled;
+CrostiniImpl.prototype.setEnabled = function(vmName, enabled) {
+  this.enabled_[vmName] = enabled;
 };
 
 /**
  * Returns true if crostini is enabled.
+ * @param {string} vmName
  * @return {boolean}
  */
-CrostiniImpl.prototype.isEnabled = function() {
-  return this.enabled_;
+CrostiniImpl.prototype.isEnabled = function(vmName) {
+  return this.enabled_[vmName];
 };
 
 /**
@@ -216,7 +224,7 @@
  * @param {boolean} persist If path is to be persisted.
  */
 CrostiniImpl.prototype.canSharePath = function(vmName, entry, persist) {
-  if (vmName === CrostiniImpl.DEFAULT_VM && !this.enabled_) {
+  if (!this.enabled_[vmName]) {
     return false;
   }
 
diff --git a/ui/file_manager/file_manager/background/js/crostini_unittest.js b/ui/file_manager/file_manager/background/js/crostini_unittest.js
index 30bc0f6..fe94175 100644
--- a/ui/file_manager/file_manager/background/js/crostini_unittest.js
+++ b/ui/file_manager/file_manager/background/js/crostini_unittest.js
@@ -137,7 +137,7 @@
  * Tests disallowed and allowed shared paths.
  */
 function testCanSharePath() {
-  crostini.setEnabled(true);
+  crostini.setEnabled('vm', true);
 
   const mockFileSystem = new MockFileSystem('test');
   const root = new MockDirectoryEntry(mockFileSystem, '/');
diff --git a/ui/file_manager/file_manager/foreground/js/constants.js b/ui/file_manager/file_manager/foreground/js/constants.js
index aea304b..9c45940 100644
--- a/ui/file_manager/file_manager/foreground/js/constants.js
+++ b/ui/file_manager/file_manager/foreground/js/constants.js
@@ -83,3 +83,9 @@
  * @const
  */
 constants.DEFAULT_CROSTINI_VM = 'termina';
+
+/**
+ * Name of the Plugin VM.
+ * @const
+ */
+constants.PLUGIN_VM = 'PluginVm';
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager.js b/ui/file_manager/file_manager/foreground/js/file_manager.js
index 11108ea..e8d18ac6 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager.js
@@ -1149,7 +1149,12 @@
         assert(this.directoryModel_));
 
     this.ui_.initDirectoryTree(directoryTree);
-    this.setCrostiniEnabled_(loadTimeData.getBoolean('CROSTINI_ENABLED'));
+    this.crostini_.setEnabled(
+        constants.DEFAULT_CROSTINI_VM,
+        loadTimeData.getBoolean('CROSTINI_ENABLED'));
+    this.crostini_.setEnabled(
+        constants.PLUGIN_VM, loadTimeData.getBoolean('PLUGIN_VM_ENABLED'));
+    this.setupCrostini_();
     chrome.fileManagerPrivate.onCrostiniChanged.addListener(
         this.onCrostiniChanged_.bind(this));
 
@@ -1160,14 +1165,13 @@
   };
 
   /**
-   * Check if crostini is enabled to create linuxFilesItem.
-   * @param {boolean} enabled
+   * Setup crostini 'Linux files'.
    * @private
    */
-  FileManager.prototype.setCrostiniEnabled_ = function(enabled) {
-    this.crostini_.setEnabled(enabled);
+  FileManager.prototype.setupCrostini_ = function() {
     // Setup Linux files fake root.
-    this.directoryTree.dataModel.linuxFilesItem = enabled ?
+    this.directoryTree.dataModel.linuxFilesItem =
+        this.crostini_.isEnabled(constants.DEFAULT_CROSTINI_VM) ?
         new NavigationModelFakeItem(
             str('LINUX_FILES_ROOT_LABEL'), NavigationModelItemType.CROSTINI,
             new FakeEntry(
@@ -1177,37 +1181,61 @@
     // Redraw the tree to ensure 'Linux files' is added/removed.
     this.directoryTree.redraw(false);
 
-    if (!enabled) {
-      return;
-    }
-
     // Load any existing shared paths.
     // Only observe firstForSession when using full-page FilesApp.
     // I.e., don't show toast in a dialog.
-    chrome.fileManagerPrivate.getCrostiniSharedPaths(
-        this.dialogType === DialogType.FULL_PAGE, constants.DEFAULT_CROSTINI_VM,
-        (entries, firstForSession) => {
-          for (let i = 0; i < entries.length; i++) {
-            this.crostini_.registerSharedPath(
-                constants.DEFAULT_CROSTINI_VM, entries[i]);
-          }
-          // Show 'Manage sharing' toast the first time FilesApp is opened.
-          if (firstForSession && entries.length >= 1) {
-            this.ui_.toast.show(
-                entries.length == 1 ?
-                    str('FOLDER_SHARED_WITH_CROSTINI') :
-                    strf('FOLDER_SHARED_WITH_CROSTINI_PLURAL', entries.length),
-                {
-                  text: str('MANAGE_LINUX_SHARING_BUTTON_LABEL'),
-                  callback: () => {
-                    chrome.fileManagerPrivate.openSettingsSubpage(
-                        'crostini/sharedPaths');
-                    CommandHandler.recordMenuItemSelected(
-                        CommandHandler.MenuCommandsForUMA
-                            .MANAGE_LINUX_SHARING_TOAST_STARTUP);
-                  }
-                });
-          }
+    let showToast = false;
+    const getSharedPaths = (vmName) => {
+      return new Promise(resolve => {
+        if (!this.crostini_.isEnabled(vmName)) {
+          return resolve(0);
+        }
+        chrome.fileManagerPrivate.getCrostiniSharedPaths(
+            this.dialogType === DialogType.FULL_PAGE, vmName,
+            (entries, firstForSession) => {
+              showToast = showToast || firstForSession;
+              for (let i = 0; i < entries.length; i++) {
+                this.crostini_.registerSharedPath(vmName, entries[i]);
+              }
+              resolve(entries.length);
+            });
+      });
+    };
+
+    const toast = (count, msgSingle, msgPlural, action, subPage, umaItem) => {
+      if (!showToast || count == 0) {
+        return;
+      }
+      this.ui_.toast.show(
+          count == 1 ? str(msgSingle) : strf(msgPlural, count), {
+            text: str(action),
+            callback: () => {
+              chrome.fileManagerPrivate.openSettingsSubpage(subPage);
+              CommandHandler.recordMenuItemSelected(umaItem);
+            }
+          });
+    };
+
+    Promise
+        .all([
+          getSharedPaths(constants.DEFAULT_CROSTINI_VM),
+          getSharedPaths(constants.PLUGIN_VM)
+        ])
+        .then(([crostiniShareCount, pluginVmShareCount]) => {
+          toast(
+              crostiniShareCount, 'FOLDER_SHARED_WITH_CROSTINI',
+              'FOLDER_SHARED_WITH_CROSTINI_PLURAL',
+              'MANAGE_LINUX_SHARING_BUTTON_LABEL', 'crostini/sharedPaths',
+              CommandHandler.MenuCommandsForUMA
+                  .MANAGE_LINUX_SHARING_TOAST_STARTUP);
+          // TODO(crbug.com/949356): UX to provide guidance for what to do
+          // when we have shared paths with both Linux and Plugin VM.
+          toast(
+              pluginVmShareCount, 'FOLDER_SHARED_WITH_PLUGIN_VM',
+              'FOLDER_SHARED_WITH_PLUGIN_VM_PLURAL',
+              'MANAGE_PLUGIN_VM_SHARING_BUTTON_LABEL', 'pluginVm/sharedPaths',
+              CommandHandler.MenuCommandsForUMA
+                  .MANAGE_PLUGIN_VM_SHARING_TOAST_STARTUP);
         });
   };
 
@@ -1217,9 +1245,11 @@
    */
   FileManager.prototype.onCrostiniChanged_ = function(event) {
     if (event.eventType === 'enable') {
-      this.setCrostiniEnabled_(true);
+      this.crostini_.setEnabled(event.vmName, true);
+      this.setupCrostini_();
     } else if (event.eventType === 'disable') {
-      this.setCrostiniEnabled_(false);
+      this.crostini_.setEnabled(event.vmName, false);
+      this.setupCrostini_();
     }
   };
 
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
index fe52060..e635015 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
@@ -453,6 +453,11 @@
   MANAGE_LINUX_SHARING: 'manage-linux-sharing',
   MANAGE_LINUX_SHARING_TOAST: 'manage-linux-sharing-toast',
   MANAGE_LINUX_SHARING_TOAST_STARTUP: 'manage-linux-sharing-toast-startup',
+  SHARE_WITH_PLUGIN_VM: 'share-with-plugin-vm',
+  MANAGE_PLUGIN_VM_SHARING: 'manage-plugin-vm-sharing',
+  MANAGE_PLUGIN_VM_SHARING_TOAST: 'manage-plugin-vm-sharing-toast',
+  MANAGE_PLUGIN_VM_SHARING_TOAST_STARTUP:
+      'manage-plugin-vm-sharing-toast-startup',
 };
 
 /**
@@ -481,6 +486,10 @@
   CommandHandler.MenuCommandsForUMA.MANAGE_LINUX_SHARING,
   CommandHandler.MenuCommandsForUMA.MANAGE_LINUX_SHARING_TOAST,
   CommandHandler.MenuCommandsForUMA.MANAGE_LINUX_SHARING_TOAST_STARTUP,
+  CommandHandler.MenuCommandsForUMA.SHARE_WITH_PLUGIN_VM,
+  CommandHandler.MenuCommandsForUMA.MANAGE_PLUGIN_VM_SHARING,
+  CommandHandler.MenuCommandsForUMA.MANAGE_PLUGIN_VM_SHARING_TOAST,
+  CommandHandler.MenuCommandsForUMA.MANAGE_PLUGIN_VM_SHARING_TOAST_STARTUP,
 ];
 console.assert(
     Object.keys(CommandHandler.MenuCommandsForUMA).length ===
@@ -1818,7 +1827,7 @@
 
 
 /**
- * Shares the selected (single only) directory with the crostini container.
+ * Shares the selected (single only) directory with the default crostini VM.
  * @type {Command}
  */
 CommandHandler.COMMANDS_['share-with-linux'] = /** @type {Command} */ ({
@@ -1890,7 +1899,7 @@
    * @param {!CommandHandlerDeps} fileManager CommandHandlerDeps to use.
    */
   canExecute: function(event, fileManager) {
-    // Must be single directory subfolder of Downloads not already shared.
+    // Must be single directory not already shared.
     const entries = CommandUtil.getCommandEntries(event.target);
     event.canExecute = entries.length === 1 && entries[0].isDirectory &&
         !fileManager.crostini.isPathShared(
@@ -1902,6 +1911,88 @@
 });
 
 /**
+ * Shares the selected (single only) directory with the Plugin VM.
+ * @type {Command}
+ */
+CommandHandler.COMMANDS_['share-with-plugin-vm'] = /** @type {Command} */ ({
+  /**
+   * @param {!Event} event Command event.
+   * @param {!CommandHandlerDeps} fileManager CommandHandlerDeps to use.
+   */
+  execute: function(event, fileManager) {
+    const entry = CommandUtil.getCommandEntry(event.target);
+    if (!entry || !entry.isDirectory) {
+      return;
+    }
+    const dir = /** @type {!DirectoryEntry} */ (entry);
+    const info = fileManager.volumeManager.getLocationInfo(dir);
+    if (!info) {
+      return;
+    }
+    function share() {
+      // Always persist shares via right-click > Share with PluginVM.
+      chrome.fileManagerPrivate.sharePathsWithCrostini(
+          constants.PLUGIN_VM, [dir], true /* persist */, () => {
+            if (chrome.runtime.lastError) {
+              console.error(
+                  'Error sharing with Plugin VM: ' +
+                  chrome.runtime.lastError.message);
+            }
+          });
+      // Register the share and show the 'Manage PluginVM sharing' toast
+      // immediately, since the container may take 10s or more to start.
+      fileManager.crostini.registerSharedPath(constants.PLUGIN_VM, dir);
+      fileManager.ui.toast.show(str('FOLDER_SHARED_WITH_CROSTINI'), {
+        text: str('MANAGE_LINUX_SHARING_BUTTON_LABEL'),
+        callback: () => {
+          chrome.fileManagerPrivate.openSettingsSubpage('pluginvm/sharedPaths');
+          CommandHandler.recordMenuItemSelected(
+              CommandHandler.MenuCommandsForUMA.MANAGE_PLUGIN_VM_SHARING_TOAST);
+        }
+      });
+    }
+    // Show a confirmation dialog if we are sharing the root of a volume.
+    // Non-Drive volume roots are always '/'.
+    if (dir.fullPath == '/') {
+      fileManager.ui_.confirmDialog.showHtml(
+          strf('SHARE_ROOT_FOLDER_WITH_CROSTINI_TITLE'),
+          strf('SHARE_ROOT_FOLDER_WITH_CROSTINI', info.volumeInfo.label), share,
+          () => {});
+    } else if (
+        info.isRootEntry &&
+        (info.rootType == VolumeManagerCommon.RootType.DRIVE ||
+         info.rootType == VolumeManagerCommon.RootType.COMPUTERS_GRAND_ROOT ||
+         info.rootType ==
+             VolumeManagerCommon.RootType.SHARED_DRIVES_GRAND_ROOT)) {
+      // Only show the dialog for My Drive, Shared Drives Grand Root and
+      // Computers Grand Root.  Do not show for roots of a single Shared Drive
+      // or Computer.
+      fileManager.ui_.confirmDialog.showHtml(
+          strf('SHARE_ROOT_FOLDER_WITH_CROSTINI_TITLE'),
+          strf('SHARE_ROOT_FOLDER_WITH_CROSTINI_DRIVE'), share, () => {});
+    } else {
+      // This is not a root, share it without confirmation dialog.
+      share();
+    }
+    CommandHandler.recordMenuItemSelected(
+        CommandHandler.MenuCommandsForUMA.SHARE_WITH_PLUGIN_VM);
+  },
+  /**
+   * @param {!Event} event Command event.
+   * @param {!CommandHandlerDeps} fileManager CommandHandlerDeps to use.
+   */
+  canExecute: function(event, fileManager) {
+    // Must be single directory subfolder of Downloads not already shared.
+    const entries = CommandUtil.getCommandEntries(event.target);
+    event.canExecute = entries.length === 1 && entries[0].isDirectory &&
+        !fileManager.crostini.isPathShared(constants.PLUGIN_VM, entries[0]) &&
+        fileManager.crostini.canSharePath(
+            constants.PLUGIN_VM, entries[0], true /* persist */);
+    event.command.setHidden(!event.canExecute);
+  }
+});
+
+/**
  * Link to settings page from gear menu.  Allows the user to manage files and
  * folders shared with the crostini container.
  * @type {Command}
@@ -1922,7 +2013,8 @@
        * @param {!CommandHandlerDeps} fileManager CommandHandlerDeps to use.
        */
       canExecute: function(event, fileManager) {
-        event.canExecute = fileManager.crostini.isEnabled();
+        event.canExecute =
+            fileManager.crostini.isEnabled(constants.DEFAULT_CROSTINI_VM);
         event.command.setHidden(!event.canExecute);
       }
     });
@@ -1956,6 +2048,59 @@
 });
 
 /**
+ * Link to settings page from gear menu.  Allows the user to manage files and
+ * folders shared with the Plugin VM.
+ * @type {Command}
+ */
+CommandHandler.COMMANDS_['manage-plugin-vm-sharing-gear'] =
+    /** @type {Command} */ ({
+      /**
+       * @param {!Event} event Command event.
+       * @param {!CommandHandlerDeps} fileManager CommandHandlerDeps to use.
+       */
+      execute: function(event, fileManager) {
+        chrome.fileManagerPrivate.openSettingsSubpage('pluginvm/sharedPaths');
+        CommandHandler.recordMenuItemSelected(
+            CommandHandler.MenuCommandsForUMA.MANAGE_PLUGIN_VM_SHARING);
+      },
+      /**
+       * @param {!Event} event Command event.
+       * @param {!CommandHandlerDeps} fileManager CommandHandlerDeps to use.
+       */
+      canExecute: function(event, fileManager) {
+        event.canExecute = fileManager.crostini.isEnabled(constants.PLUGIN_VM);
+        event.command.setHidden(!event.canExecute);
+      }
+    });
+
+/**
+ * Link to settings page from file context menus (not gear menu).  Allows
+ * the user to manage files and folders shared with the Plugin VM.
+ * @type {Command}
+ */
+CommandHandler.COMMANDS_['manage-plugin-vm-sharing'] = /** @type {Command} */ ({
+  /**
+   * @param {!Event} event Command event.
+   * @param {!CommandHandlerDeps} fileManager CommandHandlerDeps to use.
+   */
+  execute: function(event, fileManager) {
+    chrome.fileManagerPrivate.openSettingsSubpage('pluginvm/sharedPaths');
+    CommandHandler.recordMenuItemSelected(
+        CommandHandler.MenuCommandsForUMA.MANAGE_PLUGIN_VM_SHARING);
+  },
+  /**
+   * @param {!Event} event Command event.
+   * @param {!CommandHandlerDeps} fileManager CommandHandlerDeps to use.
+   */
+  canExecute: function(event, fileManager) {
+    const entries = CommandUtil.getCommandEntries(event.target);
+    event.canExecute = entries.length === 1 && entries[0].isDirectory &&
+        fileManager.crostini.isPathShared(constants.PLUGIN_VM, entries[0]);
+    event.command.setHidden(!event.canExecute);
+  }
+});
+
+/**
  * Creates a shortcut of the selected folder (single only).
  * @type {Command}
  */
diff --git a/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js b/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js
index b4dd5c36..8fada5da 100644
--- a/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js
@@ -576,8 +576,8 @@
 
   const crostini = createCrostiniForTest();
   crostini.init(volumeManagerDownloads);
-  crostini.setEnabled(true);
-  crostini.registerSharedPath('vm', sharedDir);
+  crostini.setEnabled('termina', true);
+  crostini.registerSharedPath('termina', sharedDir);
 
   const notShared1 = new MockFileEntry(mockFsDownloads, '/notShared/file1');
   const notShared2 = new MockFileEntry(mockFsDownloads, '/notShared/file2');
@@ -627,12 +627,12 @@
 
   expect('No entries', [], true, '', '');
 
-  crostini.setEnabled(false);
+  crostini.setEnabled('termina', false);
   expect(
       'Single entry, crostini-files not enabled', [notShared1], false,
       'UNABLE_TO_OPEN_CROSTINI_TITLE', 'UNABLE_TO_OPEN_CROSTINI');
 
-  crostini.setEnabled(true);
+  crostini.setEnabled('termina', true);
 
   expect('Single entry, not shared', [notShared1], true, '', '');
 
@@ -642,7 +642,7 @@
       '2 entries, not shared, same dir', [notShared1, notShared2], true, '',
       '');
   // Non-persistent shares should not be registered.
-  assertFalse(crostini.isPathShared('vm', notShared1));
+  assertFalse(crostini.isPathShared('termina', notShared1));
 
   expect(
       '2 entries, not shared, different dir', [notShared1, otherNotShared],
diff --git a/ui/file_manager/file_manager/main.html b/ui/file_manager/file_manager/main.html
index aa8ee5b..4f66f24f 100644
--- a/ui/file_manager/file_manager/main.html
+++ b/ui/file_manager/file_manager/main.html
@@ -173,6 +173,9 @@
       <command id="share-with-linux" label="$i18n{SHARE_WITH_LINUX_BUTTON_LABEL}" disabled hidden>
       <command id="manage-linux-sharing" label="$i18n{MANAGE_LINUX_SHARING_BUTTON_LABEL}" disabled hidden>
       <command id="manage-linux-sharing-gear" label="$i18n{MANAGE_LINUX_SHARING_BUTTON_LABEL}" disabled hidden>
+      <command id="share-with-plugin-vm" label="$i18n{SHARE_WITH_PLUGIN_VM_BUTTON_LABEL}" disabled hidden>
+      <command id="manage-plugin-vm-sharing" label="$i18n{MANAGE_PLUGIN_VM_SHARING_BUTTON_LABEL}" disabled hidden>
+      <command id="manage-plugin-vm-sharing-gear" label="$i18n{MANAGE_PLUGIN_VM_SHARING_BUTTON_LABEL}" disabled hidden>
 
       <command id="zoom-in" shortcut="=|Ctrl">
       <command id="zoom-out" shortcut="-|Ctrl">
@@ -218,6 +221,8 @@
       <cr-menu-item command="#zip-selection"></cr-menu-item>
       <cr-menu-item command="#share-with-linux"></cr-menu-item>
       <cr-menu-item command="#manage-linux-sharing"></cr-menu-item>
+      <cr-menu-item command="#share-with-plugin-vm"></cr-menu-item>
+      <cr-menu-item command="#manage-plugin-vm-sharing"></cr-menu-item>
       <cr-menu-item command="#set-wallpaper"></cr-menu-item>
       <hr visibleif="saveas-file full-page" class="hide-on-toolbar">
       <cr-menu-item command="#new-folder" visibleif="saveas-file full-page"
@@ -233,6 +238,8 @@
       <cr-menu-item command="#remove-folder-shortcut"></cr-menu-item>
       <cr-menu-item command="#share-with-linux"></cr-menu-item>
       <cr-menu-item command="#manage-linux-sharing"></cr-menu-item>
+      <cr-menu-item command="#share-with-plugin-vm"></cr-menu-item>
+      <cr-menu-item command="#manage-plugin-vm-sharing"></cr-menu-item>
     </cr-menu>
 
     <cr-menu id="directory-tree-context-menu" class="chrome-menu files-menu"
@@ -242,6 +249,8 @@
       <cr-menu-item command="#paste-into-folder" visibleif="full-page"></cr-menu-item>
       <cr-menu-item command="#share-with-linux"></cr-menu-item>
       <cr-menu-item command="#manage-linux-sharing"></cr-menu-item>
+      <cr-menu-item command="#share-with-plugin-vm"></cr-menu-item>
+      <cr-menu-item command="#manage-plugin-vm-sharing"></cr-menu-item>
       <hr visibleif="full-page">
       <cr-menu-item command="#format"></cr-menu-item>
       <cr-menu-item command="#rename"></cr-menu-item>
@@ -281,6 +290,8 @@
                     command="#toggle-hidden-android-folders"></cr-menu-item>
       <cr-menu-item id="gear-menu-manage-linux-sharing"
                     command="#manage-linux-sharing-gear"></cr-menu-item>
+      <cr-menu-item id="gear-menu-manage-plugin-vm-sharing"
+                    command="#manage-plugin-vm-sharing-gear"></cr-menu-item>
       <cr-menu-item id="gear-menu-drive-sync-settings"
                     command="#drive-sync-settings"></cr-menu-item>
       <hr id="help-separator">
@@ -316,6 +327,8 @@
       <cr-menu-item command="#share"></cr-menu-item>
       <cr-menu-item command="#share-with-linux"></cr-menu-item>
       <cr-menu-item command="#manage-linux-sharing"></cr-menu-item>
+      <cr-menu-item command="#share-with-plugin-vm"></cr-menu-item>
+      <cr-menu-item command="#manage-plugin-vm-sharing"></cr-menu-item>
       <hr id="drive-share-separator">
       <hr id="more-actions-separator">
       <cr-menu-item command="#show-submenu"
diff --git a/ui/file_manager/file_manager/test/crostini_mount.js b/ui/file_manager/file_manager/test/crostini_mount.js
index 7d263c9..60ee027 100644
--- a/ui/file_manager/file_manager/test/crostini_mount.js
+++ b/ui/file_manager/file_manager/test/crostini_mount.js
@@ -8,12 +8,12 @@
   const fakeRoot = '#directory-tree [root-type-icon="crostini"]';
   await test.setupAndWaitUntilReady();
   chrome.fileManagerPrivate.onCrostiniChanged.dispatchEvent(
-      {eventType: 'disable'});
+      {eventType: 'disable', vmName: 'termina'});
   await test.waitForElementLost(fakeRoot);
 
   // Reset crostini back to default enabled=true.
   chrome.fileManagerPrivate.onCrostiniChanged.dispatchEvent(
-      {eventType: 'enable'});
+      {eventType: 'enable', vmName: 'termina'});
   await test.waitForElement(fakeRoot);
   done();
 };
diff --git a/ui/file_manager/file_manager/test/crostini_share.js b/ui/file_manager/file_manager/test/crostini_share.js
index 0e98514..688fb1d 100644
--- a/ui/file_manager/file_manager/test/crostini_share.js
+++ b/ui/file_manager/file_manager/test/crostini_share.js
@@ -2,23 +2,39 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-const crostiniShare = {};
+const shareBase = {
+  // Params for 'Share with Linux'.
+  vmNameTermina: 'termina',
+  vmNameSelectorLinux: 'linux',
+  enumUmaShareWithLinux: 12,
+  enumUmaManageLinuxSharing: 13,
+  // Params for 'Share with Plugin VM'.
+  vmNamePluginVm: 'PluginVm',
+  vmNameSelectorPluginVm: 'plugin-vm',
+  enumUmaShareWithPluginVm: 16,
+  enumUmaManagePluginVmSharing: 17,
+};
 
-crostiniShare.testSharePathsCrostiniSuccess = (done) => {
-  const menuNoShareWithLinux = '#file-context-menu:not([hidden]) ' +
-      '[command="#share-with-linux"][hidden][disabled="disabled"]';
-  const menuShareWithLinux = '#file-context-menu:not([hidden]) ' +
-      '[command="#share-with-linux"]:not([hidden]):not([disabled])';
-  const menuNoManageLinuxSharing = '#file-context-menu:not([hidden]) ' +
-      '[command="#manage-linux-sharing"][hidden][disabled="disabled"]';
-  const menuManageLinuxSharing = '#file-context-menu:not([hidden]) ' +
-      '[command="#manage-linux-sharing"]:not([hidden]):not([disabled])';
-  const shareWithLinux = '#file-context-menu [command="#share-with-linux"]';
-  const menuShareWithLinuxDirTree =
-      '#directory-tree-context-menu:not([hidden]) ' +
-      '[command="#share-with-linux"]:not([hidden]):not([disabled])';
-  const shareWithLinuxDirTree =
-      '#directory-tree-context-menu [command="#share-with-linux"]';
+const crostiniShare = {};
+const pluginVmShare = {};
+
+shareBase.testSharePathsSuccess =
+    async (vmName, vmNameSelector, enumUma, done) => {
+  const share = 'share-with-' + vmNameSelector;
+  const manage = 'manage-' + vmNameSelector + '-sharing';
+  const menuNoShareWith = '#file-context-menu:not([hidden]) ' +
+      '[command="#' + share + '"][hidden][disabled="disabled"]';
+  const menuShareWith = '#file-context-menu:not([hidden]) ' +
+      '[command="#' + share + '"]:not([hidden]):not([disabled])';
+  const menuNoManageSharing = '#file-context-menu:not([hidden]) ' +
+      '[command="#' + manage + '"][hidden][disabled="disabled"]';
+  const menuManageSharing = '#file-context-menu:not([hidden]) ' +
+      '[command="#' + manage + '"]:not([hidden]):not([disabled])';
+  const shareWith = '#file-context-menu [command="#' + share + '"]';
+  const menuShareWithDirTree = '#directory-tree-context-menu:not([hidden]) ' +
+      '[command="#' + share + '"]:not([hidden]):not([disabled])';
+  const shareWithDirTree =
+      '#directory-tree-context-menu [command="#' + share + '"]';
   const photos = '#file-list [file-name="photos"]';
   const downloadsDirTree = '#directory-tree [volume-type-icon="downloads"]';
   const oldSharePaths = chrome.fileManagerPrivate.sharePathsWithCrostini;
@@ -41,280 +57,274 @@
   chrome.metricsPrivate.smallCounts_ = [];
   chrome.metricsPrivate.values_ = [];
 
-  test.setupAndWaitUntilReady()
-      .then(() => {
-        // Right-click 'photos' directory.
-        // Check 'Share with Linux' is shown in menu.
-        assertTrue(test.fakeMouseRightClick(photos), 'right-click photos');
-        return test.waitForElement(menuShareWithLinux);
-      })
-      .then(() => {
-        // Check 'Manage Linux sharing' is not shown in menu.
-        assertTrue(!!document.querySelector(menuNoManageLinuxSharing));
-        // Click on 'Share with Linux'.
-        assertTrue(test.fakeMouseClick(shareWithLinux, 'Share with Linux'));
-        // Check sharePathsWithCrostini is called.
-        return test.repeatUntil(() => {
-          return sharePathsCalled || test.pending('wait for sharePathsCalled');
-        });
-      })
-      .then(() => {
-        // Check toast is shown.
-        return test.repeatUntil(() => {
-          return document.querySelector('#toast').shadowRoot.querySelector(
-                     '#container:not([hidden])') ||
-              test.pending('wait for toast');
-        });
-      })
-      .then(() => {
-        // Right-click 'photos' directory.
-        // Check 'Share with Linux' is not shown in menu.
-        assertTrue(test.fakeMouseRightClick(photos), 'right-click photos');
-        return test.waitForElement(menuNoShareWithLinux);
-      })
-      .then(() => {
-        // Check 'Manage Linux sharing' is shown in menu.
-        assertTrue(!!document.querySelector(menuManageLinuxSharing));
+  await test.setupAndWaitUntilReady();
+  // Right-click 'photos' directory.
+  // Check 'Share with <VM>' is shown in menu.
+  assertTrue(test.fakeMouseRightClick(photos), 'right-click photos');
+  await test.waitForElement(menuShareWith);
 
-        // Share should persist when right-click > Share with Linux.
-        assertTrue(sharePathsPersist);
-        // Validate UMAs.
-        assertEquals(1, chrome.metricsPrivate.smallCounts_.length);
-        assertArrayEquals(
-            ['FileBrowser.CrostiniSharedPaths.Depth.Downloads', 1],
-            chrome.metricsPrivate.smallCounts_[0]);
-        const lastEnumUma = chrome.metricsPrivate.values_.pop();
-        assertEquals('FileBrowser.MenuItemSelected', lastEnumUma[0].metricName);
-        assertEquals(12 /* Share with Linux */, lastEnumUma[1]);
-      })
-      .then(() => {
-        // Dispatch unshare event which is normally initiated when the user
-        // manages shared paths in the settings page.
-        const photos = mockVolumeManager
-                           .getCurrentProfileVolumeInfo(
-                               VolumeManagerCommon.VolumeType.DOWNLOADS)
-                           .fileSystem.entries['/photos'];
-        chrome.fileManagerPrivate.onCrostiniChanged.dispatchEvent(
-            {eventType: 'unshare', vmName: 'termina', entries: [photos]});
-        // Check unregisterSharedPath is called.
-        return test.repeatUntil(() => {
-          return unregisterCalled || test.pending('wait for unregisterCalled');
-        });
-      })
-      .then(() => {
-        // Right-click 'photos' directory.
-        // Check 'Share with Linux' is shown in menu.
-        assertTrue(test.fakeMouseRightClick(photos), 'right-click photos');
-        return test.waitForElement(menuShareWithLinux);
-      })
-      .then(() => {
-        // Verify dialog is shown for Downloads root.
-        // Check 'Share with Linux' is shown in menu.
-        assertTrue(
-            test.fakeMouseRightClick(downloadsDirTree),
-            'right-click downloads');
-        return test.waitForElement(menuShareWithLinuxDirTree);
-      })
-      .then(() => {
-        // Click 'Share with Linux', verify dialog.
-        assertTrue(
-            test.fakeMouseClick(shareWithLinuxDirTree, 'Share with Linux'));
-        return test.waitForElement('.cr-dialog-container.shown');
-      })
-      .then(() => {
-        // Click Cancel button to close.
-        assertTrue(test.fakeMouseClick('button.cr-dialog-cancel'));
-        return test.waitForElementLost('.cr-dialog-container');
-      })
-      .then(() => {
-        // Restore fmp.*.
-        chrome.fileManagerPrivate.sharePathsWithCrostini = oldSharePaths;
-        // Restore Crostini.unregisterSharedPath.
-        fileManager.crostini.unregisterSharedPath = oldCrostiniUnregister;
-        done();
-      });
+  // Check 'Manage <VM> sharing' is not shown in menu.
+  assertTrue(!!document.querySelector(menuNoManageSharing));
+  // Click on 'Share with <VM>'.
+  assertTrue(test.fakeMouseClick(shareWith, 'Share with <VM>'));
+  // Check sharePathsWithCrostini is called.
+  await test.repeatUntil(() => {
+    return sharePathsCalled || test.pending('wait for sharePathsCalled');
+  });
+
+  // Check toast is shown.
+  await test.repeatUntil(() => {
+    return document.querySelector('#toast').shadowRoot.querySelector(
+               '#container:not([hidden])') ||
+        test.pending('wait for toast');
+  });
+
+  // Right-click 'photos' directory.
+  // Check 'Share with <VM>' is not shown in menu.
+  assertTrue(test.fakeMouseRightClick(photos), 'right-click photos');
+  await test.waitForElement(menuNoShareWith);
+
+  // Check 'Manage <VM> sharing' is shown in menu.
+  assertTrue(!!document.querySelector(menuManageSharing));
+
+  // Share should persist when right-click > Share with <VM>.
+  assertTrue(sharePathsPersist);
+  // Validate UMAs.
+  assertEquals(1, chrome.metricsPrivate.smallCounts_.length);
+  assertArrayEquals(
+      ['FileBrowser.CrostiniSharedPaths.Depth.Downloads', 1],
+      chrome.metricsPrivate.smallCounts_[0]);
+  const lastEnumUma = chrome.metricsPrivate.values_.pop();
+  assertEquals('FileBrowser.MenuItemSelected', lastEnumUma[0].metricName);
+  assertEquals(enumUma, lastEnumUma[1]);
+
+  // Dispatch unshare event which is normally initiated when the user
+  // manages shared paths in the settings page.
+  const photosEntries =
+      mockVolumeManager
+          .getCurrentProfileVolumeInfo(VolumeManagerCommon.VolumeType.DOWNLOADS)
+          .fileSystem.entries['/photos'];
+  chrome.fileManagerPrivate.onCrostiniChanged.dispatchEvent(
+      {eventType: 'unshare', vmName: vmName, entries: [photosEntries]});
+  // Check unregisterSharedPath is called.
+  await test.repeatUntil(() => {
+    return unregisterCalled || test.pending('wait for unregisterCalled');
+  });
+
+  // Right-click 'photos' directory.
+  // Check 'Share with <VM>' is shown in menu.
+  assertTrue(test.fakeMouseRightClick(photos), 'right-click photos');
+  await test.waitForElement(menuShareWith);
+
+  // Verify dialog is shown for Downloads root.
+  // Check 'Share with <VM>' is shown in menu.
+  assertTrue(
+      test.fakeMouseRightClick(downloadsDirTree), 'right-click downloads');
+  await test.waitForElement(menuShareWithDirTree);
+
+  // Click 'Share with <VM>', verify dialog.
+  assertTrue(test.fakeMouseClick(shareWithDirTree, 'Share with <VM>'));
+  await test.waitForElement('.cr-dialog-container.shown');
+
+  // Click Cancel button to close.
+  assertTrue(test.fakeMouseClick('button.cr-dialog-cancel'));
+  await test.waitForElementLost('.cr-dialog-container');
+
+  // Restore fmp.*.
+  chrome.fileManagerPrivate.sharePathsWithCrostini = oldSharePaths;
+  // Restore Crostini.unregisterSharedPath.
+  fileManager.crostini.unregisterSharedPath = oldCrostiniUnregister;
+  done();
 };
 
-// Verify right-click menu with 'Share with Linux' is not shown for:
+crostiniShare.testSharePathsSuccess = done => {
+  shareBase.testSharePathsSuccess(
+      shareBase.vmNameTermina, shareBase.vmNameSelectorLinux,
+      shareBase.enumUmaShareWithLinux, done);
+};
+
+pluginVmShare.testSharePathsSuccess = done => {
+  shareBase.testSharePathsSuccess(
+      shareBase.vmNamePluginVm, shareBase.vmNameSelectorPluginVm,
+      shareBase.enumUmaShareWithPluginVm, done);
+};
+
+// Verify right-click menu with 'Share with <VM>' is not shown
+// for:
 // * Files (not directory).
 // * Any folder already shared.
 // * Root Downloads folder.
 // * Any folder outside of downloads (e.g. crostini or drive).
 // * Is shown for drive if DriveFS is enabled.
-crostiniShare.testSharePathShown = (done) => {
+shareBase.testSharePathShown = async (vmName, vmNameSelector, done) => {
+  const share = 'share-with-' + vmNameSelector;
   const myFiles = '#directory-tree .tree-item [root-type-icon="my_files"]';
   const downloads = '#file-list li [file-type-icon="downloads"]';
   const linuxFiles = '#directory-tree .tree-item [root-type-icon="crostini"]';
   const googleDrive = '#directory-tree .tree-item [volume-type-icon="drive"]';
   const menuHidden = '#file-context-menu[hidden]';
-  const menuNoShareWithLinux = '#file-context-menu:not([hidden]) ' +
-      '[command="#share-with-linux"][hidden][disabled="disabled"]';
-  const menuShareWithLinux = '#file-context-menu:not([hidden]) ' +
-      '[command="#share-with-linux"]:not([hidden]):not([disabled])';
+  const menuNoShareWith = '#file-context-menu:not([hidden]) ' +
+      '[command="#' + share + '"][hidden][disabled="disabled"]';
+  const menuShareWith = '#file-context-menu:not([hidden]) ' +
+      '[command="#' + share + '"]:not([hidden]):not([disabled])';
   const downloadsDirTree = '#directory-tree [volume-type-icon="downloads"]';
   const removableVolumeRoot = '#directory-tree [volume-type-icon="removable"]';
-  const menuShareWithLinuxDirTree =
-      '#directory-tree-context-menu:not([hidden]) ' +
-      '[command="#share-with-linux"]:not([hidden]):not([disabled])';
-  const menuShareWithLinuxVolumeRoot = '#roots-context-menu:not([hidden]) ' +
-      '[command="#share-with-linux"]:not([hidden]):not([disabled])';
+  const menuShareWithDirTree = '#directory-tree-context-menu:not([hidden]) ' +
+      '[command="#' + share + '"]:not([hidden]):not([disabled])';
+  const menuShareWithVolumeRoot = '#roots-context-menu:not([hidden]) ' +
+      '[command="#' + share + '"]:not([hidden]):not([disabled])';
   let alreadySharedPhotosDir;
 
-  test.setupAndWaitUntilReady()
-      .then(() => {
-        // Right-click 'hello.txt' file.
-        // Check 'Share with Linux' is not shown in menu.
-        assertTrue(
-            test.fakeMouseRightClick('#file-list [file-name="hello.txt"]'),
-            'right-click hello.txt');
-        return test.waitForElement(menuNoShareWithLinux);
-      })
-      .then(() => {
-        // Set a folder as already shared.
-        alreadySharedPhotosDir =
-            mockVolumeManager
-                .getCurrentProfileVolumeInfo(
-                    VolumeManagerCommon.VolumeType.DOWNLOADS)
-                .fileSystem.entries['/photos'];
-        fileManager.crostini.registerSharedPath(
-            'termina', alreadySharedPhotosDir);
-        assertTrue(
-            test.fakeMouseRightClick('#file-list [file-name="photos"]'),
-            'right-click hello.txt');
-        return test.waitForElement(menuNoShareWithLinux);
-      })
-      .then(() => {
-        // Select 'My files' in directory tree to show Downloads in file list.
-        assertTrue(test.fakeMouseClick(myFiles), 'click My files');
-        return test.waitForElement(downloads);
-      })
-      .then(() => {
-        // Right-click 'Downloads' directory.
-        // Check 'Share with Linux' is shown in menu.
-        assertTrue(
-            test.fakeMouseRightClick(downloads), 'right-click downloads');
-        return test.waitForElement(menuShareWithLinux);
-      })
-      .then(() => {
-        // Right-click 'Downloads' directory in directory tree.
-        // Check 'Share with Linux' is shown in menu.
-        assertTrue(
-            test.fakeMouseRightClick(downloadsDirTree), 'downloads dirtree');
-        return test.waitForElement(menuShareWithLinuxDirTree);
-      })
-      .then(() => {
-        // Select removable root.
-        test.mountRemovable();
-        return test.waitForElement(removableVolumeRoot);
-      })
-      .then(() => {
-        // Right-click 'MyUSB' removable root.
-        // Check 'Share with Linux' is shown in menu.
-        assertTrue(
-            test.fakeMouseRightClick(removableVolumeRoot), 'removable root');
-        return test.waitForElement(menuShareWithLinuxVolumeRoot);
-      })
-      .then(() => {
-        // Select 'Linux files' in directory tree to show dir A in file list.
-        return test.waitForElement(linuxFiles);
-      })
-      .then(() => {
-        assertTrue(test.fakeMouseClick(linuxFiles), 'click Linux files');
-        return test.waitForFiles(
-            test.TestEntryInfo.getExpectedRows(test.BASIC_CROSTINI_ENTRY_SET));
-      })
-      .then(() => {
-        // Check 'Share with Linux' is not shown in menu.
-        assertTrue(
-            test.fakeMouseRightClick('#file-list [file-name="A"]'),
-            'right-click directory A');
-        return test.waitForElement(menuNoShareWithLinux);
-      })
-      .then(() => {
-        // Select 'Google Drive' to show dir photos in file list.
-        return test.waitForElement(googleDrive);
-      })
-      .then(() => {
-        assertTrue(test.fakeMouseClick(googleDrive), 'click Google Drive');
-        return test.waitForFiles(
-            test.TestEntryInfo.getExpectedRows(test.BASIC_DRIVE_ENTRY_SET));
-      })
-      .then(() => {
-        // Check 'Share with Linux' is not shown in menu.
-        assertTrue(
-            test.fakeMouseRightClick('#file-list [file-name="photos"]'),
-            'right-click photos');
-        return test.waitForElement(menuNoShareWithLinux);
-      })
-      .then(() => {
-        // Close menu by clicking file-list.
-        assertTrue(test.fakeMouseClick('#file-list'));
-        return test.waitForElement(menuHidden);
-      })
-      .then(() => {
-        // Set DRIVE_FS_ENABLED, and check that 'Share with Linux' is shown.
-        loadTimeData.data_['DRIVE_FS_ENABLED'] = true;
-        // Check 'Share with Linux' is not shown in menu.
-        assertTrue(
-            test.fakeMouseRightClick('#file-list [file-name="photos"]'),
-            'right-click photos');
-        return test.waitForElement(menuShareWithLinux);
-      })
-      .then(() => {
-        // Reset Linux files back to unmounted.
-        chrome.fileManagerPrivate.removeMount('crostini');
-        return test.waitForElement(
-            '#directory-tree .tree-item [root-type-icon="crostini"]');
-      })
-      .then(() => {
-        // Unset DRIVE_FS_ENABLED.
-        loadTimeData.data_['DRIVE_FS_ENABLED'] = false;
-        // Clear Crostini shared folders.
-        fileManager.crostini.unregisterSharedPath(
-            'termina', alreadySharedPhotosDir);
-        done();
-      });
+  await test.setupAndWaitUntilReady();
+  // Right-click 'hello.txt' file.
+  // Check 'Share with <VM>' is not shown in menu.
+  assertTrue(
+      test.fakeMouseRightClick('#file-list [file-name="hello.txt"]'),
+      'right-click hello.txt');
+  await test.waitForElement(menuNoShareWith);
+
+  // Set a folder as already shared.
+  alreadySharedPhotosDir =
+      mockVolumeManager
+          .getCurrentProfileVolumeInfo(VolumeManagerCommon.VolumeType.DOWNLOADS)
+          .fileSystem.entries['/photos'];
+  fileManager.crostini.registerSharedPath(vmName, alreadySharedPhotosDir);
+  assertTrue(
+      test.fakeMouseRightClick('#file-list [file-name="photos"]'),
+      'right-click hello.txt');
+  await test.waitForElement(menuNoShareWith);
+
+  // Select 'My files' in directory tree to show Downloads in file list.
+  assertTrue(test.fakeMouseClick(myFiles), 'click My files');
+  await test.waitForElement(downloads);
+
+  // Right-click 'Downloads' directory.
+  // Check 'Share with <VM>' is shown in menu.
+  assertTrue(test.fakeMouseRightClick(downloads), 'right-click downloads');
+  await test.waitForElement(menuShareWith);
+
+  // Right-click 'Downloads' directory in directory tree.
+  // Check 'Share with <VM>' is shown in menu.
+  assertTrue(test.fakeMouseRightClick(downloadsDirTree), 'downloads dirtree');
+  await test.waitForElement(menuShareWithDirTree);
+
+  // Select removable root.
+  test.mountRemovable();
+  await test.waitForElement(removableVolumeRoot);
+
+  // Right-click 'MyUSB' removable root.
+  // Check 'Share with <VM>' is shown in menu.
+  assertTrue(test.fakeMouseRightClick(removableVolumeRoot), 'removable root');
+  await test.waitForElement(menuShareWithVolumeRoot);
+
+  // Select 'Linux files' in directory tree to show dir A in file list.
+  await test.waitForElement(linuxFiles);
+
+  assertTrue(test.fakeMouseClick(linuxFiles), 'click Linux files');
+  await test.waitForFiles(
+      test.TestEntryInfo.getExpectedRows(test.BASIC_CROSTINI_ENTRY_SET));
+
+  // Check 'Share with <VM>' is not shown in menu.
+  assertTrue(
+      test.fakeMouseRightClick('#file-list [file-name="A"]'),
+      'right-click directory A');
+  await test.waitForElement(menuNoShareWith);
+
+  // Select 'Google Drive' to show dir photos in file list.
+  await test.waitForElement(googleDrive);
+
+  assertTrue(test.fakeMouseClick(googleDrive), 'click Google Drive');
+  await test.waitForFiles(
+      test.TestEntryInfo.getExpectedRows(test.BASIC_DRIVE_ENTRY_SET));
+
+  // Check 'Share with <VM>' is not shown in menu.
+  assertTrue(
+      test.fakeMouseRightClick('#file-list [file-name="photos"]'),
+      'right-click photos');
+  await test.waitForElement(menuNoShareWith);
+
+  // Close menu by clicking file-list.
+  assertTrue(test.fakeMouseClick('#file-list'));
+  await test.waitForElement(menuHidden);
+
+  // Set DRIVE_FS_ENABLED, and check that 'Share with <VM>' is shown.
+  loadTimeData.data_['DRIVE_FS_ENABLED'] = true;
+  // Check 'Share with <VM>' is not shown in menu.
+  assertTrue(
+      test.fakeMouseRightClick('#file-list [file-name="photos"]'),
+      'right-click photos');
+  await test.waitForElement(menuShareWith);
+
+  // Reset Linux files back to unmounted.
+  chrome.fileManagerPrivate.removeMount('crostini');
+  await test.waitForElement(
+      '#directory-tree .tree-item [root-type-icon="crostini"]');
+
+  // Unset DRIVE_FS_ENABLED.
+  loadTimeData.data_['DRIVE_FS_ENABLED'] = false;
+  // Clear Crostini shared folders.
+  fileManager.crostini.unregisterSharedPath(vmName, alreadySharedPhotosDir);
+  done();
 };
 
-// Verify gear menu 'Manage Linux sharing'.
-crostiniShare.testGearMenuManageLinuxSharing = (done) => {
+crostiniShare.testSharePathShown = done => {
+  shareBase.testSharePathShown(
+      shareBase.vmNameTermina, shareBase.vmNameSelectorLinux, done);
+};
+
+pluginVmShare.testSharePathShown = done => {
+  shareBase.testSharePathShown(
+      shareBase.vmNamePluginVm, shareBase.vmNameSelectorPluginVm, done);
+};
+
+// Verify gear menu 'Manage ? sharing'.
+shareBase.testGearMenuManage =
+    async (vmName, vmNameSelector, enumUma, done) => {
+  const manage = '#gear-menu-manage-' + vmNameSelector + '-sharing';
   const gearMenuClosed = '#gear-menu[hidden]';
-  const manageLinuxSharingOptionHidden =
-      '#gear-menu:not([hidden]) #gear-menu-manage-linux-sharing[hidden]';
-  const manageLinuxSharingOptionShown =
-      '#gear-menu:not([hidden]) #gear-menu-manage-linux-sharing:not([hidden])';
+  const manageSharingOptionHidden =
+      '#gear-menu:not([hidden]) ' + manage + '[hidden]';
+  const manageSharingOptionShown =
+      '#gear-menu:not([hidden]) ' + manage + ':not([hidden])';
   chrome.metricsPrivate.values_ = [];
 
-  test.setupAndWaitUntilReady()
-      .then(() => {
-        // Setup with crostini disabled.
-        fileManager.crostini.setEnabled(false);
-        // Click gear menu, ensure 'Manage Linux sharing' is hidden.
-        assertTrue(test.fakeMouseClick('#gear-button'));
-        return test.waitForElement(manageLinuxSharingOptionHidden);
-      })
-      .then(() => {
-        // Close gear menu.
-        assertTrue(test.fakeMouseClick('#gear-button'));
-        return test.waitForElement(gearMenuClosed);
-      })
-      .then(() => {
-        // Setup with crostini enabled.
-        fileManager.crostini.setEnabled(true);
-        // Click gear menu, ensure 'Manage Linux sharing' is shown.
-        assertTrue(test.fakeMouseClick('#gear-button'));
-        return test.waitForElement(manageLinuxSharingOptionShown);
-      })
-      .then(() => {
-        // Click 'Manage Linux sharing'.
-        assertTrue(test.fakeMouseClick('#gear-menu-manage-linux-sharing'));
-        return test.waitForElement(gearMenuClosed);
-      })
-      .then(() => {
-        // Verify UMA.
-        const lastEnumUma = chrome.metricsPrivate.values_.pop();
-        assertEquals('FileBrowser.MenuItemSelected', lastEnumUma[0].metricName);
-        assertEquals(13 /* Manage Linux sharing */, lastEnumUma[1]);
-        done();
-      });
+  await test.setupAndWaitUntilReady();
+
+  // Setup with crostini disabled.
+  fileManager.crostini.setEnabled(vmName, false);
+  // Click gear menu, ensure 'Manage <VM> sharing' is hidden.
+  assertTrue(test.fakeMouseClick('#gear-button'));
+  await test.waitForElement(manageSharingOptionHidden);
+
+  // Close gear menu.
+  assertTrue(test.fakeMouseClick('#gear-button'));
+  await test.waitForElement(gearMenuClosed);
+
+  // Setup with crostini enabled.
+  fileManager.crostini.setEnabled(vmName, true);
+  // Click gear menu, ensure 'Manage <VM> sharing' is shown.
+  assertTrue(test.fakeMouseClick('#gear-button'));
+  await test.waitForElement(manageSharingOptionShown);
+
+  // Click 'Manage <VM> sharing'.
+  assertTrue(test.fakeMouseClick(manage));
+  await test.waitForElement(gearMenuClosed);
+
+  // Verify UMA.
+  const lastEnumUma = chrome.metricsPrivate.values_.pop();
+  assertEquals('FileBrowser.MenuItemSelected', lastEnumUma[0].metricName);
+  assertEquals(enumUma, lastEnumUma[1]);
+  done();
+};
+
+crostiniShare.testGearMenuManageLinuxSharing = done => {
+  shareBase.testGearMenuManage(
+      shareBase.vmNameTermina, shareBase.vmNameSelectorLinux,
+      shareBase.enumUmaManageLinuxSharing, done);
+};
+
+pluginVmShare.testGearMenuManagePluginVmSharing = done => {
+  shareBase.testGearMenuManage(
+      shareBase.vmNamePluginVm, shareBase.vmNameSelectorPluginVm,
+      shareBase.enumUmaManagePluginVmSharing, done);
 };
diff --git a/ui/file_manager/file_manager/test/js/strings.js b/ui/file_manager/file_manager/test/js/strings.js
index 595743b..9d7fbcc 100644
--- a/ui/file_manager/file_manager/test/js/strings.js
+++ b/ui/file_manager/file_manager/test/js/strings.js
@@ -16,6 +16,7 @@
   'GOOGLE_DRIVE_OVERVIEW_URL':
       'https://support.google.com/chromebook/?p=filemanager_drive',
   'HIDE_SPACE_INFO': false,
+  'PLUGIN_VM_ENABLED': true,
   'UI_LOCALE': 'en_US',
   'language': 'en-US',
   'textdirection': 'ltr',
diff --git a/ui/file_manager/image_loader/piex/.gitignore b/ui/file_manager/image_loader/piex/.gitignore
index 280759f..53d1e6ef 100644
--- a/ui/file_manager/image_loader/piex/.gitignore
+++ b/ui/file_manager/image_loader/piex/.gitignore
@@ -1,7 +1,7 @@
 images
 node_modules
 package-lock.json
-tests.hash
+tests.result.txt
 tests.log
 a.out.*
 *.bc
diff --git a/ui/file_manager/image_loader/piex/Makefile b/ui/file_manager/image_loader/piex/Makefile
index 4667870a..a2603fd 100644
--- a/ui/file_manager/image_loader/piex/Makefile
+++ b/ui/file_manager/image_loader/piex/Makefile
@@ -16,10 +16,12 @@
 WOPT = -Os --llvm-opts 3 \
   -s STRICT=1 \
   -s ALLOW_MEMORY_GROWTH=1 \
+  -s NO_DYNAMIC_EXECUTION=1 \
   -s EXTRA_EXPORTED_RUNTIME_METHODS='$(WAPI)' \
   -s RESERVED_FUNCTION_POINTERS=2
 
 all: a.out.js
+	$(shell cp a.out.* extension)
 
 a.out.js: piex.cpp.bc piex.src.bc
 	em++ --bind --std=c++11 $(WASM) $(WOPT) $^
@@ -33,4 +35,5 @@
 .PHONY: clean
 
 clean:
-	$(shell rm -f tests.hash tests.log package-lock* *.bc a.out.*)
+	$(shell rm -f tests.{result*,log} package-lock* *.bc a.out.*)
+	$(shell rm -f extension/a.out.*)
diff --git a/ui/file_manager/image_loader/piex/README.md b/ui/file_manager/image_loader/piex/README.md
index 53a2a40..256ee901 100644
--- a/ui/file_manager/image_loader/piex/README.md
+++ b/ui/file_manager/image_loader/piex/README.md
@@ -1,20 +1,29 @@
 Install emscripten http://lmgtfy.com/?q=install+the+emscripten+sdk
 
-  % git clone https://github.com/juj/emsdk.git
-  % cd emsdk
-  % ./emsdk install latest
-  % ./emsdk activate latest
-  % source ./emsdk_env.sh
+```shell
+  git clone https://github.com/juj/emsdk.git
+  cd emsdk
+  ./emsdk install latest
+  ./emsdk activate latest
+  source ./emsdk_env.sh
+```
 
 Install piexwasm project components
 
-  % cd ui/file_manager/image_loader/piex
-  % npm install
+```shell
+  cd chrome/src/ui/file_manager/image_loader/piex
+  npm install
+```
 
 Build piexwasm code a.out.js a.out.wasm
 
-  % npm run build
+```shell
+  npm run build
+```
 
 Run tests
 
-  % npm run test
+```shell
+  npm run test
+```
+
diff --git a/ui/file_manager/image_loader/piex/extension/background.js b/ui/file_manager/image_loader/piex/extension/background.js
new file mode 100644
index 0000000..70cab29
--- /dev/null
+++ b/ui/file_manager/image_loader/piex/extension/background.js
@@ -0,0 +1,24 @@
+// 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.
+//
+// background.js: test loading the [piexwasm] module in chrome extension.
+//
+window.onload = () => {
+  console.log('[piexwasm] window.onload');
+
+  let script = document.createElement('script');
+  document.head.appendChild(script);
+
+  script.onerror = (error) => {
+    console.log('[piexwasm] failed loading script:', script.src);
+  };
+
+  self.Module = {
+    onRuntimeInitialized: () => {
+      console.log('[piexwasm] runtime loaded');
+    },
+  };
+
+  script.src = 'a.out.js';
+};
diff --git a/ui/file_manager/image_loader/piex/extension/manifest.json b/ui/file_manager/image_loader/piex/extension/manifest.json
new file mode 100644
index 0000000..3d5b62d
--- /dev/null
+++ b/ui/file_manager/image_loader/piex/extension/manifest.json
@@ -0,0 +1,14 @@
+{
+  "name": "Test [piexwasm] module.",
+  "description": "Test [piexwasm] module loads and runs in a Chrome extension.",
+  "version": "1.0.0",
+  "manifest_version": 2,
+
+  "background": {
+    "scripts": [
+      "background.js"
+    ]
+  },
+
+  "content_security_policy": "script-src 'self' 'wasm-eval'; object-src 'self'"
+}
diff --git a/ui/file_manager/image_loader/piex/images.golden.hash b/ui/file_manager/image_loader/piex/images.golden.txt
similarity index 84%
rename from ui/file_manager/image_loader/piex/images.golden.hash
rename to ui/file_manager/image_loader/piex/images.golden.txt
index 88e41200..114aa314 100644
--- a/ui/file_manager/image_loader/piex/images.golden.hash
+++ b/ui/file_manager/image_loader/piex/images.golden.txt
Binary files differ
diff --git a/ui/file_manager/image_loader/piex/piex.cpp b/ui/file_manager/image_loader/piex/piex.cpp
index a6bc668..33c26ba 100644
--- a/ui/file_manager/image_loader/piex/piex.cpp
+++ b/ui/file_manager/image_loader/piex/piex.cpp
@@ -143,3 +143,11 @@
 }
 
 }  // extern "C"
+
+int main(int argc, char* argv[]) {
+  // clang-format off
+  return EM_ASM_INT({
+    console.log('[piexwasm] main');
+  });
+  // clang-format on
+}
diff --git a/ui/file_manager/image_loader/piex/tests.html b/ui/file_manager/image_loader/piex/tests.html
index 5b303605..e9ed990 100644
--- a/ui/file_manager/image_loader/piex/tests.html
+++ b/ui/file_manager/image_loader/piex/tests.html
@@ -150,6 +150,10 @@
       return renderRGB(name, image);
   }
 
+  function removeNullBytes(string) {
+    return (string || '').replace(/\0/g, '');
+  }
+
   self.Module = {
     onRuntimeInitialized: piexModuleReady,
   };
@@ -196,7 +200,9 @@
       let preview = imageBuffer.preview();
       let thumb = imageBuffer.thumbnail();
       time = performance.now() - time;
-      console.log('test:', image, result.maker, result.model);
+      const maker = removeNullBytes(result.maker);
+      const model = removeNullBytes(result.model);
+      console.log('test:', image, maker, model);
       window.images_ = 0;
       renderResult(image, preview);
       renderResult(image, thumb);
diff --git a/ui/file_manager/image_loader/piex/tests.sh b/ui/file_manager/image_loader/piex/tests.sh
index f1073511..e9355b9 100755
--- a/ui/file_manager/image_loader/piex/tests.sh
+++ b/ui/file_manager/image_loader/piex/tests.sh
@@ -13,13 +13,13 @@
 HTTP_SERVER_PID=$!
 
 # Extract preview thumbnails from the raw test images.
-rm -f tests.hash
+rm -f tests.result.txt
 node tests.js ${HTTP}/tests.html $* | tee -a tests.log | \
-  grep --text "^test: images/" > tests.hash
+  grep --text "^test: images/" > tests.result.txt
 kill ${HTTP_SERVER_PID} > /dev/null 2>&1
 
-# Compare their hash to the golden hash values.
-if [[ $(cmp tests.hash images.golden.hash 2>&1) ]]; then
+# Compare their properties to the golden file values.
+if [[ $(cmp tests.result.txt images.golden.txt 2>&1) ]]; then
   echo "tests FAIL" || exit 1
 else
   echo "tests PASS"
diff --git a/ui/gfx/transform.cc b/ui/gfx/transform.cc
index 6b5f36d4..0d5e04b 100644
--- a/ui/gfx/transform.cc
+++ b/ui/gfx/transform.cc
@@ -53,7 +53,10 @@
                      SkMScalar col2row4,
                      SkMScalar col3row4,
                      SkMScalar col4row4)
-    : matrix_(SkMatrix44::kUninitialized_Constructor) {
+    : matrix_(SkMatrix44::kIdentity_Constructor) {
+  // TODO(masonfreed): Replace this with an explicit 16-element constructor
+  // on SkMatrix44, once that's available. This code does a *lot* of extra
+  // work, because each call to setDouble re-calculates the matrix type.
   matrix_.set(0, 0, col1row1);
   matrix_.set(1, 0, col1row2);
   matrix_.set(2, 0, col1row3);