diff --git a/DEPS b/DEPS
index 21119cc..d56c2f3 100644
--- a/DEPS
+++ b/DEPS
@@ -175,7 +175,7 @@
   # 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': 'ecd17b9e34516aad4f4e6967efc5c2398503406c',
+  'skia_revision': '4045cd82e75548918692b72f97eb89b125478a50',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -187,11 +187,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': 'a156df23585a92dc813cc88480f1a195467c9d81',
+  'angle_revision': '3d1386f3ea3f0ce933e6e3def9a67b39e80f1ce6',
   # 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': 'ba0c95eb406fb2c36cb2d1515765f4de82cbed9b',
+  'swiftshader_revision': '63ed0e445fa525ee01637350ea92fbdaa2226c73',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -226,7 +226,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
-  'freetype_revision': '7a019a63ed9753772e758beec3cad7c0b74ee2aa',
+  'freetype_revision': '11beee855e29757a07320fd60e85de2e8da4e037',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling HarfBuzz
   # and whatever else without interference from each other.
@@ -238,7 +238,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '910f6c87ac65a90489987644607cb011c2efc0a9',
+  'catapult_revision': '475c8941a1ee84f98e8056d16ddceff37cece233',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -246,7 +246,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': '298b8cc3134fdb6d63895f869e02e359e8afbf98',
+  'devtools_frontend_revision': 'ac1817c5d0362e4ffae45eea28bd86340299140b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -286,7 +286,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'spv_tools_revision': '4af38c49bfeeac536b9bf9b25be2d4bbec356972',
+  'spv_tools_revision': '538512e8e8980cc01ab6501cd1cbd402d54f8491',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -302,7 +302,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '73ea1f11068a3b85c7cd7cd12b856a681df4ce31',
+  'dawn_revision': '9d2de1d6d45f4dfd006a8d6d70ffdf5fb44aed84',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -871,7 +871,7 @@
 
   # For Linux and Chromium OS.
   'src/third_party/cros_system_api': {
-      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '9c6bf7207bfe1e3e07ee6d42846a0fe20cb55b10',
+      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '484e71aca63a67f490eed8eb42c6f3c0b92c2cb6',
       'condition': 'checkout_linux',
   },
 
@@ -1218,7 +1218,7 @@
     Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + '6f26bce0b1c4e8ce0e13332f7c0083788def5fdf',
 
   'src/third_party/openscreen/src':
-    Var('chromium_git') + '/openscreen' + '@' + '851d4192af51a242f887db5d56138f66bab46137',
+    Var('chromium_git') + '/openscreen' + '@' + '94b61ee5c25c872920f45e5581442e4bf1a5a7ea',
 
   'src/third_party/openxr/src': {
     'url': Var('chromium_git') + '/external/github.com/KhronosGroup/OpenXR-SDK' + '@' + '9e97b73e7dd2bfc07745489d728f6a36665c648f',
@@ -1235,7 +1235,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '4c8ff7ce1c1a4609c994c8a0169e43e22682d5e4',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'c98edc42336fbf508cec873654b7e13ee2866bc9',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1465,7 +1465,7 @@
   },
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '43126bb4231c8768825b6710237a52ac06315735',
+    Var('webrtc_git') + '/src.git' + '@' + 'dfae553e3a6928c9cf71121650bd4b605c359587',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1540,7 +1540,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@5ad624673601376973f44ab125bcf5c509a2bee3',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@08494419674464d45d9d0f6d8ebfddc15286d992',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/ash/assistant/assistant_alarm_timer_controller.cc b/ash/assistant/assistant_alarm_timer_controller.cc
index db30e9b..e232230 100644
--- a/ash/assistant/assistant_alarm_timer_controller.cc
+++ b/ash/assistant/assistant_alarm_timer_controller.cc
@@ -202,6 +202,55 @@
   model_.RemoveObserver(observer);
 }
 
+void AssistantAlarmTimerController::SetAssistant(
+    chromeos::assistant::mojom::Assistant* assistant) {
+  assistant_ = assistant;
+}
+
+void AssistantAlarmTimerController::OnAssistantControllerConstructed() {
+  assistant_controller_->state_controller()->AddObserver(this);
+  assistant_controller_->ui_controller()->AddModelObserver(this);
+}
+
+void AssistantAlarmTimerController::OnAssistantControllerDestroying() {
+  assistant_controller_->ui_controller()->RemoveModelObserver(this);
+  assistant_controller_->state_controller()->RemoveObserver(this);
+}
+
+void AssistantAlarmTimerController::OnDeepLinkReceived(
+    assistant::util::DeepLinkType type,
+    const std::map<std::string, std::string>& params) {
+  using assistant::util::DeepLinkParam;
+  using assistant::util::DeepLinkType;
+
+  if (type != DeepLinkType::kAlarmTimer)
+    return;
+
+  const base::Optional<assistant::util::AlarmTimerAction>& action =
+      assistant::util::GetDeepLinkParamAsAlarmTimerAction(params);
+  if (!action.has_value())
+    return;
+
+  // Timer ID is optional. Only used for adding time to timer.
+  const base::Optional<std::string>& alarm_timer_id =
+      assistant::util::GetDeepLinkParam(params, DeepLinkParam::kId);
+
+  // Duration is optional. Only used for adding time to timer.
+  const base::Optional<base::TimeDelta>& duration =
+      assistant::util::GetDeepLinkParamAsTimeDelta(params,
+                                                   DeepLinkParam::kDurationMs);
+
+  PerformAlarmTimerAction(action.value(), alarm_timer_id, duration);
+}
+
+void AssistantAlarmTimerController::OnAssistantStatusChanged(
+    mojom::AssistantState state) {
+  // If LibAssistant is no longer running we need to clear our cache to
+  // accurately reflect LibAssistant alarm/timer state.
+  if (state == mojom::AssistantState::NOT_READY)
+    model_.RemoveAllTimers();
+}
+
 void AssistantAlarmTimerController::OnTimerStateChanged(
     std::vector<mojom::AssistantTimerPtr> timers) {
   if (timers.empty()) {
@@ -271,45 +320,6 @@
                                         /*from_server=*/false);
 }
 
-void AssistantAlarmTimerController::SetAssistant(
-    chromeos::assistant::mojom::Assistant* assistant) {
-  assistant_ = assistant;
-}
-
-void AssistantAlarmTimerController::OnAssistantControllerConstructed() {
-  assistant_controller_->ui_controller()->AddModelObserver(this);
-}
-
-void AssistantAlarmTimerController::OnAssistantControllerDestroying() {
-  assistant_controller_->ui_controller()->RemoveModelObserver(this);
-}
-
-void AssistantAlarmTimerController::OnDeepLinkReceived(
-    assistant::util::DeepLinkType type,
-    const std::map<std::string, std::string>& params) {
-  using assistant::util::DeepLinkParam;
-  using assistant::util::DeepLinkType;
-
-  if (type != DeepLinkType::kAlarmTimer)
-    return;
-
-  const base::Optional<assistant::util::AlarmTimerAction>& action =
-      assistant::util::GetDeepLinkParamAsAlarmTimerAction(params);
-  if (!action.has_value())
-    return;
-
-  // Timer ID is optional. Only used for adding time to timer.
-  const base::Optional<std::string>& alarm_timer_id =
-      assistant::util::GetDeepLinkParam(params, DeepLinkParam::kId);
-
-  // Duration is optional. Only used for adding time to timer.
-  const base::Optional<base::TimeDelta>& duration =
-      assistant::util::GetDeepLinkParamAsTimeDelta(params,
-                                                   DeepLinkParam::kDurationMs);
-
-  PerformAlarmTimerAction(action.value(), alarm_timer_id, duration);
-}
-
 void AssistantAlarmTimerController::OnUiVisibilityChanged(
     AssistantVisibility new_visibility,
     AssistantVisibility old_visibility,
diff --git a/ash/assistant/assistant_alarm_timer_controller.h b/ash/assistant/assistant_alarm_timer_controller.h
index 9c395da..4678e580 100644
--- a/ash/assistant/assistant_alarm_timer_controller.h
+++ b/ash/assistant/assistant_alarm_timer_controller.h
@@ -13,6 +13,7 @@
 #include "ash/assistant/model/assistant_alarm_timer_model.h"
 #include "ash/assistant/model/assistant_alarm_timer_model_observer.h"
 #include "ash/assistant/model/assistant_ui_model_observer.h"
+#include "ash/public/cpp/assistant/assistant_state.h"
 #include "ash/public/mojom/assistant_controller.mojom.h"
 #include "base/macros.h"
 #include "base/timer/timer.h"
@@ -35,6 +36,7 @@
 class AssistantAlarmTimerController
     : public mojom::AssistantAlarmTimerController,
       public AssistantControllerObserver,
+      public AssistantStateObserver,
       public AssistantAlarmTimerModelObserver,
       public AssistantUiModelObserver {
  public:
@@ -52,16 +54,6 @@
   void AddModelObserver(AssistantAlarmTimerModelObserver* observer);
   void RemoveModelObserver(AssistantAlarmTimerModelObserver* observer);
 
-  // mojom::AssistantAlarmTimerController:
-  void OnTimerStateChanged(
-      std::vector<mojom::AssistantTimerPtr> timers) override;
-
-  // AssistantAlarmTimerModelObserver:
-  void OnTimerAdded(const mojom::AssistantTimer& timer) override;
-  void OnTimerUpdated(const mojom::AssistantTimer& timer) override;
-  void OnTimerRemoved(const mojom::AssistantTimer& timer) override;
-  void OnAllTimersRemoved() override;
-
   // Provides a pointer to the |assistant| owned by AssistantController.
   void SetAssistant(chromeos::assistant::mojom::Assistant* assistant);
 
@@ -72,6 +64,19 @@
       assistant::util::DeepLinkType type,
       const std::map<std::string, std::string>& params) override;
 
+  // AssistantStateObserver:
+  void OnAssistantStatusChanged(mojom::AssistantState state) override;
+
+  // mojom::AssistantAlarmTimerController:
+  void OnTimerStateChanged(
+      std::vector<mojom::AssistantTimerPtr> timers) override;
+
+  // AssistantAlarmTimerModelObserver:
+  void OnTimerAdded(const mojom::AssistantTimer& timer) override;
+  void OnTimerUpdated(const mojom::AssistantTimer& timer) override;
+  void OnTimerRemoved(const mojom::AssistantTimer& timer) override;
+  void OnAllTimersRemoved() override;
+
   // AssistantUiModelObserver:
   void OnUiVisibilityChanged(
       AssistantVisibility new_visibility,
diff --git a/ash/assistant/model/assistant_alarm_timer_model.cc b/ash/assistant/model/assistant_alarm_timer_model.cc
index f2e2649..63ae0e6 100644
--- a/ash/assistant/model/assistant_alarm_timer_model.cc
+++ b/ash/assistant/model/assistant_alarm_timer_model.cc
@@ -30,12 +30,12 @@
 
   auto it = timers_.find(timer->id);
   if (it == timers_.end()) {
-    timers_[timer->id] = std::move(timer);
+    timers_[ptr->id] = std::move(timer);
     NotifyTimerAdded(*ptr);
     return;
   }
 
-  timers_[timer->id] = std::move(timer);
+  timers_[ptr->id] = std::move(timer);
   NotifyTimerUpdated(*ptr);
 }
 
diff --git a/base/trace_event/memory_infra_background_allowlist.cc b/base/trace_event/memory_infra_background_allowlist.cc
index f9a894e..7d1e574 100644
--- a/base/trace_event/memory_infra_background_allowlist.cc
+++ b/base/trace_event/memory_infra_background_allowlist.cc
@@ -77,6 +77,7 @@
     "blink_gc/main/heap",
     "blink_gc/workers/heap/worker_0x?",
     "blink_objects/AdSubframe",
+    "blink_objects/ArrayBufferContents",
     "blink_objects/AudioHandler",
     "blink_objects/ContextLifecycleStateObserver",
     "blink_objects/DetachedScriptState",
diff --git a/cc/test/test_skcanvas.h b/cc/test/test_skcanvas.h
index 6c293a2..936ef0d 100644
--- a/cc/test/test_skcanvas.h
+++ b/cc/test/test_skcanvas.h
@@ -64,7 +64,7 @@
                     SrcRectConstraint));
   MOCK_METHOD5(onDrawArc,
                void(const SkRect&, SkScalar, SkScalar, bool, const SkPaint&));
-  MOCK_METHOD1(didConcat44, void(const SkScalar[16]));
+  MOCK_METHOD1(didConcat44, void(const SkM44&));
   MOCK_METHOD1(didConcat, void(const SkMatrix&));
   MOCK_METHOD2(didScale, void(SkScalar, SkScalar));
   MOCK_METHOD2(didTranslate, void(SkScalar, SkScalar));
diff --git a/chrome/VERSION b/chrome/VERSION
index e8e7182..bc357c0 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=84
 MINOR=0
-BUILD=4108
+BUILD=4109
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index f9e5fdb1..16bcf906 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -884,6 +884,7 @@
     "//components/embedder_support/android:web_contents_delegate_java",
     "//components/embedder_support/android:web_contents_delegate_javatests",
     "//components/external_intents/android:java",
+    "//components/external_intents/android:javatests",
     "//components/feature_engagement:feature_engagement_java",
     "//components/gcm_driver/android:gcm_driver_java",
     "//components/gcm_driver/instance_id/android:instance_id_driver_java",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index 767e56f..c454ecd 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -1595,7 +1595,6 @@
   "java/src/org/chromium/chrome/browser/tab/TabLifecycle.java",
   "java/src/org/chromium/chrome/browser/tab/TabObserver.java",
   "java/src/org/chromium/chrome/browser/tab/TabParentIntent.java",
-  "java/src/org/chromium/chrome/browser/tab/TabRedirectHandler.java",
   "java/src/org/chromium/chrome/browser/tab/TabState.java",
   "java/src/org/chromium/chrome/browser/tab/TabStateBrowserControlsVisibilityDelegate.java",
   "java/src/org/chromium/chrome/browser/tab/TabThemeColorHelper.java",
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni
index 79b2941..6ad5bbb 100644
--- a/chrome/android/chrome_test_java_sources.gni
+++ b/chrome/android/chrome_test_java_sources.gni
@@ -488,7 +488,6 @@
   "javatests/src/org/chromium/chrome/browser/tab/RepostFormWarningTest.java",
   "javatests/src/org/chromium/chrome/browser/tab/SadTabTest.java",
   "javatests/src/org/chromium/chrome/browser/tab/TabIdManagerTest.java",
-  "javatests/src/org/chromium/chrome/browser/tab/TabRedirectHandlerTest.java",
   "javatests/src/org/chromium/chrome/browser/tab/TabStateTest.java",
   "javatests/src/org/chromium/chrome/browser/tab/TabUmaTest.java",
   "javatests/src/org/chromium/chrome/browser/tab/UndoIntegrationTest.java",
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java
index 4721412..c0eef24 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java
@@ -141,7 +141,8 @@
                         : null);
         if (mTabSwitcher != null) {
             mTabSwitcher.initWithNative(mActivity, mActivity.getTabContentManager(),
-                    mActivity.getCompositorViewHolder().getDynamicResourceLoader(), mActivity);
+                    mActivity.getCompositorViewHolder().getDynamicResourceLoader(), mActivity,
+                    mActivity.getModalDialogManager());
         }
         if (mTasksSurface != null) {
             mTasksSurface.onFinishNativeInitialization(
diff --git a/chrome/android/features/tab_ui/BUILD.gn b/chrome/android/features/tab_ui/BUILD.gn
index fa9b426..1af43b7 100644
--- a/chrome/android/features/tab_ui/BUILD.gn
+++ b/chrome/android/features/tab_ui/BUILD.gn
@@ -119,10 +119,7 @@
     "java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMenuItemProperties.java",
     "java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogParent.java",
     "java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogCoordinator.java",
-    "java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogMediator.java",
-    "java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogParent.java",
-    "java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogProperties.java",
-    "java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogViewBinder.java",
+    "java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogView.java",
     "java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridItemTouchHelperCallback.java",
     "java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelProperties.java",
     "java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelViewBinder.java",
diff --git a/chrome/android/features/tab_ui/java/res/layout/iph_drag_and_drop_dialog_layout.xml b/chrome/android/features/tab_ui/java/res/layout/iph_drag_and_drop_dialog_layout.xml
index 4d9ee34..fb5fcd2 100644
--- a/chrome/android/features/tab_ui/java/res/layout/iph_drag_and_drop_dialog_layout.xml
+++ b/chrome/android/features/tab_ui/java/res/layout/iph_drag_and_drop_dialog_layout.xml
@@ -2,14 +2,14 @@
 <!-- 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. -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<org.chromium.chrome.browser.tasks.tab_management.TabGridIphDialogView
+    xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:id="@+id/iph_dialog"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:layout_gravity="center"
     android:orientation="vertical"
-    android:background="@drawable/popup_bg_tinted"
     android:clickable="true"
     android:focusable="true">
     <ImageView
@@ -39,15 +39,4 @@
         android:text="@string/iph_drag_and_drop_content"
         android:textAppearance="@style/TextAppearance.TextMedium.Primary"
         android:gravity="start" />
-    <TextView
-        android:id="@+id/close_button"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="32dp"
-        android:layout_marginEnd="32dp"
-        android:layout_marginTop="16dp"
-        android:layout_marginBottom="16dp"
-        android:text="@string/ok"
-        android:textAppearance="@style/TextAppearance.TextMediumThick.Blue"
-        android:gravity="end" />
-</LinearLayout>
+</org.chromium.chrome.browser.tasks.tab_management.TabGridIphDialogView>
diff --git a/chrome/android/features/tab_ui/java/res/values/dimens.xml b/chrome/android/features/tab_ui/java/res/values/dimens.xml
index 6a22242..2d8f0f1 100644
--- a/chrome/android/features/tab_ui/java/res/values/dimens.xml
+++ b/chrome/android/features/tab_ui/java/res/values/dimens.xml
@@ -13,9 +13,8 @@
     <dimen name="tab_grid_dialog_side_margin">16dp</dimen>
     <dimen name="tab_grid_dialog_top_margin">85dp</dimen>
     <dimen name="tab_grid_iph_item_description_margin">16dp</dimen>
-    <dimen name="tab_grid_iph_dialog_height">430dp</dimen>
+    <dimen name="tab_grid_iph_dialog_height">400dp</dimen>
     <dimen name="tab_grid_iph_dialog_top_margin">24dp</dimen>
-    <dimen name="tab_grid_iph_dialog_side_margin">12dp</dimen>
     <dimen name="tab_grid_iph_dialog_text_top_margin_landscape">8dp</dimen>
     <dimen name="tab_grid_iph_dialog_text_top_margin_portrait">16dp</dimen>
     <dimen name="tab_grid_iph_dialog_text_side_margin">32dp</dimen>
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/SingleTabSwitcherCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/SingleTabSwitcherCoordinator.java
index 2f08366c..e950ddf 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/SingleTabSwitcherCoordinator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/SingleTabSwitcherCoordinator.java
@@ -20,6 +20,7 @@
 import org.chromium.chrome.browser.tasks.tab_management.TabSwitcher;
 import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
 import org.chromium.chrome.tab_ui.R;
+import org.chromium.ui.modaldialog.ModalDialogManager;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
 import org.chromium.ui.resources.dynamics.DynamicResourceLoader;
@@ -120,7 +121,8 @@
     @Override
     public void initWithNative(Context context, TabContentManager tabContentManager,
             DynamicResourceLoader dynamicResourceLoader,
-            SnackbarManager.SnackbarManageable snackbarManageable) {
+            SnackbarManager.SnackbarManageable snackbarManageable,
+            ModalDialogManager modalDialogManager) {
         mTabListFaviconProvider.initWithNative(Profile.getLastUsedRegularProfile());
     }
 
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksSurfaceCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksSurfaceCoordinator.java
index ac8bf91..f8306f73 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksSurfaceCoordinator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/TasksSurfaceCoordinator.java
@@ -108,7 +108,8 @@
     public void onFinishNativeInitialization(Context context, FakeboxDelegate fakeboxDelegate) {
         ChromeActivity activity = (ChromeActivity) context;
         mTabSwitcher.initWithNative(activity, activity.getTabContentManager(),
-                activity.getCompositorViewHolder().getDynamicResourceLoader(), activity);
+                activity.getCompositorViewHolder().getDynamicResourceLoader(), activity,
+                activity.getModalDialogManager());
 
         mMediator.initWithNative(fakeboxDelegate);
     }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IphMessageService.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IphMessageService.java
index 3635535..68c89bd7 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IphMessageService.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/IphMessageService.java
@@ -13,7 +13,7 @@
  * One of the concrete {@link MessageService} that only serves {@link MessageType.IPH}.
  */
 public class IphMessageService extends MessageService {
-    private final TabGridIphDialogCoordinator.IphController mIphController;
+    private final TabSwitcherCoordinator.IphController mIphController;
     private final Tracker mTracker;
 
     /**
@@ -44,7 +44,7 @@
         }
     }
 
-    IphMessageService(TabGridIphDialogCoordinator.IphController controller) {
+    IphMessageService(TabSwitcherCoordinator.IphController controller) {
         super(MessageType.IPH);
         mIphController = controller;
         Profile profile = Profile.getLastUsedRegularProfile().getOriginalProfile();
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogCoordinator.java
index 750cd6a..bc164a5 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogCoordinator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogCoordinator.java
@@ -5,49 +5,69 @@
 package org.chromium.chrome.browser.tasks.tab_management;
 
 import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
 
+import org.chromium.chrome.tab_ui.R;
+import org.chromium.ui.modaldialog.DialogDismissalCause;
+import org.chromium.ui.modaldialog.ModalDialogManager;
+import org.chromium.ui.modaldialog.ModalDialogProperties;
 import org.chromium.ui.modelutil.PropertyModel;
-import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
 
 /**
- * Coordinator for the IPH dialog in {@link TabSwitcherMediator}
+ * Coordinator for the IPH dialog in grid tab switcher.
  */
-class TabGridIphDialogCoordinator {
-    /**
-     * Interface to control the IPH dialog.
-     */
-    interface IphController {
-        /**
-         * Show the dialog with IPH.
-         */
-        void showIph();
-    }
-    private final PropertyModelChangeProcessor mModelChangeProcessor;
-    private final TabGridIphDialogMediator mMediator;
-    private final TabGridIphDialogParent mIphDialogParent;
+class TabGridIphDialogCoordinator implements TabSwitcherCoordinator.IphController {
+    private final View mParentView;
+    private final TabGridIphDialogView mIphDialogView;
+    private final PropertyModel mModel;
+    private final ModalDialogManager mModalDialogManager;
+    private final ViewTreeObserver.OnGlobalLayoutListener mRootViewLayoutListener;
 
-    TabGridIphDialogCoordinator(Context context, ViewGroup parent) {
-        PropertyModel iphItemPropertyModel = new PropertyModel(TabGridIphDialogProperties.ALL_KEYS);
-        mIphDialogParent = new TabGridIphDialogParent(context, parent);
+    TabGridIphDialogCoordinator(
+            Context context, ViewGroup parent, ModalDialogManager modalDialogManager) {
+        mIphDialogView = (TabGridIphDialogView) LayoutInflater.from(context).inflate(
+                R.layout.iph_drag_and_drop_dialog_layout, null, false);
+        mModalDialogManager = modalDialogManager;
+        mParentView = parent;
 
-        mModelChangeProcessor = PropertyModelChangeProcessor.create(
-                iphItemPropertyModel, mIphDialogParent, TabGridIphDialogViewBinder::bind);
+        ModalDialogProperties.Controller dialogController = new ModalDialogProperties.Controller() {
+            @Override
+            public void onClick(PropertyModel model, int buttonType) {
+                if (buttonType == ModalDialogProperties.ButtonType.POSITIVE) {
+                    modalDialogManager.dismissDialog(
+                            model, DialogDismissalCause.POSITIVE_BUTTON_CLICKED);
+                }
+            }
 
-        mMediator = new TabGridIphDialogMediator(iphItemPropertyModel);
+            @Override
+            public void onDismiss(PropertyModel model, int dismissalCause) {
+                mIphDialogView.stopIPHAnimation();
+            }
+        };
+        mModel = new PropertyModel.Builder(ModalDialogProperties.ALL_KEYS)
+                         .with(ModalDialogProperties.CONTROLLER, dialogController)
+                         .with(ModalDialogProperties.CANCEL_ON_TOUCH_OUTSIDE, true)
+                         .with(ModalDialogProperties.POSITIVE_BUTTON_TEXT,
+                                 context.getResources().getString(R.string.ok))
+                         .with(ModalDialogProperties.CUSTOM_VIEW, mIphDialogView)
+                         .build();
+
+        mIphDialogView.setRootView(mParentView);
+        mRootViewLayoutListener = mIphDialogView::updateLayout;
+        mParentView.getViewTreeObserver().addOnGlobalLayoutListener(mRootViewLayoutListener);
     }
 
-    /**
-     * Get the controller to show IPH dialog.
-     * @return The {@link IphController} used to show IPH.
-     */
-    IphController getIphController() {
-        return mMediator;
+    @Override
+    public void showIph() {
+        mModalDialogManager.showDialog(mModel, ModalDialogManager.ModalDialogType.APP);
+        mIphDialogView.startIPHAnimation();
     }
 
     /** Destroy the IPH component. */
     public void destroy() {
-        mModelChangeProcessor.destroy();
-        mIphDialogParent.destroy();
+        mParentView.getViewTreeObserver().removeOnGlobalLayoutListener(mRootViewLayoutListener);
     }
 }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogMediator.java
deleted file mode 100644
index ef985b2..0000000
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogMediator.java
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2020 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.tasks.tab_management;
-
-import android.view.View;
-
-import org.chromium.chrome.browser.widget.ScrimView;
-import org.chromium.ui.modelutil.PropertyModel;
-
-/**
- * A mediator for the TabGridIphDialog component, responsible for communicating
- * with the components' coordinator as well as managing the business logic
- * for IPH item show/hide.
- */
-class TabGridIphDialogMediator implements TabGridIphDialogCoordinator.IphController {
-    private PropertyModel mModel;
-
-    TabGridIphDialogMediator(PropertyModel model) {
-        mModel = model;
-
-        View.OnClickListener closeIPHDialogOnClickListener = view -> {
-            mModel.set(TabGridIphDialogProperties.IS_VISIBLE, false);
-        };
-        mModel.set(TabGridIphDialogProperties.CLOSE_BUTTON_LISTENER, closeIPHDialogOnClickListener);
-        ScrimView.ScrimObserver observer = new ScrimView.ScrimObserver() {
-            @Override
-            public void onScrimClick() {
-                mModel.set(TabGridIphDialogProperties.IS_VISIBLE, false);
-            }
-
-            @Override
-            public void onScrimVisibilityChanged(boolean visible) {}
-        };
-        mModel.set(TabGridIphDialogProperties.SCRIM_VIEW_OBSERVER, observer);
-    }
-
-    @Override
-    public void showIph() {
-        mModel.set(TabGridIphDialogProperties.IS_VISIBLE, true);
-    }
-}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogParent.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogParent.java
deleted file mode 100644
index e3cd895..0000000
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogParent.java
+++ /dev/null
@@ -1,188 +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.tasks.tab_management;
-
-import android.content.ComponentCallbacks;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.graphics.drawable.Animatable;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.PopupWindow;
-import android.widget.TextView;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.vectordrawable.graphics.drawable.Animatable2Compat;
-import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat;
-
-import org.chromium.chrome.browser.widget.ScrimView;
-import org.chromium.chrome.tab_ui.R;
-
-/**
- * Represents a parent component for TabGridIph related UIs.
- */
-public class TabGridIphDialogParent {
-    private final int mDialogSideMargin;
-    private final int mDialogTextSideMargin;
-    private final int mDialogTextTopMarginPortrait;
-    private final int mDialogTextTopMarginLandscape;
-    private final Context mContext;
-    private final View mParentView;
-    private View mIphDialogView;
-    private TextView mCloseIPHDialogButton;
-    private ScrimView mScrimView;
-    private ScrimView.ScrimParams mScrimParams;
-    private Drawable mIphDrawable;
-    private PopupWindow mIphWindow;
-    private Animatable mIphAnimation;
-    private Animatable2Compat.AnimationCallback mAnimationCallback;
-    private ViewGroup.MarginLayoutParams mDialogMarginParams;
-    private ViewGroup.MarginLayoutParams mTitleTextMarginParams;
-    private ViewGroup.MarginLayoutParams mDescriptionTextMarginParams;
-    private ViewGroup.MarginLayoutParams mCloseButtonMarginParams;
-    private ComponentCallbacks mComponentCallbacks;
-
-    TabGridIphDialogParent(Context context, View parentView) {
-        mContext = context;
-        mParentView = parentView;
-        mDialogSideMargin =
-                (int) mContext.getResources().getDimension(R.dimen.tab_grid_iph_dialog_side_margin);
-        mDialogTextSideMargin = (int) mContext.getResources().getDimension(
-                R.dimen.tab_grid_iph_dialog_text_side_margin);
-        mDialogTextTopMarginPortrait = (int) mContext.getResources().getDimension(
-                R.dimen.tab_grid_iph_dialog_text_top_margin_portrait);
-        mDialogTextTopMarginLandscape = (int) mContext.getResources().getDimension(
-                R.dimen.tab_grid_iph_dialog_text_top_margin_landscape);
-
-        FrameLayout backgroundView = new FrameLayout(mContext);
-        mIphDialogView = LayoutInflater.from(mContext).inflate(
-                R.layout.iph_drag_and_drop_dialog_layout, backgroundView, false);
-        mCloseIPHDialogButton = mIphDialogView.findViewById(R.id.close_button);
-        mIphDrawable =
-                ((ImageView) mIphDialogView.findViewById(R.id.animation_drawable)).getDrawable();
-        mIphAnimation = (Animatable) mIphDrawable;
-        TextView iphDialogTitleText = mIphDialogView.findViewById(R.id.title);
-        TextView iphDialogDescriptionText = mIphDialogView.findViewById(R.id.description);
-        mAnimationCallback = new Animatable2Compat.AnimationCallback() {
-            @Override
-            public void onAnimationEnd(Drawable drawable) {
-                Handler handler = new Handler();
-                handler.postDelayed(mIphAnimation::start, 1500);
-            }
-        };
-        backgroundView.addView(mIphDialogView);
-        mIphWindow = new PopupWindow(backgroundView, ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT);
-        mScrimView = new ScrimView(mContext, null, backgroundView);
-        mDialogMarginParams = (ViewGroup.MarginLayoutParams) mIphDialogView.getLayoutParams();
-        mTitleTextMarginParams =
-                (ViewGroup.MarginLayoutParams) iphDialogTitleText.getLayoutParams();
-        mDescriptionTextMarginParams =
-                (ViewGroup.MarginLayoutParams) iphDialogDescriptionText.getLayoutParams();
-        mCloseButtonMarginParams =
-                (ViewGroup.MarginLayoutParams) mCloseIPHDialogButton.getLayoutParams();
-
-        mComponentCallbacks = new ComponentCallbacks() {
-            @Override
-            public void onConfigurationChanged(Configuration newConfig) {
-                updateMargins(newConfig.orientation);
-            }
-
-            @Override
-            public void onLowMemory() {}
-        };
-        mContext.registerComponentCallbacks(mComponentCallbacks);
-    }
-
-    /**
-     * Setup the {@link View.OnClickListener} for close button in the IPH dialog.
-     *
-     * @param listener The {@link View.OnClickListener} used to setup close button in IPH dialog.
-     */
-    void setupCloseIphDialogButtonOnclickListener(View.OnClickListener listener) {
-        mCloseIPHDialogButton.setOnClickListener(listener);
-    }
-
-    /**
-     * Setup the {@link ScrimView.ScrimParams} for the {@link ScrimView}.
-     *
-     * @param observer The {@link ScrimView.ScrimObserver} used to setup the scrim view params.
-     */
-    void setupIPHDialogScrimViewObserver(ScrimView.ScrimObserver observer) {
-        mScrimParams = new ScrimView.ScrimParams(mIphDialogView, false, true, 0, observer);
-    }
-
-    /**
-     * Close the IPH dialog and hide the scrim view.
-     */
-    void closeIphDialog() {
-        mIphWindow.dismiss();
-        mScrimView.hideScrim(true);
-        AnimatedVectorDrawableCompat.unregisterAnimationCallback(mIphDrawable, mAnimationCallback);
-        mIphAnimation.stop();
-    }
-
-    /**
-     * Show the scrim view and show dialog above it.
-     */
-    void showIPHDialog() {
-        if (mScrimParams != null) {
-            mScrimView.showScrim(mScrimParams);
-        }
-        updateMargins(mContext.getResources().getConfiguration().orientation);
-        mIphWindow.showAtLocation(mParentView, Gravity.CENTER, 0, 0);
-        AnimatedVectorDrawableCompat.registerAnimationCallback(mIphDrawable, mAnimationCallback);
-        mIphAnimation.start();
-    }
-
-    private void updateMargins(int orientation) {
-        int parentViewHeight = mParentView.getHeight();
-        int dialogHeight =
-                (int) mContext.getResources().getDimension(R.dimen.tab_grid_iph_dialog_height);
-        // Dynamically setup the top margin base on parent view height, the minimum top margin is
-        // specified in case the parent view height is smaller than or too close to dialog height.
-        int updatedDialogTopMargin = Math.max((parentViewHeight - dialogHeight) / 2,
-                (int) mContext.getResources().getDimension(R.dimen.tab_grid_iph_dialog_top_margin));
-
-        int dialogTopMargin;
-        int dialogSideMargin;
-        int textTopMargin;
-        if (orientation == Configuration.ORIENTATION_PORTRAIT) {
-            dialogTopMargin = updatedDialogTopMargin;
-            dialogSideMargin = mDialogSideMargin;
-            textTopMargin = mDialogTextTopMarginPortrait;
-        } else {
-            dialogTopMargin = mDialogSideMargin;
-            dialogSideMargin = updatedDialogTopMargin;
-            textTopMargin = mDialogTextTopMarginLandscape;
-        }
-        mDialogMarginParams.setMargins(
-                dialogSideMargin, dialogTopMargin, dialogSideMargin, dialogTopMargin);
-        mTitleTextMarginParams.setMargins(
-                mDialogTextSideMargin, textTopMargin, mDialogTextSideMargin, textTopMargin);
-        mDescriptionTextMarginParams.setMargins(
-                mDialogTextSideMargin, 0, mDialogTextSideMargin, textTopMargin);
-        mCloseButtonMarginParams.setMargins(
-                mDialogTextSideMargin, textTopMargin, mDialogTextSideMargin, textTopMargin);
-    }
-
-    /**
-     * Destroy any members that needs clean up.
-     */
-    public void destroy() {
-        mContext.unregisterComponentCallbacks(mComponentCallbacks);
-    }
-
-    @VisibleForTesting
-    PopupWindow getIphWindowForTesting() {
-        return mIphWindow;
-    }
-}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogProperties.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogProperties.java
deleted file mode 100644
index f75a927..0000000
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogProperties.java
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2020 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.tasks.tab_management;
-
-import android.view.View;
-
-import org.chromium.chrome.browser.widget.ScrimView;
-import org.chromium.ui.modelutil.PropertyKey;
-import org.chromium.ui.modelutil.PropertyModel;
-
-/**
- * List of properties used by TabGridIphDialog.
- */
-class TabGridIphDialogProperties {
-    public static final PropertyModel
-            .WritableObjectPropertyKey<View.OnClickListener> CLOSE_BUTTON_LISTENER =
-            new PropertyModel.WritableObjectPropertyKey<>();
-    public static final PropertyModel
-            .WritableObjectPropertyKey<ScrimView.ScrimObserver> SCRIM_VIEW_OBSERVER =
-            new PropertyModel.WritableObjectPropertyKey<>();
-    public static final PropertyModel.WritableBooleanPropertyKey IS_VISIBLE =
-            new PropertyModel.WritableBooleanPropertyKey();
-    public static final PropertyKey[] ALL_KEYS =
-            new PropertyKey[] {CLOSE_BUTTON_LISTENER, SCRIM_VIEW_OBSERVER, IS_VISIBLE};
-}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogView.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogView.java
new file mode 100644
index 0000000..b589c98
--- /dev/null
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogView.java
@@ -0,0 +1,125 @@
+// 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.tasks.tab_management;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.drawable.Animatable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.vectordrawable.graphics.drawable.Animatable2Compat;
+import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat;
+
+import org.chromium.chrome.tab_ui.R;
+
+/**
+ * The view for TabGridIph related UIs.
+ */
+public class TabGridIphDialogView extends LinearLayout {
+    private final int mDialogHeight;
+    private final int mDialogTopMargin;
+    private final int mDialogTextSideMargin;
+    private final int mDialogTextTopMarginPortrait;
+    private final int mDialogTextTopMarginLandscape;
+    private final Context mContext;
+    private View mRootView;
+    private Drawable mIphDrawable;
+    private Animatable mIphAnimation;
+    private Animatable2Compat.AnimationCallback mAnimationCallback;
+    private ViewGroup.MarginLayoutParams mTitleTextMarginParams;
+    private ViewGroup.MarginLayoutParams mDescriptionTextMarginParams;
+    private int mParentViewHeight;
+
+    public TabGridIphDialogView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mContext = context;
+        mDialogHeight =
+                (int) mContext.getResources().getDimension(R.dimen.tab_grid_iph_dialog_height);
+        mDialogTopMargin =
+                (int) mContext.getResources().getDimension(R.dimen.tab_grid_iph_dialog_top_margin);
+        mDialogTextSideMargin = (int) mContext.getResources().getDimension(
+                R.dimen.tab_grid_iph_dialog_text_side_margin);
+        mDialogTextTopMarginPortrait = (int) mContext.getResources().getDimension(
+                R.dimen.tab_grid_iph_dialog_text_top_margin_portrait);
+        mDialogTextTopMarginLandscape = (int) mContext.getResources().getDimension(
+                R.dimen.tab_grid_iph_dialog_text_top_margin_landscape);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mIphDrawable = ((ImageView) findViewById(R.id.animation_drawable)).getDrawable();
+        mIphAnimation = (Animatable) mIphDrawable;
+        TextView iphDialogTitleText = findViewById(R.id.title);
+        TextView iphDialogDescriptionText = findViewById(R.id.description);
+        mAnimationCallback = new Animatable2Compat.AnimationCallback() {
+            @Override
+            public void onAnimationEnd(Drawable drawable) {
+                Handler handler = new Handler();
+                handler.postDelayed(mIphAnimation::start, 1500);
+            }
+        };
+        mTitleTextMarginParams =
+                (ViewGroup.MarginLayoutParams) iphDialogTitleText.getLayoutParams();
+        mDescriptionTextMarginParams =
+                (ViewGroup.MarginLayoutParams) iphDialogDescriptionText.getLayoutParams();
+    }
+
+    /**
+     * Setup the root view of the dialog.
+     * @param rootView  The root view of the IPH dialog. Will be used to update the IPH view layout.
+     */
+    void setRootView(View rootView) {
+        mRootView = rootView;
+    }
+
+    /**
+     * Stops the IPH animation. This is called when the IPH dialog hides.
+     */
+    void stopIPHAnimation() {
+        AnimatedVectorDrawableCompat.unregisterAnimationCallback(mIphDrawable, mAnimationCallback);
+        mIphAnimation.stop();
+    }
+
+    /**
+     * Update the IPH view layout and start playing IPH animation. This is called when the IPH
+     * dialog shows.
+     */
+    void startIPHAnimation() {
+        updateLayout();
+        AnimatedVectorDrawableCompat.registerAnimationCallback(mIphDrawable, mAnimationCallback);
+        mIphAnimation.start();
+    }
+
+    /**
+     * Update the IPH view layout based on the current size of the root view.
+     */
+    void updateLayout() {
+        if (mParentViewHeight == mRootView.getHeight()) return;
+        mParentViewHeight = mRootView.getHeight();
+        int orientation = mContext.getResources().getConfiguration().orientation;
+        int textTopMargin;
+        if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+            textTopMargin = mDialogTextTopMarginPortrait;
+        } else {
+            textTopMargin = mDialogTextTopMarginLandscape;
+        }
+        mTitleTextMarginParams.setMargins(
+                mDialogTextSideMargin, textTopMargin, mDialogTextSideMargin, textTopMargin);
+        mDescriptionTextMarginParams.setMargins(
+                mDialogTextSideMargin, 0, mDialogTextSideMargin, textTopMargin);
+
+        // The IPH view height should be at most (root view height - 2 * top margin).
+        int dialogHeight = Math.min(mDialogHeight, mParentViewHeight - 2 * mDialogTopMargin);
+        setMinimumHeight(dialogHeight);
+    }
+}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogViewBinder.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogViewBinder.java
deleted file mode 100644
index 3531e65..0000000
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogViewBinder.java
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2020 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.tasks.tab_management;
-
-import static org.chromium.chrome.browser.tasks.tab_management.TabGridIphDialogProperties.CLOSE_BUTTON_LISTENER;
-import static org.chromium.chrome.browser.tasks.tab_management.TabGridIphDialogProperties.IS_VISIBLE;
-import static org.chromium.chrome.browser.tasks.tab_management.TabGridIphDialogProperties.SCRIM_VIEW_OBSERVER;
-
-import org.chromium.ui.modelutil.PropertyKey;
-import org.chromium.ui.modelutil.PropertyModel;
-
-/**
- * ViewBinder for TabGridIphDialog.
- */
-class TabGridIphDialogViewBinder {
-    public static void bind(
-            PropertyModel model, TabGridIphDialogParent iphDialogParent, PropertyKey propertyKey) {
-        if (CLOSE_BUTTON_LISTENER == propertyKey) {
-            iphDialogParent.setupCloseIphDialogButtonOnclickListener(
-                    model.get(CLOSE_BUTTON_LISTENER));
-        } else if (SCRIM_VIEW_OBSERVER == propertyKey) {
-            iphDialogParent.setupIPHDialogScrimViewObserver(model.get(SCRIM_VIEW_OBSERVER));
-        } else if (IS_VISIBLE == propertyKey) {
-            if (model.get(IS_VISIBLE)) {
-                iphDialogParent.showIPHDialog();
-            } else {
-                iphDialogParent.closeIphDialog();
-            }
-        }
-    }
-}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphItemCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphItemCoordinator.java
deleted file mode 100644
index 88613ec3..0000000
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphItemCoordinator.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.tasks.tab_management;
-
-import android.content.Context;
-import android.view.LayoutInflater;
-import android.view.ViewGroup;
-
-import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.tab_ui.R;
-import org.chromium.ui.modelutil.PropertyModel;
-import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
-
-/**
- * Coordinator for the IPH item in {@link TabSwitcherMediator}
- */
-class TabGridIphItemCoordinator {
-    private final PropertyModelChangeProcessor mModelChangeProcessor;
-    private final TabGridIphItemMediator mMediator;
-    private final TabGridIphItemView mIphItemView;
-
-    TabGridIphItemCoordinator(Context context, TabListRecyclerView contentView, ViewGroup parent) {
-        PropertyModel iphItemPropertyModel = new PropertyModel(TabGridIphItemProperties.ALL_KEYS);
-        LayoutInflater.from(context).inflate(R.layout.iph_card_item_layout, parent, true);
-        mIphItemView = parent.findViewById(R.id.tab_grid_iph_item);
-
-        mModelChangeProcessor = PropertyModelChangeProcessor.create(iphItemPropertyModel,
-                new TabGridIphItemViewBinder.ViewHolder(contentView, mIphItemView),
-                TabGridIphItemViewBinder::bind);
-
-        mMediator = new TabGridIphItemMediator(
-                iphItemPropertyModel, Profile.getLastUsedRegularProfile());
-    }
-
-    /**
-     * Get the provider to show IPH item.
-     * @return The {@link TabSwitcherMediator.IphProvider} used to show IPH.
-     */
-    TabSwitcherMediator.IphProvider getIphProvider() {
-        return mMediator;
-    }
-
-    /** Destroy the IPH component. */
-    public void destroy() {
-        mModelChangeProcessor.destroy();
-        mIphItemView.destroy();
-    }
-}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcher.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcher.java
index 4715e85..a0967892 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcher.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcher.java
@@ -18,6 +18,7 @@
 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
+import org.chromium.ui.modaldialog.ModalDialogManager;
 import org.chromium.ui.resources.dynamics.DynamicResourceLoader;
 import org.chromium.ui.resources.dynamics.ViewResourceAdapter;
 
@@ -49,7 +50,8 @@
      */
     void initWithNative(Context context, TabContentManager tabContentManager,
             DynamicResourceLoader dynamicResourceLoader,
-            SnackbarManager.SnackbarManageable snackbarManageable);
+            SnackbarManager.SnackbarManageable snackbarManageable,
+            ModalDialogManager modalDialogManager);
 
     // TODO(960196): Remove the following interfaces when the associated bug is resolved.
     /**
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java
index 4ef3e00a..0bad646 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java
@@ -36,6 +36,7 @@
 import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
 import org.chromium.chrome.tab_ui.R;
 import org.chromium.components.browser_ui.widget.MenuOrKeyboardActionController;
+import org.chromium.ui.modaldialog.ModalDialogManager;
 import org.chromium.ui.modelutil.LayoutViewBuilder;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
@@ -51,6 +52,16 @@
         implements Destroyable, TabSwitcher, TabSwitcher.TabListDelegate,
                    TabSwitcher.TabDialogDelegation, TabSwitcherMediator.ResetHandler,
                    TabSwitcherMediator.MessageItemsController {
+    /**
+     * Interface to control the IPH dialog.
+     */
+    interface IphController {
+        /**
+         * Show the dialog with IPH.
+         */
+        void showIph();
+    }
+
     // TODO(crbug.com/982018): Rename 'COMPONENT_NAME' so as to add different metrics for carousel
     // tab switcher.
     static final String COMPONENT_NAME = "GridTabSwitcher";
@@ -178,7 +189,8 @@
     @Override
     public void initWithNative(Context context, TabContentManager tabContentManager,
             DynamicResourceLoader dynamicResourceLoader,
-            SnackbarManager.SnackbarManageable snackbarManageable) {
+            SnackbarManager.SnackbarManageable snackbarManageable,
+            ModalDialogManager modalDialogManager) {
         // For tab switcher in carousel mode, the selection editor should still follow grid style.
         int selectionEditorMode = mMode == TabListCoordinator.TabListMode.CAROUSEL
                 ? TabListCoordinator.TabListMode.GRID
@@ -221,9 +233,10 @@
 
             if (TabUiFeatureUtilities.isTabGroupsAndroidEnabled()
                     && !TabSwitcherMediator.isShowingTabsInMRUOrder()) {
-                mTabGridIphDialogCoordinator = new TabGridIphDialogCoordinator(context, mContainer);
+                mTabGridIphDialogCoordinator =
+                        new TabGridIphDialogCoordinator(context, mContainer, modalDialogManager);
                 IphMessageService iphMessageService =
-                        new IphMessageService(mTabGridIphDialogCoordinator.getIphController());
+                        new IphMessageService(mTabGridIphDialogCoordinator);
                 mMessageCardProviderCoordinator.subscribeMessageService(iphMessageService);
             }
         }
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogViewBinderTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogViewBinderTest.java
deleted file mode 100644
index 404ecd5..0000000
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogViewBinderTest.java
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright 2020 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.tasks.tab_management;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.areAnimatorsEnabled;
-
-import android.graphics.drawable.Animatable;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.filters.SmallTest;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.PopupWindow;
-import android.widget.TextView;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import org.chromium.chrome.browser.widget.ScrimView;
-import org.chromium.chrome.tab_ui.R;
-import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.content_public.browser.test.util.TestThreadUtils;
-import org.chromium.ui.modelutil.PropertyModel;
-import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
-import org.chromium.ui.test.util.DummyUiActivityTestCase;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * Tests for {@link TabGridIphDialogViewBinder}.
- */
-@RunWith(ChromeJUnit4ClassRunner.class)
-public class TabGridIphDialogViewBinderTest extends DummyUiActivityTestCase {
-    private TextView mCloseIPHDialogButton;
-    private TabGridIphDialogParent mIphDialogParent;
-    private PopupWindow mIphWindow;
-    private ViewGroup mDialogParentView;
-    private Animatable mIphAnimation;
-
-    private PropertyModel mModel;
-    private PropertyModelChangeProcessor mMCP;
-
-    @Override
-    public void setUpTest() throws Exception {
-        super.setUpTest();
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            ViewGroup parentView = new FrameLayout(getActivity());
-            mIphDialogParent = new TabGridIphDialogParent(getActivity(), parentView);
-            mIphWindow = mIphDialogParent.getIphWindowForTesting();
-            mDialogParentView = (ViewGroup) mIphWindow.getContentView();
-            mCloseIPHDialogButton = mDialogParentView.findViewById(R.id.close_button);
-            mIphAnimation = (Animatable) ((ImageView) mDialogParentView.findViewById(
-                                                  R.id.animation_drawable))
-                                    .getDrawable();
-
-            mModel = new PropertyModel(TabGridIphDialogProperties.ALL_KEYS);
-            mMCP = PropertyModelChangeProcessor.create(
-                    mModel, mIphDialogParent, TabGridIphDialogViewBinder::bind);
-        });
-    }
-
-    @Override
-    public void tearDownTest() throws Exception {
-        mMCP.destroy();
-        super.tearDownTest();
-    }
-
-    @Test
-    @UiThreadTest
-    @SmallTest
-    public void testSetIphDialogCloseButtonListener() {
-        AtomicBoolean iphDialogCloseButtonClicked = new AtomicBoolean();
-        iphDialogCloseButtonClicked.set(false);
-        mCloseIPHDialogButton.performClick();
-        Assert.assertFalse(iphDialogCloseButtonClicked.get());
-
-        mModel.set(TabGridIphDialogProperties.CLOSE_BUTTON_LISTENER,
-                (View view) -> iphDialogCloseButtonClicked.set(true));
-
-        mCloseIPHDialogButton.performClick();
-        Assert.assertTrue(iphDialogCloseButtonClicked.get());
-    }
-
-    @Test
-    @UiThreadTest
-    @SmallTest
-    public void testSetIphDialogVisibility() {
-        assertFalse(mIphWindow.isShowing());
-        assertFalse(mIphAnimation.isRunning());
-
-        mModel.set(TabGridIphDialogProperties.IS_VISIBLE, true);
-
-        assertTrue(mIphWindow.isShowing());
-        if (areAnimatorsEnabled()) {
-            assertTrue(mIphAnimation.isRunning());
-        }
-
-        mModel.set(TabGridIphDialogProperties.IS_VISIBLE, false);
-
-        assertFalse(mIphWindow.isShowing());
-        if (areAnimatorsEnabled()) {
-            assertFalse(mIphAnimation.isRunning());
-        }
-    }
-
-    @Test
-    @UiThreadTest
-    @SmallTest
-    public void testSetScrimViewObserver() {
-        AtomicBoolean iphDialogScrimViewClicked = new AtomicBoolean();
-        iphDialogScrimViewClicked.set(false);
-        ScrimView.ScrimObserver observer = new ScrimView.ScrimObserver() {
-            @Override
-            public void onScrimClick() {
-                iphDialogScrimViewClicked.set(true);
-            }
-
-            @Override
-            public void onScrimVisibilityChanged(boolean visible) {}
-        };
-
-        mModel.set(TabGridIphDialogProperties.SCRIM_VIEW_OBSERVER, observer);
-        mModel.set(TabGridIphDialogProperties.IS_VISIBLE, true);
-
-        assertTrue(mDialogParentView.getChildAt(0) instanceof ScrimView);
-        ScrimView scrimView = (ScrimView) mDialogParentView.getChildAt(0);
-        scrimView.performClick();
-        assertTrue(iphDialogScrimViewClicked.get());
-    }
-}
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphTest.java
index 27da5c99..d45c76a 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphTest.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.tasks.tab_management;
 
 import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.Espresso.pressBack;
 import static android.support.test.espresso.action.ViewActions.click;
 import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
 import static android.support.test.espresso.assertion.ViewAssertions.matches;
@@ -12,6 +13,7 @@
 import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
 import static android.support.test.espresso.matcher.ViewMatchers.withId;
 import static android.support.test.espresso.matcher.ViewMatchers.withParent;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
 
 import static org.hamcrest.CoreMatchers.allOf;
 import static org.hamcrest.Matchers.not;
@@ -19,7 +21,6 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.clickScrimToExitDialog;
 import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.closeFirstTabInTabSwitcher;
 import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.enterTabSwitcher;
 import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.getSwipeToDismissAction;
@@ -32,6 +33,8 @@
 import android.support.test.espresso.NoMatchingRootException;
 import android.support.test.espresso.contrib.RecyclerViewActions;
 import android.support.test.filters.MediumTest;
+import android.support.test.uiautomator.UiDevice;
+import android.view.View;
 import android.widget.TextView;
 
 import androidx.recyclerview.widget.RecyclerView;
@@ -58,6 +61,8 @@
 import org.chromium.chrome.test.util.ChromeTabUtils;
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
+import org.chromium.ui.modaldialog.ModalDialogManager;
+import org.chromium.ui.modaldialog.ModalDialogProperties;
 import org.chromium.ui.test.util.UiRestriction;
 
 import java.io.IOException;
@@ -121,10 +126,27 @@
                 .perform(click());
         verifyIphDialogShowing(cta);
 
-        // Exit by clicking the scrim view.
-        clickScrimToExitDialog(cta);
+        // Press back should dismiss the IPH dialog.
+        pressBack();
         verifyIphDialogHiding(cta);
         onView(withId(R.id.tab_grid_message_item)).check(matches(isDisplayed()));
+
+        // Check the IPH message card is showing and open the IPH dialog.
+        onView(withId(R.id.tab_grid_message_item)).check(matches(isDisplayed()));
+        onView(allOf(withId(R.id.action_button), withParent(withId(R.id.tab_grid_message_item))))
+                .perform(click());
+        verifyIphDialogShowing(cta);
+
+        // Click outside of the dialog area to close the IPH dialog.
+        ModalDialogManager manager = cta.getModalDialogManager();
+        View dialogView = manager.getCurrentDialogForTest().get(ModalDialogProperties.CUSTOM_VIEW);
+        int[] location = new int[2];
+        // Get the position of the dialog view and click slightly above so that we essentially click
+        // on the scrim.
+        dialogView.getLocationOnScreen(location);
+        UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
+                .click(location[0], location[1] / 2);
+        verifyIphDialogHiding(cta);
     }
 
     @Test
@@ -240,6 +262,7 @@
     }
 
     private void verifyIphDialogShowing(ChromeTabbedActivity cta) {
+        // Verify IPH dialog view.
         onView(withId(R.id.iph_dialog))
                 .inRoot(withDecorView(not(cta.getWindow().getDecorView())))
                 .check((v, noMatchException) -> {
@@ -251,11 +274,11 @@
                     String description = cta.getString(R.string.iph_drag_and_drop_content);
                     assertEquals(
                             description, ((TextView) v.findViewById(R.id.description)).getText());
-
-                    String closeButtonText = cta.getString(R.string.ok);
-                    assertEquals(closeButtonText,
-                            ((TextView) v.findViewById(R.id.close_button)).getText());
                 });
+        // Verify ModalDialog button.
+        onView(withId(R.id.positive_button))
+                .inRoot(withDecorView(not(cta.getWindow().getDecorView())))
+                .check(matches(withText(cta.getString(R.string.ok))));
     }
 
     private void verifyIphDialogHiding(ChromeTabbedActivity cta) {
@@ -273,7 +296,7 @@
     }
 
     private void exitIphDialogByClickingButton(ChromeTabbedActivity cta) {
-        onView(withId(R.id.close_button))
+        onView(withId(R.id.positive_button))
                 .inRoot(withDecorView(not(cta.getWindow().getDecorView())))
                 .perform(click());
     }
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogMediatorUnitTest.java
deleted file mode 100644
index 26a693a..0000000
--- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogMediatorUnitTest.java
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2020 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.tasks.tab_management;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import android.view.View;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestRule;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.annotation.Config;
-
-import org.chromium.base.metrics.RecordHistogram;
-import org.chromium.chrome.browser.widget.ScrimView;
-import org.chromium.chrome.test.util.browser.Features;
-import org.chromium.testing.local.LocalRobolectricTestRunner;
-import org.chromium.ui.modelutil.PropertyModel;
-
-/**
- * Tests for {@link TabGridDialogMediator}.
- */
-@RunWith(LocalRobolectricTestRunner.class)
-@Config(manifest = Config.NONE)
-public class TabGridIphDialogMediatorUnitTest {
-    @Rule
-    public TestRule mProcessor = new Features.JUnitProcessor();
-
-    @Mock
-    View mView;
-
-    private PropertyModel mModel;
-    private TabGridIphDialogMediator mMediator;
-
-    @Before
-    public void setUp() {
-        RecordHistogram.setDisabledForTests(true);
-
-        MockitoAnnotations.initMocks(this);
-
-        mModel = new PropertyModel(TabGridIphDialogProperties.ALL_KEYS);
-        mMediator = new TabGridIphDialogMediator(mModel);
-    }
-
-    @After
-    public void tearDown() {
-        RecordHistogram.setDisabledForTests(false);
-    }
-
-    @Test
-    public void testCloseIphDialogButtonListener() {
-        View.OnClickListener listener =
-                mModel.get(TabGridIphDialogProperties.CLOSE_BUTTON_LISTENER);
-        assertNotNull(listener);
-        mModel.set(TabGridIphDialogProperties.IS_VISIBLE, true);
-
-        listener.onClick(mView);
-        assertFalse(mModel.get(TabGridIphDialogProperties.IS_VISIBLE));
-    }
-
-    @Test
-    public void testScrimViewObserver() {
-        ScrimView.ScrimObserver observer =
-                mModel.get(TabGridIphDialogProperties.SCRIM_VIEW_OBSERVER);
-        assertNotNull(observer);
-        mModel.set(TabGridIphDialogProperties.IS_VISIBLE, true);
-
-        observer.onScrimClick();
-        assertFalse(mModel.get(TabGridIphDialogProperties.IS_VISIBLE));
-    }
-
-    @Test
-    public void testShowIph() {
-        mModel.set(TabGridIphDialogProperties.IS_VISIBLE, false);
-
-        mMediator.showIph();
-        assertTrue(mModel.get(TabGridIphDialogProperties.IS_VISIBLE));
-    }
-}
diff --git a/chrome/android/features/tab_ui/tab_management_java_sources.gni b/chrome/android/features/tab_ui/tab_management_java_sources.gni
index 57a3115..91049a1 100644
--- a/chrome/android/features/tab_ui/tab_management_java_sources.gni
+++ b/chrome/android/features/tab_ui/tab_management_java_sources.gni
@@ -36,7 +36,6 @@
   "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridAccessibilityHelperTest.java",
   "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogParentTest.java",
   "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java",
-  "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogViewBinderTest.java",
   "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphTest.java",
   "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelViewBinderTest.java",
   "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupPopupUiTest.java",
@@ -63,7 +62,6 @@
   "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_groups/TabGroupUtilsUnitTest.java",
   "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/MessageCardProviderMediatorUnitTest.java",
   "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediatorUnitTest.java",
-  "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphDialogMediatorUnitTest.java",
   "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridItemTouchHelperCallbackUnitTest.java",
   "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupPopupUiMediatorUnitTest.java",
   "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupTitleEditorUnitTest.java",
diff --git a/chrome/android/features/vr/BUILD.gn b/chrome/android/features/vr/BUILD.gn
index ac1da8c9..56cb5bb 100644
--- a/chrome/android/features/vr/BUILD.gn
+++ b/chrome/android/features/vr/BUILD.gn
@@ -79,6 +79,7 @@
     "//chrome/browser/util:java",
     "//components/browser_ui/modaldialog/android:java",
     "//components/embedder_support/android:content_view_java",
+    "//components/external_intents/android:java",
     "//components/infobars/core:infobar_enums_java",
     "//components/policy/android:policy_java",
     "//content/public/android:content_java",
diff --git a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShell.java b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShell.java
index 39a42eb4..019bbb1 100644
--- a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShell.java
+++ b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShell.java
@@ -49,7 +49,6 @@
 import org.chromium.chrome.browser.tab.TabCreationState;
 import org.chromium.chrome.browser.tab.TabLaunchType;
 import org.chromium.chrome.browser.tab.TabObserver;
-import org.chromium.chrome.browser.tab.TabRedirectHandler;
 import org.chromium.chrome.browser.tabmodel.ChromeTabCreator;
 import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver;
 import org.chromium.chrome.browser.tabmodel.TabCreatorManager.TabCreator;
@@ -60,6 +59,7 @@
 import org.chromium.chrome.browser.toolbar.NewTabButton;
 import org.chromium.chrome.browser.util.VoiceRecognitionUtil;
 import org.chromium.chrome.browser.vr.keyboard.VrInputMethodManagerWrapper;
+import org.chromium.components.external_intents.RedirectHandlerImpl;
 import org.chromium.content_public.browser.ImeAdapter;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
@@ -92,7 +92,7 @@
     private final VrCompositorSurfaceManager mVrCompositorSurfaceManager;
     private final VrShellDelegate mDelegate;
     private final VirtualDisplayAndroid mContentVirtualDisplay;
-    private final TabRedirectHandler mTabRedirectHandler;
+    private final RedirectHandlerImpl mRedirectHandler;
     private final TabObserver mTabObserver;
     private final TabModelSelectorObserver mTabModelSelectorObserver;
     private final View.OnTouchListener mTouchListener;
@@ -114,7 +114,7 @@
 
     private boolean mReprojectedRendering;
 
-    private TabRedirectHandler mNonVrTabRedirectHandler;
+    private RedirectHandlerImpl mNonVrRedirectHandler;
     private UiWidgetFactory mNonVrUiWidgetFactory;
 
     private TabModelSelector mTabModelSelector;
@@ -232,7 +232,7 @@
         mNonVrUiWidgetFactory = UiWidgetFactory.getInstance();
         UiWidgetFactory.setInstance(new VrUiWidgetFactory(this, mActivity.getModalDialogManager()));
 
-        mTabRedirectHandler = new TabRedirectHandler() {
+        mRedirectHandler = new RedirectHandlerImpl() {
             @Override
             public boolean shouldStayInApp(boolean hasExternalProtocol) {
                 return !hasExternalProtocol;
@@ -511,16 +511,15 @@
     private void initializeTabForVR() {
         if (mTab == null) return;
         // Make sure we are not redirecting to another app, i.e. out of VR mode.
-        mNonVrTabRedirectHandler =
-                RedirectHandlerTabHelper.swapHandlerFor(mTab, mTabRedirectHandler);
+        mNonVrRedirectHandler = RedirectHandlerTabHelper.swapHandlerFor(mTab, mRedirectHandler);
         assert mTab.getWindowAndroid() == mContentVrWindowAndroid;
         configWebContentsImeForVr(mTab.getWebContents());
     }
 
     private void restoreTabFromVR() {
         if (mTab == null) return;
-        RedirectHandlerTabHelper.swapHandlerFor(mTab, mNonVrTabRedirectHandler);
-        mNonVrTabRedirectHandler = null;
+        RedirectHandlerTabHelper.swapHandlerFor(mTab, mNonVrRedirectHandler);
+        mNonVrRedirectHandler = null;
         restoreWebContentsImeFromVr(mTab.getWebContents());
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/splashscreen/TwaSplashController.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/splashscreen/TwaSplashController.java
index 425002f..449d7f0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/splashscreen/TwaSplashController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/splashscreen/TwaSplashController.java
@@ -125,8 +125,7 @@
     }
 
     @Override
-    public void onSplashHidden(Tab tab, @SplashController.SplashHidesReason int reason,
-            long startTimestamp, long endTimestamp) {
+    public void onSplashHidden(Tab tab, long startTimestamp, long endTimestamp) {
         mLifecycleDispatcher.unregister(this); // Unregister to get gc-ed
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
index b15d6239..20c08bc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
@@ -45,7 +45,6 @@
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabCreationState;
 import org.chromium.chrome.browser.tab.TabLaunchType;
-import org.chromium.chrome.browser.tab.TabRedirectHandler;
 import org.chromium.chrome.browser.tab.TabSelectionType;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabModelObserver;
@@ -54,6 +53,7 @@
 import org.chromium.components.external_intents.ExternalNavigationHandler;
 import org.chromium.components.external_intents.ExternalNavigationHandler.OverrideUrlLoadingResult;
 import org.chromium.components.external_intents.ExternalNavigationParams;
+import org.chromium.components.external_intents.RedirectHandlerImpl;
 import org.chromium.components.feature_engagement.EventConstants;
 import org.chromium.components.feature_engagement.FeatureConstants;
 import org.chromium.components.feature_engagement.Tracker;
@@ -156,7 +156,7 @@
     private long mNativeContextualSearchManagerPtr;
 
     private ViewGroup mParentView;
-    private TabRedirectHandler mTabRedirectHandler;
+    private RedirectHandlerImpl mRedirectHandler;
     private OverlayPanelContentViewDelegate mSearchContentViewDelegate;
     private TabModelSelectorTabModelObserver mTabModelObserver;
     private TabModelSelectorTabObserver mTabModelSelectorTabObserver;
@@ -277,7 +277,7 @@
 
         mInProductHelp.setParentView(parentView);
 
-        mTabRedirectHandler = TabRedirectHandler.create();
+        mRedirectHandler = RedirectHandlerImpl.create();
 
         mIsShowingPromo = false;
         mDidLogPromoOutcome = false;
@@ -303,7 +303,7 @@
         mParentView.getViewTreeObserver().removeOnGlobalFocusChangeListener(mOnFocusChangeListener);
         ContextualSearchManagerJni.get().destroy(mNativeContextualSearchManagerPtr, this);
         stopListeningForHideNotifications();
-        mTabRedirectHandler.clear();
+        mRedirectHandler.clear();
         mInternalStateController.enter(InternalState.UNDEFINED);
         AccessibilityUtil.removeObserver(this);
     }
@@ -1069,17 +1069,18 @@
         public boolean shouldInterceptNavigation(
                 ExternalNavigationHandler externalNavHandler, NavigationParams navigationParams) {
             assert mSearchPanel != null;
-            mTabRedirectHandler.updateNewUrlLoading(navigationParams.pageTransitionType,
+            mRedirectHandler.updateNewUrlLoading(navigationParams.pageTransitionType,
                     navigationParams.isRedirect,
                     navigationParams.hasUserGesture || navigationParams.hasUserGestureCarryover,
-                    mActivity.getLastUserInteractionTime(), TabRedirectHandler.INVALID_ENTRY_INDEX);
+                    mActivity.getLastUserInteractionTime(),
+                    RedirectHandlerImpl.INVALID_ENTRY_INDEX);
             ExternalNavigationParams params =
                     new ExternalNavigationParams
                             .Builder(navigationParams.url, false, navigationParams.referrer,
                                     navigationParams.pageTransitionType,
                                     navigationParams.isRedirect)
                             .setApplicationMustBeInForeground(true)
-                            .setRedirectHandler(mTabRedirectHandler)
+                            .setRedirectHandler(mRedirectHandler)
                             .setIsMainFrame(navigationParams.isMainFrame)
                             .build();
             if (externalNavHandler.shouldOverrideUrlLoading(params)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java
index 2752ebc3..33673e6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java
@@ -49,13 +49,13 @@
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabImpl;
 import org.chromium.chrome.browser.tab.TabObserver;
-import org.chromium.chrome.browser.tab.TabRedirectHandler;
 import org.chromium.components.embedder_support.util.UrlConstants;
 import org.chromium.components.embedder_support.util.UrlUtilities;
 import org.chromium.components.embedder_support.util.UrlUtilitiesJni;
 import org.chromium.components.external_intents.ExternalNavigationDelegate;
 import org.chromium.components.external_intents.ExternalNavigationHandler.OverrideUrlLoadingResult;
 import org.chromium.components.external_intents.ExternalNavigationParams;
+import org.chromium.components.external_intents.RedirectHandlerImpl;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.NavigationController;
 import org.chromium.content_public.browser.NavigationEntry;
@@ -635,7 +635,7 @@
         if (!hasValidTab() || mTab.getWebContents() == null) return false;
 
         InstantAppsHandler handler = InstantAppsHandler.getInstance();
-        TabRedirectHandler redirect = RedirectHandlerTabHelper.getHandlerFor(mTab);
+        RedirectHandlerImpl redirect = RedirectHandlerTabHelper.getHandlerFor(mTab);
         Intent intent = redirect != null ? redirect.getInitialIntent() : null;
         // TODO(mariakhomenko): consider also handling NDEF_DISCOVER action redirects.
         if (isIncomingRedirect && intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
index e3523f6c..8c71d8a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
@@ -82,6 +82,7 @@
 import org.chromium.components.background_task_scheduler.BackgroundTaskSchedulerFactory;
 import org.chromium.components.browser_ui.util.ConversionUtils;
 import org.chromium.components.minidump_uploader.CrashFileManager;
+import org.chromium.components.signin.AccountManagerFacade;
 import org.chromium.components.signin.AccountManagerFacadeProvider;
 import org.chromium.components.signin.AccountsChangeObserver;
 import org.chromium.components.viz.common.VizSwitches;
@@ -164,8 +165,8 @@
         // Initialize the AccountManagerFacade with the correct AccountManagerDelegate. Must be done
         // only once and before AccountMangerHelper.get(...) is called to avoid using the
         // default AccountManagerDelegate.
-        AccountManagerFacadeProvider.initializeAccountManagerFacade(
-                AppHooks.get().createAccountManagerDelegate());
+        AccountManagerFacadeProvider.setInstance(
+                new AccountManagerFacade(AppHooks.get().createAccountManagerDelegate()));
 
         // Set the unique identification generator for invalidations.  The
         // invalidations system can start and attempt to fetch the client ID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java
index f4a15c5..4636b1c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java
@@ -9,7 +9,6 @@
 import android.os.Environment;
 import android.os.StatFs;
 import android.provider.Settings;
-import android.text.format.DateUtils;
 
 import androidx.annotation.IntDef;
 
@@ -29,7 +28,6 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.HashSet;
 import java.util.Set;
-import java.util.concurrent.TimeUnit;
 
 /**
  * Centralizes UMA data collection for WebAPKs. NOTE: Histogram names and values are defined in
@@ -267,16 +265,6 @@
         }
     }
 
-    /**
-     * Recorded when a WebAPK is launched from the homescreen. Records the time elapsed since the
-     * previous WebAPK launch. Not recorded the first time that a WebAPK is launched.
-     */
-    public static void recordLaunchInterval(long intervalMs) {
-        RecordHistogram.recordCustomCountHistogram("WebApk.LaunchInterval2",
-                (int) (DateUtils.MINUTE_IN_MILLIS * intervalMs), 30,
-                (int) TimeUnit.DAYS.toMinutes(90), 50);
-    }
-
     /** Records to UMA the count of old "WebAPK update request" files. */
     public static void recordNumberOfStaleWebApkUpdateRequestFiles(int count) {
         RecordHistogram.recordCountHistogram("WebApk.Update.NumStaleUpdateRequestFiles", count);
@@ -297,10 +285,8 @@
      * @param isChildTab Whether {@link Tab#getParentId()} is non-empty.
      * @param isNavigationInScope
      */
-    public static void recordNavigation(boolean isChildTab, boolean isNavigationInScope) {
-        RecordHistogram.recordBooleanHistogram(
-                isChildTab ? "WebApk.Navigation.ChildTab.InScope" : "WebApk.Navigation.InScope",
-                isNavigationInScope);
+    public static void recordNavigation(boolean isNavigationInScope) {
+        RecordHistogram.recordBooleanHistogram("WebApk.Navigation.InScope", isNavigationInScope);
     }
 
     /**
@@ -329,9 +315,6 @@
         RecordHistogram.recordSparseHistogram(
                 "WebApk.Install.AvailableSpace.Fail", roundByteToMb(spaceSize));
 
-        RecordHistogram.recordSparseHistogram(
-                "WebApk.Install.ChromeCacheSize.Fail", roundByteToMb(cacheSize));
-
         RecordHistogram.recordSparseHistogram("WebApk.Install.AvailableSpaceAfterFreeUpCache.Fail",
                 roundByteToMb(spaceSize + cacheSize));
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateImpl.java
index 6058a35d..d77f044 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateImpl.java
@@ -18,6 +18,7 @@
 import org.chromium.components.external_intents.ExternalNavigationHandler;
 import org.chromium.components.external_intents.ExternalNavigationHandler.OverrideUrlLoadingResult;
 import org.chromium.components.external_intents.ExternalNavigationParams;
+import org.chromium.components.external_intents.RedirectHandlerImpl;
 import org.chromium.components.navigation_interception.InterceptNavigationDelegate;
 import org.chromium.components.navigation_interception.NavigationParams;
 import org.chromium.content_public.browser.NavigationController;
@@ -149,9 +150,9 @@
             return true;
         }
 
-        TabRedirectHandler tabRedirectHandler = null;
+        RedirectHandlerImpl redirectHandler = null;
         if (navigationParams.isMainFrame) {
-            tabRedirectHandler = RedirectHandlerTabHelper.getOrCreateHandlerFor(mTab);
+            redirectHandler = RedirectHandlerTabHelper.getOrCreateHandlerFor(mTab);
         } else if (navigationParams.isExternalProtocol) {
             // Only external protocol navigations are intercepted for iframe navigations.  Since
             // we do not see all previous navigations for the iframe, we can not build a complete
@@ -163,20 +164,20 @@
             // not covering the case where a gesture is carried over via a redirect.  This is
             // currently not feasible because we do not see all navigations for iframes and it is
             // better to error on the side of caution and require direct user gestures for iframes.
-            tabRedirectHandler = TabRedirectHandler.create();
+            redirectHandler = RedirectHandlerImpl.create();
         } else {
             assert false;
             return false;
         }
-        tabRedirectHandler.updateNewUrlLoading(navigationParams.pageTransitionType,
+        redirectHandler.updateNewUrlLoading(navigationParams.pageTransitionType,
                 navigationParams.isRedirect,
                 navigationParams.hasUserGesture || navigationParams.hasUserGestureCarryover,
                 lastUserInteractionTime, getLastCommittedEntryIndex());
 
         boolean shouldCloseTab = shouldCloseContentsOnOverrideUrlLoadingAndLaunchIntent();
-        ExternalNavigationParams params = buildExternalNavigationParams(navigationParams,
-                tabRedirectHandler,
-                shouldCloseTab).build();
+        ExternalNavigationParams params =
+                buildExternalNavigationParams(navigationParams, redirectHandler, shouldCloseTab)
+                        .build();
         @OverrideUrlLoadingResult
         int result = mExternalNavHandler.shouldOverrideUrlLoading(params);
         mLastOverrideUrlLoadingResult = result;
@@ -213,7 +214,7 @@
      * ExternalNavigationHandler#shouldOverrideUrlLoading().
      */
     public ExternalNavigationParams.Builder buildExternalNavigationParams(
-            NavigationParams navigationParams, TabRedirectHandler tabRedirectHandler,
+            NavigationParams navigationParams, RedirectHandlerImpl redirectHandler,
             boolean shouldCloseTab) {
         boolean isInitialTabLaunchInBackground =
                 mTab.getLaunchType() == TabLaunchType.FROM_LONGPRESS_BACKGROUND && shouldCloseTab;
@@ -223,7 +224,7 @@
                 .Builder(navigationParams.url, mTab.isIncognito(), navigationParams.referrer,
                         navigationParams.pageTransitionType, navigationParams.isRedirect)
                 .setApplicationMustBeInForeground(true)
-                .setRedirectHandler(tabRedirectHandler)
+                .setRedirectHandler(redirectHandler)
                 .setOpenInNewTab(shouldCloseTab)
                 .setIsBackgroundTabNavigation(mTab.isHidden() && !isInitialTabLaunchInBackground)
                 .setIsMainFrame(navigationParams.isMainFrame)
@@ -281,7 +282,7 @@
         if (RedirectHandlerTabHelper.getOrCreateHandlerFor(mTab).isOnNavigation()) {
             return RedirectHandlerTabHelper.getOrCreateHandlerFor(mTab)
                            .getLastCommittedEntryIndexBeforeStartingNavigation()
-                    == TabRedirectHandler.INVALID_ENTRY_INDEX;
+                    == RedirectHandlerImpl.INVALID_ENTRY_INDEX;
         }
         return false;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/RedirectHandlerTabHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/RedirectHandlerTabHelper.java
index 61d3966a..6833684 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/RedirectHandlerTabHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/RedirectHandlerTabHelper.java
@@ -14,6 +14,7 @@
 import org.chromium.chrome.browser.LaunchIntentDispatcher;
 import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.components.external_intents.RedirectHandlerImpl;
 
 /**
  * This class glues RedirectHandler instances to Tabs.
@@ -22,16 +23,16 @@
     private static final Class<RedirectHandlerTabHelper> USER_DATA_KEY =
             RedirectHandlerTabHelper.class;
 
-    private TabRedirectHandler mRedirectHandler;
+    private RedirectHandlerImpl mRedirectHandler;
 
     /**
-     * Returns {@link TabRedirectHandler} that hangs on to a given {@link Tab}.
+     * Returns {@link RedirectHandlerImpl} that hangs on to a given {@link Tab}.
      * If not present, creates a new instance and associate it with the {@link UserDataHost}
      * that the {@link Tab} manages.
-     * @param tab Tab instance that the TabRedirectHandler hangs on to.
-     * @return TabRedirectHandler for a given Tab.
+     * @param tab Tab instance that the RedirectHandlerImpl hangs on to.
+     * @return RedirectHandlerImpl for a given Tab.
      */
-    public static TabRedirectHandler getOrCreateHandlerFor(Tab tab) {
+    public static RedirectHandlerImpl getOrCreateHandlerFor(Tab tab) {
         UserDataHost host = tab.getUserDataHost();
         RedirectHandlerTabHelper helper = host.getUserData(USER_DATA_KEY);
         if (helper == null) {
@@ -43,22 +44,22 @@
     }
 
     /**
-     * @return {@link TabRedirectHandler} hanging to the given {@link Tab},
+     * @return {@link RedirectHandlerImpl} hanging to the given {@link Tab},
      *     or {@code null} if there is no instance available.
      */
     @Nullable
-    public static TabRedirectHandler getHandlerFor(Tab tab) {
+    public static RedirectHandlerImpl getHandlerFor(Tab tab) {
         RedirectHandlerTabHelper helper = tab.getUserDataHost().getUserData(USER_DATA_KEY);
         if (helper == null) return null;
         return helper.mRedirectHandler;
     }
 
     /**
-     * Replace {@link TabRedirectHandler} instance for the Tab with the new one.
-     * @return Old {@link TabRedirectHandler} associated with the Tab. Could be {@code null}.
+     * Replace {@link RedirectHandlerImpl} instance for the Tab with the new one.
+     * @return Old {@link RedirectHandlerImpl} associated with the Tab. Could be {@code null}.
      */
-    public static TabRedirectHandler swapHandlerFor(
-            Tab tab, @Nullable TabRedirectHandler newHandler) {
+    public static RedirectHandlerImpl swapHandlerFor(
+            Tab tab, @Nullable RedirectHandlerImpl newHandler) {
         UserDataHost host = tab.getUserDataHost();
         RedirectHandlerTabHelper oldHelper = host.getUserData(USER_DATA_KEY);
         if (newHandler != null) {
@@ -73,10 +74,10 @@
     }
 
     private RedirectHandlerTabHelper() {
-        mRedirectHandler = new TabRedirectHandler();
+        mRedirectHandler = RedirectHandlerImpl.create();
     }
 
-    private RedirectHandlerTabHelper(TabRedirectHandler handler) {
+    private RedirectHandlerTabHelper(RedirectHandlerImpl handler) {
         mRedirectHandler = handler;
     }
 
@@ -86,7 +87,7 @@
     }
 
     /**
-     * Wrapper around TabRedirectHandler#updateIntent() that supplies //chrome-level params.
+     * Wrapper around RedirectHandlerImpl#updateIntent() that supplies //chrome-level params.
      */
     public static void updateIntentInTab(Tab tab, Intent intent) {
         RedirectHandlerTabHelper.getOrCreateHandlerFor(tab).updateIntent(intent,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/SplashController.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/SplashController.java
index 6c8de936f..0bbc6bc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/SplashController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/SplashController.java
@@ -70,16 +70,12 @@
         }
     };
 
-    // SplashHidesReason defined in tools/metrics/histograms/enums.xml.
-    @IntDef({SplashHidesReason.PAINT, SplashHidesReason.LOAD_FINISHED,
-            SplashHidesReason.LOAD_FAILED, SplashHidesReason.CRASH})
+    @IntDef({SplashHidesReason.OTHER, SplashHidesReason.LOAD_FAILED, SplashHidesReason.CRASH})
     @Retention(RetentionPolicy.SOURCE)
     public @interface SplashHidesReason {
-        int PAINT = 0;
-        int LOAD_FINISHED = 1;
-        int LOAD_FAILED = 2;
-        int CRASH = 3;
-        int NUM_ENTRIES = 4;
+        int OTHER = 0;
+        int LOAD_FAILED = 1;
+        int CRASH = 2;
     }
 
     @IntDef({TranslucencyRemoval.NONE, TranslucencyRemoval.ON_SPLASH_SHOWN,
@@ -203,14 +199,14 @@
     @Override
     public void didFirstVisuallyNonEmptyPaint(Tab tab) {
         if (canHideSplashScreen()) {
-            hideSplash(tab, SplashHidesReason.PAINT);
+            hideSplash(tab, SplashHidesReason.OTHER);
         }
     }
 
     @Override
     public void onPageLoadFinished(Tab tab, String url) {
         if (canHideSplashScreen()) {
-            hideSplash(tab, SplashHidesReason.LOAD_FINISHED);
+            hideSplash(tab, SplashHidesReason.OTHER);
         }
     }
 
@@ -302,14 +298,14 @@
         }
 
         if (reason == SplashHidesReason.LOAD_FAILED || reason == SplashHidesReason.CRASH) {
-            animateHideSplash(tab, reason);
+            animateHideSplash(tab);
             return;
         }
         // Delay hiding the splash screen till the compositor has finished drawing the next frame.
         // Without this callback we were seeing a short flash of white between the splash screen and
         // the web content (crbug.com/734500).
         CompositorView compositorView = mActivity.getCompositorViewHolder().getCompositorView();
-        compositorView.surfaceRedrawNeededAsync(() -> { animateHideSplash(tab, reason); });
+        compositorView.surfaceRedrawNeededAsync(() -> { animateHideSplash(tab); });
     }
 
     private void removeTranslucency() {
@@ -330,7 +326,7 @@
         notifyTranslucencyRemoved();
     }
 
-    private void animateHideSplash(final Tab tab, final @SplashHidesReason int reason) {
+    private void animateHideSplash(final Tab tab) {
         if (mWasSplashHideAnimationStarted) return;
 
         mWasSplashHideAnimationStarted = true;
@@ -342,23 +338,23 @@
         mActivity.findViewById(R.id.coordinator).setVisibility(View.VISIBLE);
 
         if (mSplashHideAnimationDurationMs == 0) {
-            hideSplashNow(tab, reason);
+            hideSplashNow(tab);
             return;
         }
         mFadeOutAnimator = mSplashView.animate()
                                    .alpha(0f)
                                    .setDuration(mSplashHideAnimationDurationMs)
-                                   .withEndAction(() -> { hideSplashNow(tab, reason); });
+                                   .withEndAction(() -> { hideSplashNow(tab); });
     }
 
-    private void hideSplashNow(Tab tab, @SplashHidesReason int reason) {
+    private void hideSplashNow(Tab tab) {
         mParentView.removeView(mSplashView);
 
         long splashHiddenTimestamp = SystemClock.elapsedRealtime();
         recordTraceEventsFinishedHidingSplash();
 
         assert mSplashShownTimestamp != 0;
-        mDelegate.onSplashHidden(tab, reason, mSplashShownTimestamp, splashHiddenTimestamp);
+        mDelegate.onSplashHidden(tab, mSplashShownTimestamp, splashHiddenTimestamp);
         notifySplashscreenHidden(mSplashShownTimestamp, splashHiddenTimestamp);
 
         mFinishHandler.setShouldAttemptFinishingTask(false);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/SplashDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/SplashDelegate.java
index 42f28e9..63a47b5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/SplashDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/SplashDelegate.java
@@ -16,12 +16,10 @@
     /**
      * Called when splash screen has been hidden.
      * @param tab
-     * @param reason Reason that the splash screen was hidden.
      * @param startTimestamp Time that the splash screen was shown.
      * @param endTimestap Time that the splash screen was hidden.
      */
-    void onSplashHidden(Tab tab, @SplashController.SplashHidesReason int reason,
-            long startTimestamp, long endTimestamp);
+    void onSplashHidden(Tab tab, long startTimestamp, long endTimestamp);
 
     /** Returns whether to wait for a subsequent page load to hide the splash screen. */
     boolean shouldWaitForSubsequentPageLoadToHideSplash();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActiveTabUmaTracker.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActiveTabUmaTracker.java
index dbd4efb..12456aba 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActiveTabUmaTracker.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActiveTabUmaTracker.java
@@ -42,12 +42,11 @@
             RecordHistogram.recordBooleanHistogram(
                     HISTOGRAM_NAVIGATION_STATUS, !navigation.isErrorPage());
 
-            if (mIntentDataProvider.isWebApkActivity()) {
+            if (mIntentDataProvider.isWebApkActivity() && tab.getParentId() == Tab.INVALID_TAB_ID) {
                 VerificationState verificationState = mCurrentPageVerifier.getState();
                 boolean isNavigationInScope = (verificationState == null
                         || verificationState.status != VerificationStatus.FAILURE);
-                boolean isChildTab = (tab.getParentId() != Tab.INVALID_TAB_ID);
-                WebApkUma.recordNavigation(isChildTab, isNavigationInScope);
+                WebApkUma.recordNavigation(isNavigationInScope);
             }
         }
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappSplashDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappSplashDelegate.java
index 3937c2a..9f253b190 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappSplashDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappSplashDelegate.java
@@ -17,7 +17,6 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.FileUtils;
 import org.chromium.base.StrictModeContext;
-import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.browser.customtabs.content.TabObserverRegistrar;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.ui.util.ColorUtils;
@@ -27,7 +26,6 @@
 /** Delegate for splash screen for webapps and WebAPKs. */
 public class WebappSplashDelegate implements SplashDelegate {
     public static final int HIDE_ANIMATION_DURATION_MS = 300;
-    public static final String HISTOGRAM_SPLASHSCREEN_HIDES = "Webapp.Splashscreen.Hides";
 
     private TabObserverRegistrar mTabObserverRegistrar;
 
@@ -59,16 +57,12 @@
     }
 
     @Override
-    public void onSplashHidden(Tab tab, @SplashController.SplashHidesReason int reason,
-            long startTimestamp, long endTimestamp) {
+    public void onSplashHidden(Tab tab, long startTimestamp, long endTimestamp) {
         if (mWebApkNetworkErrorObserver != null) {
             mTabObserverRegistrar.unregisterTabObserver(mWebApkNetworkErrorObserver);
             tab.removeObserver(mWebApkNetworkErrorObserver);
             mWebApkNetworkErrorObserver = null;
         }
-
-        RecordHistogram.recordEnumeratedHistogram(HISTOGRAM_SPLASHSCREEN_HIDES, reason,
-                SplashController.SplashHidesReason.NUM_ENTRIES);
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java
index cfdc303..837fbad 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java
@@ -308,11 +308,9 @@
         openBookmarkManager();
         Assert.assertTrue("Grid view does not contain added bookmark: ",
                 isItemPresentInBookmarkList(TEST_PAGE_TITLE_GOOGLE));
-        final View tile = getViewWithText(mItemsContainer, TEST_PAGE_TITLE_GOOGLE);
-        ChromeTabUtils.waitForTabPageLoaded(mActivityTestRule.getActivity().getActivityTab(),
-                mTestPage, () -> TouchCommon.singleClickView(tile));
-        Assert.assertEquals(TEST_PAGE_TITLE_GOOGLE,
-                mActivityTestRule.getActivity().getActivityTab().getTitle());
+        final View title = getViewWithText(mItemsContainer, TEST_PAGE_TITLE_GOOGLE);
+        ChromeTabUtils.waitForTabPageLoadStart(mActivityTestRule.getActivity().getActivityTab(),
+                mTestPage, () -> TouchCommon.singleClickView(title));
     }
 
     @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
index 4e96e19..3bd6621 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
@@ -33,11 +33,11 @@
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.DisableIf;
-import org.chromium.chrome.browser.tab.TabRedirectHandler;
 import org.chromium.components.external_intents.ExternalNavigationDelegate;
 import org.chromium.components.external_intents.ExternalNavigationHandler;
 import org.chromium.components.external_intents.ExternalNavigationHandler.OverrideUrlLoadingResult;
 import org.chromium.components.external_intents.ExternalNavigationParams;
+import org.chromium.components.external_intents.RedirectHandlerImpl;
 import org.chromium.content_public.browser.test.NativeLibraryTestRule;
 import org.chromium.ui.base.PageTransition;
 import org.chromium.webapk.lib.common.WebApkConstants;
@@ -155,7 +155,7 @@
     public void testStartActivityToTrustedPackageWithoutUserGesture() {
         mDelegate.add(new IntentActivity(YOUTUBE_URL, YOUTUBE_PACKAGE_NAME));
 
-        TabRedirectHandler handler = TabRedirectHandler.create();
+        RedirectHandlerImpl handler = RedirectHandlerImpl.create();
         handler.updateNewUrlLoading(PageTransition.CLIENT_REDIRECT, false, false, 0, 0);
 
         checkUrl(YOUTUBE_URL)
@@ -278,7 +278,7 @@
     public void testRedirectFromFormSubmit_NoUserGesture_OnIntentRedirectChain() {
         mDelegate.add(new IntentActivity(YOUTUBE_URL, YOUTUBE_PACKAGE_NAME));
 
-        TabRedirectHandler redirectHandler = new TabRedirectHandler() {
+        RedirectHandlerImpl redirectHandler = new RedirectHandlerImpl() {
             @Override
             public boolean isOnEffectiveIntentRedirectChain() {
                 return true;
@@ -538,7 +538,7 @@
         mDelegate.add(new IntentActivity(YOUTUBE_MOBILE_URL, YOUTUBE_PACKAGE_NAME));
         mDelegate.add(new IntentActivity(YOUTUBE_URL, YOUTUBE_PACKAGE_NAME));
 
-        TabRedirectHandler redirectHandler = TabRedirectHandler.create();
+        RedirectHandlerImpl redirectHandler = RedirectHandlerImpl.create();
         Intent ytIntent = Intent.parseUri(YOUTUBE_URL, Intent.URI_INTENT_SCHEME);
         Intent fooIntent = Intent.parseUri("http://foo.com/", Intent.URI_INTENT_SCHEME);
         int transTypeLinkFromIntent = PageTransition.LINK
@@ -587,7 +587,7 @@
     testInitialIntentHeadingToChrome() throws URISyntaxException {
         mDelegate.add(new IntentActivity(YOUTUBE_MOBILE_URL, YOUTUBE_PACKAGE_NAME));
 
-        TabRedirectHandler redirectHandler = TabRedirectHandler.create();
+        RedirectHandlerImpl redirectHandler = RedirectHandlerImpl.create();
         Intent fooIntent = Intent.parseUri("http://foo.com/", Intent.URI_INTENT_SCHEME);
         fooIntent.setPackage(mContext.getPackageName());
         int transTypeLinkFromIntent = PageTransition.LINK
@@ -623,7 +623,7 @@
     testIntentForCustomTab() throws URISyntaxException {
         mDelegate.add(new IntentActivity(YOUTUBE_URL, YOUTUBE_PACKAGE_NAME));
 
-        TabRedirectHandler redirectHandler = TabRedirectHandler.create();
+        RedirectHandlerImpl redirectHandler = RedirectHandlerImpl.create();
         int transTypeLinkFromIntent = PageTransition.LINK | PageTransition.FROM_API;
 
         // In Custom Tabs, if the first url is not a redirect, stay in chrome.
@@ -696,7 +696,7 @@
     @SmallTest
     public void
     testInstantAppsIntent_customTabRedirect() throws Exception {
-        TabRedirectHandler redirectHandler = TabRedirectHandler.create();
+        RedirectHandlerImpl redirectHandler = RedirectHandlerImpl.create();
         int transTypeLinkFromIntent = PageTransition.LINK | PageTransition.FROM_API;
 
         // In Custom Tabs, if the first url is a redirect, don't allow it to intent out, unless
@@ -722,7 +722,7 @@
     public void testInstantAppsIntent_incomingIntentRedirect() throws Exception {
         int transTypeLinkFromIntent = PageTransition.LINK
                 | PageTransition.FROM_API;
-        TabRedirectHandler redirectHandler = TabRedirectHandler.create();
+        RedirectHandlerImpl redirectHandler = RedirectHandlerImpl.create();
         Intent fooIntent = Intent.parseUri("http://instantappenabled.com",
                 Intent.URI_INTENT_SCHEME);
         redirectHandler.updateIntent(fooIntent, !IS_CUSTOM_TAB_INTENT, !SEND_TO_EXTERNAL_APPS,
@@ -916,7 +916,7 @@
     @Test
     @SmallTest
     public void testFallbackUrl_RedirectToIntentToMarket() {
-        TabRedirectHandler redirectHandler = TabRedirectHandler.create();
+        RedirectHandlerImpl redirectHandler = RedirectHandlerImpl.create();
 
         redirectHandler.updateNewUrlLoading(PageTransition.TYPED, false, false, 0, 0);
         checkUrl("http://goo.gl/abcdefg")
@@ -999,7 +999,7 @@
     public void testFallback_UseFallbackUrlForRedirectionFromTypedInUrl() {
         mDelegate.add(new IntentActivity(YOUTUBE_MOBILE_URL, YOUTUBE_PACKAGE_NAME));
 
-        TabRedirectHandler redirectHandler = TabRedirectHandler.create();
+        RedirectHandlerImpl redirectHandler = RedirectHandlerImpl.create();
 
         redirectHandler.updateNewUrlLoading(PageTransition.TYPED, false, false, 0, 0);
         checkUrl("http://goo.gl/abcdefg")
@@ -1025,7 +1025,7 @@
         // We cannot resolve any intent, so fall-back URL will be used.
         mDelegate.setCanResolveActivityForExternalSchemes(false);
 
-        TabRedirectHandler redirectHandler = TabRedirectHandler.create();
+        RedirectHandlerImpl redirectHandler = RedirectHandlerImpl.create();
 
         redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, true, 0, 0);
         checkUrl(INTENT_URL_WITH_CHAIN_FALLBACK_URL)
@@ -1059,7 +1059,7 @@
     public void testIgnoreEffectiveRedirectFromUserTyping() {
         mDelegate.add(new IntentActivity(YOUTUBE_MOBILE_URL, YOUTUBE_PACKAGE_NAME));
 
-        TabRedirectHandler redirectHandler = TabRedirectHandler.create();
+        RedirectHandlerImpl redirectHandler = RedirectHandlerImpl.create();
 
         redirectHandler.updateNewUrlLoading(PageTransition.TYPED, false, false, 0, 0);
         checkUrl(YOUTUBE_MOBILE_URL)
@@ -1085,7 +1085,7 @@
     public void testNavigationFromLinkWithoutUserGesture() {
         mDelegate.add(new IntentActivity(YOUTUBE_MOBILE_URL, YOUTUBE_PACKAGE_NAME));
 
-        TabRedirectHandler redirectHandler = TabRedirectHandler.create();
+        RedirectHandlerImpl redirectHandler = RedirectHandlerImpl.create();
 
         redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, false, 1, 0);
         checkUrl(YOUTUBE_MOBILE_URL)
@@ -1266,7 +1266,7 @@
     public void testNavigationFromReload() {
         mDelegate.add(new IntentActivity(YOUTUBE_MOBILE_URL, YOUTUBE_PACKAGE_NAME));
 
-        TabRedirectHandler redirectHandler = TabRedirectHandler.create();
+        RedirectHandlerImpl redirectHandler = RedirectHandlerImpl.create();
 
         redirectHandler.updateNewUrlLoading(PageTransition.RELOAD, false, false, 1, 0);
         checkUrl(YOUTUBE_MOBILE_URL)
@@ -1290,7 +1290,7 @@
     public void testNavigationWithForwardBack() {
         mDelegate.add(new IntentActivity(YOUTUBE_MOBILE_URL, YOUTUBE_PACKAGE_NAME));
 
-        TabRedirectHandler redirectHandler = TabRedirectHandler.create();
+        RedirectHandlerImpl redirectHandler = RedirectHandlerImpl.create();
 
         redirectHandler.updateNewUrlLoading(
                 PageTransition.FORM_SUBMIT | PageTransition.FORWARD_BACK, false, false, 1, 0);
@@ -1973,7 +1973,7 @@
         private boolean mChromeAppInForegroundRequired = true;
         private boolean mIsBackgroundTabNavigation;
         private boolean mHasUserGesture;
-        private TabRedirectHandler mRedirectHandler;
+        private RedirectHandlerImpl mRedirectHandler;
 
         private ExternalNavigationTestParams(String url) {
             mUrl = url;
@@ -2016,7 +2016,7 @@
             return this;
         }
 
-        public ExternalNavigationTestParams withRedirectHandler(TabRedirectHandler handler) {
+        public ExternalNavigationTestParams withRedirectHandler(RedirectHandlerImpl handler) {
             mRedirectHandler = handler;
             return this;
         }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageArchivePublisherBridgeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageArchivePublisherBridgeTest.java
index 71c77f5..5a80dfc 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageArchivePublisherBridgeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageArchivePublisherBridgeTest.java
@@ -56,7 +56,7 @@
             throws InterruptedException {
         final Semaphore semaphore = new Semaphore(0);
         PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> {
-            Profile profile = Profile.getLastUsedProfile();
+            Profile profile = Profile.getLastUsedRegularProfile();
             if (incognitoProfile) {
                 profile = profile.getOffTheRecordProfile();
             }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java
index f3231c4b..b2a9c2d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java
@@ -78,7 +78,7 @@
             throws InterruptedException {
         final Semaphore semaphore = new Semaphore(0);
         PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> {
-            Profile profile = Profile.getLastUsedProfile();
+            Profile profile = Profile.getLastUsedRegularProfile();
             if (incognitoProfile) {
                 profile = profile.getOffTheRecordProfile();
             }
@@ -100,11 +100,16 @@
         if (!incognitoProfile) Assert.assertNotNull(mOfflinePageBridge);
     }
 
-    private OfflinePageBridge getBridgeForProfileKey() throws InterruptedException {
+    private OfflinePageBridge getBridgeForProfileKey(final boolean incognitoProfile)
+            throws InterruptedException {
         final Semaphore semaphore = new Semaphore(0);
         AtomicReference<OfflinePageBridge> offlinePageBridgeRef = new AtomicReference<>();
         PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> {
-            ProfileKey profileKey = ProfileKey.getLastUsedProfileKey();
+            Profile profile = Profile.getLastUsedRegularProfile();
+            if (incognitoProfile) {
+                profile = profile.getOffTheRecordProfile();
+            }
+            ProfileKey profileKey = profile.getProfileKey();
             // Ensure we start in an offline state.
             OfflinePageBridge offlinePageBridge = OfflinePageBridge.getForProfileKey(profileKey);
             offlinePageBridgeRef.set(offlinePageBridge);
@@ -121,7 +126,7 @@
             });
         });
         Assert.assertTrue(semaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-        Assert.assertNotNull(offlinePageBridgeRef.get());
+        if (!incognitoProfile) Assert.assertNotNull(offlinePageBridgeRef.get());
         return offlinePageBridgeRef.get();
     }
 
@@ -151,7 +156,7 @@
     @Test
     @MediumTest
     public void testProfileAndKeyMapToSameOfflinePageBridge() throws Exception {
-        OfflinePageBridge offlinePageBridgeRetrievedByKey = getBridgeForProfileKey();
+        OfflinePageBridge offlinePageBridgeRetrievedByKey = getBridgeForProfileKey(false);
         Assert.assertSame(mOfflinePageBridge, offlinePageBridgeRetrievedByKey);
     }
 
@@ -216,6 +221,14 @@
 
     @Test
     @MediumTest
+    @RetryOnFailure
+    public void testOfflinePageBridgeForProfileKeyDisabledInIncognito() throws Exception {
+        OfflinePageBridge offlinePageBridgeRetrievedByKey = getBridgeForProfileKey(true);
+        Assert.assertNull(offlinePageBridgeRetrievedByKey);
+    }
+
+    @Test
+    @MediumTest
     public void testDeletePagesByOfflineIds() throws Exception {
         // Save 3 pages and record their offline IDs to delete later.
         Set<String> pageUrls = new HashSet<>();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageSavePageLaterEvaluationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageSavePageLaterEvaluationTest.java
index 94f3f84..c5f185e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageSavePageLaterEvaluationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageSavePageLaterEvaluationTest.java
@@ -229,7 +229,9 @@
             throws InterruptedException {
         final Semaphore semaphore = new Semaphore(0);
         PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> {
-            Profile profile = Profile.getLastUsedProfile();
+            // TODO (https://crbug.com/714249):  Add incognito mode tests to check that
+            // OfflinePageEvaluationBridge is null for incognito.
+            Profile profile = Profile.getLastUsedRegularProfile();
             mBridge = new OfflinePageEvaluationBridge(profile, useTestingScheduler);
             if (mBridge == null) {
                 Assert.fail("OfflinePageEvaluationBridge initialization failed!");
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtilsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtilsTest.java
index 509efb4..63eafbc 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtilsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtilsTest.java
@@ -103,7 +103,7 @@
             // Ensure we start in an online state.
             NetworkChangeNotifier.forceConnectivityState(true);
 
-            Profile profile = Profile.getLastUsedProfile();
+            Profile profile = Profile.getLastUsedRegularProfile();
             mOfflinePageBridge = OfflinePageBridge.getForProfile(profile);
             if (!NetworkChangeNotifier.isInitialized()) {
                 NetworkChangeNotifier.init();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflineTestUtil.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflineTestUtil.java
index 097ee4d..b9a30819 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflineTestUtil.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflineTestUtil.java
@@ -123,7 +123,7 @@
         final AtomicReference<OfflinePageBridge> result = new AtomicReference<OfflinePageBridge>();
         PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> {
             OfflinePageBridge bridge =
-                    OfflinePageBridge.getForProfile(Profile.getLastUsedProfile());
+                    OfflinePageBridge.getForProfile(Profile.getLastUsedRegularProfile());
             if (bridge == null || bridge.isOfflinePageModelLoaded()) {
                 result.set(bridge);
                 ready.notifyCalled();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/RequestCoordinatorBridgeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/RequestCoordinatorBridgeTest.java
index 58f4bb73..c4c9c7e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/RequestCoordinatorBridgeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/RequestCoordinatorBridgeTest.java
@@ -49,7 +49,7 @@
             throws InterruptedException {
         final Semaphore semaphore = new Semaphore(0);
         PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> {
-            Profile profile = Profile.getLastUsedProfile();
+            Profile profile = Profile.getLastUsedRegularProfile();
             if (incognitoProfile) {
                 profile = profile.getOffTheRecordProfile();
             }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorControllerTest.java
index f3dae0e..3e0743b6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorControllerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorControllerTest.java
@@ -383,7 +383,7 @@
 
         final Semaphore semaphore = new Semaphore(0);
         TestThreadUtils.runOnUiThreadBlocking(() -> {
-            Profile profile = Profile.getLastUsedProfile();
+            Profile profile = Profile.getLastUsedRegularProfile();
             OfflinePageBridge offlinePageBridge = OfflinePageBridge.getForProfile(profile);
             offlinePageBridge.savePage(mActivityTestRule.getWebContents(), CLIENT_ID,
                     new OfflinePageBridge.SavePageCallback() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchFeedFlowTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchFeedFlowTest.java
index f2b9c8e8..9da40401 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchFeedFlowTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchFeedFlowTest.java
@@ -247,7 +247,7 @@
 
         // Register Offline Page observer and enable limitless prefetching.
         TestThreadUtils.runOnUiThreadBlocking(() -> {
-            OfflinePageBridge.getForProfileKey(ProfileKey.getLastUsedProfileKey())
+            OfflinePageBridge.getForProfileKey(ProfileKey.getLastUsedRegularProfileKey())
                     .addObserver(new OfflinePageBridge.OfflinePageModelObserver() {
                         @Override
                         public void offlinePageAdded(OfflinePageItem addedPage) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
index 078afe08..87f0c55 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
@@ -99,7 +99,7 @@
         OmniboxTestUtils.waitForOmniboxSuggestions(locationBar);
 
         ChromeTabUtils.waitForTabPageLoadStart(
-                mActivityTestRule.getActivity().getActivityTab(), new Runnable() {
+                mActivityTestRule.getActivity().getActivityTab(), null, new Runnable() {
                     @Override
                     public void run() {
                         final UrlBar urlBar =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenTest.java
index 0579587..865f19389 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenTest.java
@@ -174,35 +174,6 @@
     @Test
     @SmallTest
     @Feature({"Webapps"})
-    public void testUmaOnNativeLoad() {
-        mActivityTestRule.startWebappActivityAndWaitForSplashScreen();
-
-        // Tests UMA values.
-        Assert.assertEquals(0,
-                getHistogramTotalCountFor(WebappSplashDelegate.HISTOGRAM_SPLASHSCREEN_HIDES,
-                        SplashController.SplashHidesReason.NUM_ENTRIES));
-    }
-
-    @Test
-    @SmallTest
-    @Feature({"Webapps"})
-    public void testUmaWhenSplashHides() {
-        mActivityTestRule.startWebappActivityAndWaitForSplashScreen();
-        PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT,
-                () -> TabTestUtils.simulateFirstVisuallyNonEmptyPaint(
-                                mActivityTestRule.getActivity().getActivityTab()));
-
-        mActivityTestRule.waitUntilSplashscreenHides();
-
-        // HIDES should now have a value.
-        Assert.assertEquals(1,
-                getHistogramTotalCountFor(WebappSplashDelegate.HISTOGRAM_SPLASHSCREEN_HIDES,
-                        SplashController.SplashHidesReason.NUM_ENTRIES));
-    }
-
-    @Test
-    @SmallTest
-    @Feature({"Webapps"})
     public void testRegularSplashScreenAppears() throws Exception {
         // Register a properly-sized icon for the splash screen.
         Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index 36a498f..be5b00f 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-84.0.4104.0_rc-r1-merged.afdo.bz2
\ No newline at end of file
+chromeos-chrome-amd64-84.0.4106.0_rc-r1-merged.afdo.bz2
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings.grdp b/chrome/app/os_settings_strings.grdp
index c3cae3ed..28ba777 100644
--- a/chrome/app/os_settings_strings.grdp
+++ b/chrome/app/os_settings_strings.grdp
@@ -988,7 +988,7 @@
     Disk size
   </message>
   <message name="IDS_SETTINGS_CROSTINI_DISK_RESIZE_TITLE" desc="The title of the settings dialogue the user uses to resize the Crostini (AKA Linux (Beta)) Disk.">
-    Resize Linux Disk
+    Resize Linux disk
   </message>
   <message name="IDS_SETTINGS_CROSTINI_DISK_RESIZE_UNSUPPORTED" desc="The message diusplayed to the user when resizing their Crostini disk isn't supported, explaining a workaround.">
     Your container doesn't support being resized. To adjust the amount of space that is pre-allocated to Linux (Beta), back up and then restore into a new container.
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index ea761b7..cd45d530 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -1685,7 +1685,7 @@
      other {Change passwords}}
   </message>
   <message name="IDS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_ENABLED" desc="This text points out that Safe Browsing is enabled and that the user is protected.">
-    Safe Browsing is up to date and protecting you from harmful sites and downloads
+    Safe Browsing is on and protecting you from harmful sites and downloads
   </message>
   <message name="IDS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_DISABLED_BY_ADMIN" desc="This text points out that Safe Browsing is disabled by an administrator.">
     <ph name="BEGIN_LINK">&lt;a target="_blank" href="$1"&gt;</ph>Your administrator<ph name="END_LINK">&lt;/a&gt;</ph> has turned off Safe Browsing
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_ENABLED.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_ENABLED.png.sha1
new file mode 100644
index 0000000..b90329f
--- /dev/null
+++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_ENABLED.png.sha1
@@ -0,0 +1 @@
+dcc4e4728dad2c30f7b91f4a9414a8256c944f35
\ No newline at end of file
diff --git a/chrome/browser/android/webapk/webapk_installer.cc b/chrome/browser/android/webapk/webapk_installer.cc
index 37be7ea..f2909801 100644
--- a/chrome/browser/android/webapk/webapk_installer.cc
+++ b/chrome/browser/android/webapk/webapk_installer.cc
@@ -18,7 +18,6 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/memory/ref_counted.h"
-#include "base/metrics/histogram_macros.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -556,9 +555,6 @@
     const base::android::JavaParamRef<jobject>& obj,
     jint status) {
   SpaceStatus space_status = static_cast<SpaceStatus>(status);
-  UMA_HISTOGRAM_ENUMERATION("WebApk.Install.SpaceStatus", status,
-                            static_cast<int>(SpaceStatus::COUNT));
-
   if (space_status == SpaceStatus::NOT_ENOUGH_SPACE) {
     OnResult(WebApkInstallResult::FAILURE);
     return;
diff --git a/chrome/browser/chrome_back_forward_cache_browsertest.cc b/chrome/browser/chrome_back_forward_cache_browsertest.cc
index 73dbf1c8..aa23d155 100644
--- a/chrome/browser/chrome_back_forward_cache_browsertest.cc
+++ b/chrome/browser/chrome_back_forward_cache_browsertest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/auto_reset.h"
 #include "base/command_line.h"
 #include "base/macros.h"
 #include "base/test/mock_callback.h"
@@ -9,15 +10,18 @@
 #include "build/build_config.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/permissions/permission_manager_factory.h"
+#include "chrome/browser/printing/print_view_manager_common.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "components/network_session_configurator/common/network_switches.h"
 #include "components/permissions/permission_manager.h"
+#include "components/printing/common/print.mojom.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
@@ -28,6 +32,7 @@
 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
+#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
 #include "third_party/blink/public/mojom/webshare/webshare.mojom.h"
 
 class ChromeBackForwardCacheBrowserTest : public InProcessBrowserTest {
@@ -242,6 +247,120 @@
   delete_observer_rfh_a.WaitUntilDeleted();
 }
 
+class PrintPreviewObserver : printing::PrintPreviewUI::TestDelegate {
+ public:
+  explicit PrintPreviewObserver(bool wait_for_loaded) {
+    if (wait_for_loaded)
+      queue_.emplace();  // DOMMessageQueue doesn't allow assignment
+    printing::PrintPreviewUI::SetDelegateForTesting(this);
+  }
+
+  ~PrintPreviewObserver() override {
+    printing::PrintPreviewUI::SetDelegateForTesting(nullptr);
+  }
+
+  void WaitUntilPreviewIsReady() {
+    if (rendered_page_count_ >= total_page_count_)
+      return;
+
+    base::RunLoop run_loop;
+    base::AutoReset<base::RunLoop*> auto_reset(&run_loop_, &run_loop);
+    run_loop.Run();
+
+    if (queue_.has_value()) {
+      std::string message;
+      EXPECT_TRUE(queue_->WaitForMessage(&message));
+      EXPECT_EQ("\"success\"", message);
+    }
+  }
+
+ private:
+  // PrintPreviewUI::TestDelegate:
+  void DidGetPreviewPageCount(int page_count) override {
+    total_page_count_ = page_count;
+  }
+
+  // PrintPreviewUI::TestDelegate:
+  void DidRenderPreviewPage(content::WebContents* preview_dialog) override {
+    ++rendered_page_count_;
+    CHECK(rendered_page_count_ <= total_page_count_);
+    if (rendered_page_count_ == total_page_count_ && run_loop_) {
+      run_loop_->Quit();
+
+      if (queue_.has_value()) {
+        content::ExecuteScriptAsync(
+            preview_dialog,
+            "window.addEventListener('message', event => {"
+            "  if (event.data.type === 'documentLoaded') {"
+            "    domAutomationController.send(event.data.load_state);"
+            "  }"
+            "});");
+      }
+    }
+  }
+
+  base::Optional<content::DOMMessageQueue> queue_;
+  int total_page_count_ = 1;
+  int rendered_page_count_ = 0;
+  base::RunLoop* run_loop_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(PrintPreviewObserver);
+};
+
+class ChromeBackForwardCacheBrowserTestWithPrinting
+    : public ChromeBackForwardCacheBrowserTest {
+ public:
+  ChromeBackForwardCacheBrowserTestWithPrinting() = default;
+  ~ChromeBackForwardCacheBrowserTestWithPrinting() override = default;
+
+  void PrintAndWaitUntilPreviewIsReady(bool print_only_selection) {
+    PrintPreviewObserver print_preview_observer(/*wait_for_loaded=*/true);
+    printing::StartPrint(browser()->tab_strip_model()->GetActiveWebContents(),
+                         /*print_renderer=*/mojo::NullAssociatedRemote(),
+                         /*print_preview_disabled=*/false,
+                         print_only_selection);
+    print_preview_observer.WaitUntilPreviewIsReady();
+  }
+
+  void WaitUntilMessagesReceived() {
+    run_loop_ = std::make_unique<base::RunLoop>();
+    run_loop_->Run();
+  }
+
+  static mojo::AssociatedRemote<printing::mojom::PrintRenderFrame>
+  GetPrintRenderFrame(content::RenderFrameHost* rfh) {
+    mojo::AssociatedRemote<printing::mojom::PrintRenderFrame> remote;
+    rfh->GetRemoteAssociatedInterfaces()->GetInterface(&remote);
+    return remote;
+  }
+
+ private:
+  std::unique_ptr<base::RunLoop> run_loop_;
+};
+
+IN_PROC_BROWSER_TEST_F(ChromeBackForwardCacheBrowserTestWithPrinting,
+                       DoesNotCacheIfPrinting) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  // 1) Navigate to A.
+  EXPECT_TRUE(content::NavigateToURL(
+      web_contents(), embedded_test_server()->GetURL("/printing/test1.html")));
+  content::RenderFrameHost* rfh_a = current_frame_host();
+  content::RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
+  PrintAndWaitUntilPreviewIsReady(/*print_only_selection=*/false);
+
+  // 2) Navigate to B.
+  EXPECT_TRUE(content::NavigateToURL(web_contents(), GetURL("b.com")));
+  content::RenderFrameHost* rfh_b = current_frame_host();
+  content::RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
+  // A is not cached because of printing.
+  EXPECT_TRUE(delete_observer_rfh_a.deleted());
+
+  // 3) Navigate back.
+  web_contents()->GetController().GoBack();
+  EXPECT_TRUE(content::WaitForLoadStop(web_contents()));
+}
+
 #if defined(OS_ANDROID)
 IN_PROC_BROWSER_TEST_F(ChromeBackForwardCacheBrowserTest,
                        DoesNotCacheIfWebShare) {
diff --git a/chrome/browser/chromeos/arc/print/arc_print_service.cc b/chrome/browser/chromeos/arc/print/arc_print_service.cc
index f79b147..d9cefe3 100644
--- a/chrome/browser/chromeos/arc/print/arc_print_service.cc
+++ b/chrome/browser/chromeos/arc/print/arc_print_service.cc
@@ -492,9 +492,7 @@
       return;
 
     printing::PrintedDocument* document = job_->document();
-    document->SetDocument(std::move(metafile_) /* metafile */,
-                          gfx::Size() /* paper_size */,
-                          gfx::Rect() /* page_rect */);
+    document->SetDocument(std::move(metafile_));
     UMA_HISTOGRAM_COUNTS_1000("Arc.CupsPrinting.PageCount",
                               document->page_count());
     job_->StartPrinting();
diff --git a/chrome/browser/chromeos/dbus/chrome_features_service_provider.cc b/chrome/browser/chromeos/dbus/chrome_features_service_provider.cc
index d98de00..5fb7842 100644
--- a/chrome/browser/chromeos/dbus/chrome_features_service_provider.cc
+++ b/chrome/browser/chromeos/dbus/chrome_features_service_provider.cc
@@ -98,6 +98,14 @@
                           weak_ptr_factory_.GetWeakPtr()));
   exported_object->ExportMethod(
       kChromeFeaturesServiceInterface,
+      kChromeFeaturesServiceIsCryptohomeDistributedModelEnabledMethod,
+      base::BindRepeating(
+          &ChromeFeaturesServiceProvider::IsCryptohomeDistributedModelEnabled,
+          weak_ptr_factory_.GetWeakPtr()),
+      base::BindRepeating(&ChromeFeaturesServiceProvider::OnExported,
+                          weak_ptr_factory_.GetWeakPtr()));
+  exported_object->ExportMethod(
+      kChromeFeaturesServiceInterface,
       kChromeFeaturesServiceIsVmManagementCliAllowedMethod,
       base::BindRepeating(
           &ChromeFeaturesServiceProvider::IsVmManagementCliAllowed,
@@ -169,6 +177,14 @@
       profile ? crostini::CrostiniFeatures::Get()->IsAllowed(profile) : false);
 }
 
+void ChromeFeaturesServiceProvider::IsCryptohomeDistributedModelEnabled(
+    dbus::MethodCall* method_call,
+    dbus::ExportedObject::ResponseSender response_sender) {
+  SendResponse(
+      method_call, std::move(response_sender),
+      base::FeatureList::IsEnabled(::features::kCryptohomeDistributedModel));
+}
+
 void ChromeFeaturesServiceProvider::IsPluginVmEnabled(
     dbus::MethodCall* method_call,
     dbus::ExportedObject::ResponseSender response_sender) {
diff --git a/chrome/browser/chromeos/dbus/chrome_features_service_provider.h b/chrome/browser/chromeos/dbus/chrome_features_service_provider.h
index c46423a..afa0554 100644
--- a/chrome/browser/chromeos/dbus/chrome_features_service_provider.h
+++ b/chrome/browser/chromeos/dbus/chrome_features_service_provider.h
@@ -65,6 +65,9 @@
                         dbus::ExportedObject::ResponseSender response_sender);
   void IsCrostiniEnabled(dbus::MethodCall* method_call,
                          dbus::ExportedObject::ResponseSender response_sender);
+  void IsCryptohomeDistributedModelEnabled(
+      dbus::MethodCall* method_call,
+      dbus::ExportedObject::ResponseSender response_sender);
   void IsPluginVmEnabled(dbus::MethodCall* method_call,
                          dbus::ExportedObject::ResponseSender response_sender);
   void IsUsbguardEnabled(dbus::MethodCall* method_call,
diff --git a/chrome/browser/chromeos/extensions/printing/print_job_controller.cc b/chrome/browser/chromeos/extensions/printing/print_job_controller.cc
index 0b22e1f..6f4a53ad 100644
--- a/chrome/browser/chromeos/extensions/printing/print_job_controller.cc
+++ b/chrome/browser/chromeos/extensions/printing/print_job_controller.cc
@@ -167,11 +167,7 @@
   job->Initialize(std::move(query), title, /*page_count=*/1);
   job->SetSource(printing::PrintJob::Source::EXTENSION, extension_id);
   printing::PrintedDocument* document = job->document();
-  // |paper_size| and |page_rect| are used only for OS_MACOSX, so just use
-  // default constructor values.
-  document->SetDocument(std::move(metafile),
-                        /*paper_size=*/gfx::Size(),
-                        /*page_rect=*/gfx::Rect());
+  document->SetDocument(std::move(metafile));
   // Save PrintJob scoped refptr and callback to resolve when print job is
   // created.
   extension_pending_jobs_[extension_id].emplace(job, std::move(callback));
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
index fa79455..9b54f8b 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -462,6 +462,7 @@
     Toolbar, /* toolbar.js */
     FilesAppBrowserTest,
     ::testing::Values(TestCase("toolbarDeleteWithMenuItemNoEntrySelected"),
+                      TestCase("toolbarDeleteButtonKeepFocus"),
                       TestCase("toolbarDeleteEntry").InGuestMode(),
                       TestCase("toolbarDeleteEntry"),
                       TestCase("toolbarRefreshButtonWithSelection").EnableArc(),
diff --git a/chrome/browser/chromeos/plugin_vm/plugin_vm_uninstaller_notification.cc b/chrome/browser/chromeos/plugin_vm/plugin_vm_uninstaller_notification.cc
index d759722..0ec49b31 100644
--- a/chrome/browser/chromeos/plugin_vm/plugin_vm_uninstaller_notification.cc
+++ b/chrome/browser/chromeos/plugin_vm/plugin_vm_uninstaller_notification.cc
@@ -59,6 +59,7 @@
       IDS_PLUGIN_VM_REMOVING_NOTIFICATION_FAILED_MESSAGE));
   notification_->set_pinned(false);
   notification_->set_never_timeout(false);
+  notification_->set_accent_color(ash::kSystemNotificationColorCriticalWarning);
 
   ForceRedisplay();
 }
diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc
index b2aee66..f254f8b 100644
--- a/chrome/browser/chromeos/preferences.cc
+++ b/chrome/browser/chromeos/preferences.cc
@@ -157,9 +157,6 @@
       prefs::kSystemTimezoneAutomaticDetectionPolicy,
       enterprise_management::SystemTimezoneProto::USERS_DECIDE);
   registry->RegisterStringPref(prefs::kMinimumAllowedChromeVersion, "");
-  // TODO(tonydeluna): Remove deprecated pref.
-  // Carrier deal notification shown count defaults to 0.
-  registry->RegisterIntegerPref(prefs::kCarrierDealPromoShown, 0);
 
   ash::RegisterLocalStatePrefs(registry);
 }
@@ -340,11 +337,6 @@
 
   registry->RegisterBooleanPref(prefs::kShowMobileDataNotification, true);
 
-  // Number of times Data Saver prompt has been shown on 3G data network.
-  registry->RegisterIntegerPref(
-      prefs::kDataSaverPromptsShown, 0,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
-
   // Initially all existing users would see "What's new" for current version
   // after update.
   registry->RegisterStringPref(
diff --git a/chrome/browser/installable/installable_metrics.h b/chrome/browser/installable/installable_metrics.h
index 47e91c2..15b85728 100644
--- a/chrome/browser/installable/installable_metrics.h
+++ b/chrome/browser/installable/installable_metrics.h
@@ -72,7 +72,7 @@
   // Install icon in the Omnibox.
   OMNIBOX_INSTALL_ICON = 15,
 
-  // Installed from sync (not reported).
+  // Installed from sync (not reported by |TrackInstallEvent|).
   SYNC = 16,
 
   // Add any new values above this one.
diff --git a/chrome/browser/media/router/BUILD.gn b/chrome/browser/media/router/BUILD.gn
index efa5f12..0a680d4 100644
--- a/chrome/browser/media/router/BUILD.gn
+++ b/chrome/browser/media/router/BUILD.gn
@@ -13,9 +13,9 @@
     "//chrome:strings",
     "//chrome/common:constants",
     "//components/cast_channel",
-    "//components/cast_channel",
     "//components/keyed_service/content",
     "//components/keyed_service/core",
+    "//components/openscreen_platform:openscreen_platform_network_service",
     "//content/public/browser",
     "//content/public/common",
     "//crypto",
@@ -165,7 +165,6 @@
       ]
 
       deps += [
-        "//components/openscreen_platform:openscreen_platform_network_service",
         "//third_party/openscreen/src/osp/public",
         "//third_party/openscreen/src/platform",
         "//third_party/openscreen/src/util",
@@ -180,9 +179,7 @@
     "//chrome/test:test_support",
     "//testing/gmock",
   ]
-  public_deps = [
-    ":router",
-  ]
+  public_deps = [ ":router" ]
   sources = [
     "test/mock_media_router.cc",
     "test/mock_media_router.h",
@@ -316,9 +313,7 @@
 }
 
 fuzzer_test("dial_internal_message_fuzzer") {
-  sources = [
-    "providers/dial/dial_internal_message_fuzzer.cc",
-  ]
+  sources = [ "providers/dial/dial_internal_message_fuzzer.cc" ]
   deps = [
     ":router",
     "//base",
diff --git a/chrome/browser/media/router/mojo/media_router_desktop.cc b/chrome/browser/media/router/mojo/media_router_desktop.cc
index fb53618..e0e7eae8 100644
--- a/chrome/browser/media/router/mojo/media_router_desktop.cc
+++ b/chrome/browser/media/router/mojo/media_router_desktop.cc
@@ -14,10 +14,12 @@
 #include "chrome/browser/media/router/providers/cast/cast_media_route_provider.h"
 #include "chrome/browser/media/router/providers/cast/chrome_cast_message_handler.h"
 #include "chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.h"
+#include "chrome/browser/net/system_network_context_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/media_router/media_source.h"
 #include "components/cast_channel/cast_socket_service.h"
+#include "components/openscreen_platform/network_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "extensions/common/extension.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
@@ -208,6 +210,13 @@
 }
 
 void MediaRouterDesktop::InitializeMediaRouteProviders() {
+  if (!openscreen_platform::HasNetworkContextGetter()) {
+    openscreen_platform::SetNetworkContextGetter(base::BindRepeating([] {
+      DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+      return g_browser_process->system_network_context_manager()->GetContext();
+    }));
+  }
+
   InitializeExtensionMediaRouteProviderProxy();
   InitializeWiredDisplayMediaRouteProvider();
   if (CastMediaRouteProviderEnabled())
diff --git a/chrome/browser/metrics/process_memory_metrics_emitter.cc b/chrome/browser/metrics/process_memory_metrics_emitter.cc
index 992b419..bf785d1c 100644
--- a/chrome/browser/metrics/process_memory_metrics_emitter.cc
+++ b/chrome/browser/metrics/process_memory_metrics_emitter.cc
@@ -96,6 +96,10 @@
     {"blink_objects/Document", "NumberOfDocuments", MetricSize::kTiny,
      MemoryAllocatorDump::kNameObjectCount, EmitTo::kCountsInUkmAndSizeInUma,
      &Memory_Experimental::SetNumberOfDocuments},
+    {"blink_objects/ArrayBufferContents", "NumberOfArrayBufferContents",
+     MetricSize::kTiny, MemoryAllocatorDump::kNameObjectCount,
+     EmitTo::kCountsInUkmAndSizeInUma,
+     &Memory_Experimental::SetNumberOfArrayBufferContents},
     {"blink_objects/AdSubframe", "NumberOfAdSubframes", MetricSize::kTiny,
      MemoryAllocatorDump::kNameObjectCount, EmitTo::kCountsInUkmAndSizeInUma,
      &Memory_Experimental::SetNumberOfAdSubframes},
diff --git a/chrome/browser/password_manager/password_accessory_controller_impl.cc b/chrome/browser/password_manager/password_accessory_controller_impl.cc
index 95d05ee..4e421cf 100644
--- a/chrome/browser/password_manager/password_accessory_controller_impl.cc
+++ b/chrome/browser/password_manager/password_accessory_controller_impl.cc
@@ -274,7 +274,8 @@
 
   if (base::FeatureList::IsEnabled(
           password_manager::features::kRecoverFromNeverSaveAndroid) &&
-      is_password_field) {
+      is_password_field &&
+      !web_contents_->GetBrowserContext()->IsOffTheRecord()) {
     BlacklistedStatus blacklisted_status =
         credential_cache_->GetCredentialStore(origin).GetBlacklistedStatus();
     if (blacklisted_status == BlacklistedStatus::kWasBlacklisted ||
diff --git a/chrome/browser/password_manager/password_accessory_controller_impl_unittest.cc b/chrome/browser/password_manager/password_accessory_controller_impl_unittest.cc
index 52a29ef..244c751 100644
--- a/chrome/browser/password_manager/password_accessory_controller_impl_unittest.cc
+++ b/chrome/browser/password_manager/password_accessory_controller_impl_unittest.cc
@@ -21,6 +21,7 @@
 #include "chrome/browser/password_manager/password_generation_controller_impl.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "chrome/test/base/testing_profile.h"
 #include "components/autofill/core/common/autofill_features.h"
 #include "components/autofill/core/common/password_form.h"
 #include "components/autofill/core/common/password_generation_util.h"
@@ -28,7 +29,9 @@
 #include "components/password_manager/core/browser/credential_cache.h"
 #include "components/password_manager/core/browser/password_manager_test_utils.h"
 #include "components/password_manager/core/browser/stub_password_manager_driver.h"
+#include "components/password_manager/core/common/password_manager_features.h"
 #include "components/strings/grit/components_strings.h"
+#include "content/public/test/web_contents_tester.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkBitmap.h"
@@ -552,14 +555,18 @@
 }
 
 TEST_F(PasswordAccessoryControllerTest, AddsSaveToggleIfIsBlacklisted) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(
+      password_manager::features::kRecoverFromNeverSaveAndroid);
   cache()->SaveCredentialsAndBlacklistedForOrigin(
       {}, CredentialCache::IsOriginBlacklisted(true),
       url::Origin::Create(GURL(kExampleSite)));
   AccessorySheetData::Builder data_builder(AccessoryTabType::PASSWORDS,
                                            passwords_empty_str(kExampleDomain));
   data_builder
-      .SetOptionToggle(base::ASCIIToUTF16("Save passwords"), false,
-                       autofill::AccessoryAction::TOGGLE_SAVE_PASSWORDS)
+      .SetOptionToggle(
+          l10n_util::GetStringUTF16(IDS_PASSWORD_SAVING_STATUS_TOGGLE), false,
+          autofill::AccessoryAction::TOGGLE_SAVE_PASSWORDS)
       .AppendFooterCommand(manage_passwords_str(),
                            autofill::AccessoryAction::MANAGE_PASSWORDS);
   EXPECT_CALL(mock_manual_filling_controller_,
@@ -569,7 +576,47 @@
       /*is_manual_generation_available=*/false);
 }
 
+TEST_F(PasswordAccessoryControllerTest,
+       NoSaveToggleIfIsBlacklistedAndIncognito) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(
+      password_manager::features::kRecoverFromNeverSaveAndroid);
+
+  auto incognito_web_contents(content::WebContentsTester::CreateTestWebContents(
+      profile()->GetOffTheRecordProfile(), /*site_instance=*/nullptr));
+  content::WebContents* raw_web_contents = incognito_web_contents.get();
+
+  // Set the correct WebContents for the test and make sure the right frame
+  // is focused.
+  SetContents(std::move(incognito_web_contents));
+  NavigateAndCommit(GURL(kExampleSite));
+  FocusWebContentsOnMainFrame();
+
+  PasswordAccessoryControllerImpl::CreateForWebContentsForTesting(
+      raw_web_contents, cache(), mock_manual_filling_controller_.AsWeakPtr());
+  PasswordAccessoryController* incognito_accessory =
+      PasswordAccessoryControllerImpl::FromWebContents(raw_web_contents);
+  cache()->SaveCredentialsAndBlacklistedForOrigin(
+      {}, CredentialCache::IsOriginBlacklisted(true),
+      url::Origin::Create(GURL(kExampleSite)));
+
+  // Check that the accessory data passed to the |ManualFillingController| does
+  // not contain the save passwords toggle.
+  AccessorySheetData::Builder data_builder(AccessoryTabType::PASSWORDS,
+                                           passwords_empty_str(kExampleDomain));
+  data_builder.AppendFooterCommand(manage_passwords_str(),
+                                   autofill::AccessoryAction::MANAGE_PASSWORDS);
+  EXPECT_CALL(mock_manual_filling_controller_,
+              RefreshSuggestions(std::move(data_builder).Build()));
+  incognito_accessory->RefreshSuggestionsForField(
+      FocusedFieldType::kFillablePasswordField,
+      /*is_manual_generation_available=*/false);
+}
+
 TEST_F(PasswordAccessoryControllerTest, AddsSaveToggleIfWasBlacklisted) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(
+      password_manager::features::kRecoverFromNeverSaveAndroid);
   cache()->SaveCredentialsAndBlacklistedForOrigin(
       {}, CredentialCache::IsOriginBlacklisted(true),
       url::Origin::Create(GURL(kExampleSite)));
@@ -580,8 +627,9 @@
   AccessorySheetData::Builder data_builder(AccessoryTabType::PASSWORDS,
                                            passwords_empty_str(kExampleDomain));
   data_builder
-      .SetOptionToggle(base::ASCIIToUTF16("Save passwords"), true,
-                       autofill::AccessoryAction::TOGGLE_SAVE_PASSWORDS)
+      .SetOptionToggle(
+          l10n_util::GetStringUTF16(IDS_PASSWORD_SAVING_STATUS_TOGGLE), true,
+          autofill::AccessoryAction::TOGGLE_SAVE_PASSWORDS)
       .AppendFooterCommand(manage_passwords_str(),
                            autofill::AccessoryAction::MANAGE_PASSWORDS);
   EXPECT_CALL(mock_manual_filling_controller_,
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 0f9fba5..ac6d48a 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -391,45 +391,6 @@
 
 namespace {
 
-// Deprecated 8/2018.
-const char kDnsPrefetchingStartupList[] = "dns_prefetching.startup_list";
-const char kDnsPrefetchingHostReferralList[] =
-    "dns_prefetching.host_referral_list";
-
-// Deprecated 9/2018
-const char kGeolocationAccessToken[] = "geolocation.access_token";
-const char kGoogleServicesPasswordHash[] = "google.services.password_hash";
-const char kModuleConflictBubbleShown[] = "module_conflict.bubble_shown";
-const char kOptionsWindowLastTabIndex[] = "options_window.last_tab_index";
-const char kTrustedDownloadSources[] = "trusted_download_sources";
-#if defined(OS_WIN)
-const char kLastWelcomedOSVersion[] = "browser.last_welcomed_os_version";
-#endif
-const char kSupervisedUserCreationAllowed[] =
-    "profile.managed_user_creation_allowed";
-
-// Deprecated 10/2018
-const char kReverseAutologinEnabled[] = "reverse_autologin.enabled";
-
-// Deprecated 11/2018.
-const char kNetworkQualities[] = "net.network_qualities";
-const char kForceSessionSync[] = "settings.history_recorded";
-const char kOnboardDuringNUX[] = "browser.onboard_during_nux";
-const char kNuxOnboardGroup[] = "browser.onboard_group";
-// This pref is particularly large, taking up 15+% of the prefs file, so should
-// perhaps be kept around longer than the others.
-const char kHttpServerProperties[] = "net.http_server_properties";
-
-// Deprecated 1/2019.
-const char kNextUpdateCheck[] = "extensions.autoupdate.next_check";
-const char kLastUpdateCheck[] = "extensions.autoupdate.last_check";
-
-// Deprecated 3/2019.
-const char kCurrentThemeImages[] = "extensions.theme.images";
-const char kCurrentThemeColors[] = "extensions.theme.colors";
-const char kCurrentThemeTints[] = "extensions.theme.tints";
-const char kCurrentThemeDisplayProperties[] = "extensions.theme.properties";
-
 #if defined(OS_ANDROID)
 // Deprecated 4/2019.
 const char kDismissedAssetDownloadSuggestions[] =
@@ -562,32 +523,6 @@
 // Register prefs used only for migration (clearing or moving to a new key).
 void RegisterProfilePrefsForMigration(
     user_prefs::PrefRegistrySyncable* registry) {
-  registry->RegisterListPref(kDnsPrefetchingStartupList);
-  registry->RegisterListPref(kDnsPrefetchingHostReferralList);
-
-  registry->RegisterStringPref(kGeolocationAccessToken, std::string());
-  registry->RegisterStringPref(kGoogleServicesPasswordHash, std::string());
-  registry->RegisterIntegerPref(kModuleConflictBubbleShown, 0);
-  registry->RegisterIntegerPref(kOptionsWindowLastTabIndex, 0);
-  registry->RegisterStringPref(kTrustedDownloadSources, std::string());
-  registry->RegisterBooleanPref(kSupervisedUserCreationAllowed, true);
-
-  registry->RegisterBooleanPref(kReverseAutologinEnabled, true);
-
-  registry->RegisterDictionaryPref(kNetworkQualities, PrefRegistry::LOSSY_PREF);
-  registry->RegisterBooleanPref(kForceSessionSync, false);
-  registry->RegisterBooleanPref(kOnboardDuringNUX, false);
-  registry->RegisterIntegerPref(kNuxOnboardGroup, 0);
-  registry->RegisterDictionaryPref(kHttpServerProperties,
-                                   PrefRegistry::LOSSY_PREF);
-  registry->RegisterIntegerPref(kLastUpdateCheck, 0);
-  registry->RegisterIntegerPref(kNextUpdateCheck, 0);
-
-  registry->RegisterDictionaryPref(kCurrentThemeImages);
-  registry->RegisterDictionaryPref(kCurrentThemeColors);
-  registry->RegisterDictionaryPref(kCurrentThemeTints);
-  registry->RegisterDictionaryPref(kCurrentThemeDisplayProperties);
-
 #if defined(OS_ANDROID)
   registry->RegisterListPref(kDismissedAssetDownloadSuggestions);
   registry->RegisterListPref(kDismissedOfflinePageDownloadSuggestions);
@@ -816,7 +751,6 @@
 #endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
   registry->RegisterBooleanPref(kHasSeenWin10PromoPage, false);  // DEPRECATED
-  registry->RegisterStringPref(kLastWelcomedOSVersion, std::string());
 #endif  // defined(OS_WIN)
 
 #if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
@@ -825,8 +759,6 @@
   DeviceOAuth2TokenStoreDesktop::RegisterPrefs(registry);
 #endif
 
-  // Obsolete. See MigrateObsoleteBrowserPrefs().
-  registry->RegisterIntegerPref(metrics::prefs::kStabilityExecutionPhase, 0);
 #if !defined(OS_ANDROID)
   registry->RegisterBooleanPref(kNtpActivateHideShortcutsFieldTrial, false);
 #endif  // !defined(OS_ANDROID)
@@ -1136,24 +1068,6 @@
 
 // This method should be periodically pruned of year+ old migrations.
 void MigrateObsoleteBrowserPrefs(Profile* profile, PrefService* local_state) {
-  // Added 12/2018.
-  local_state->ClearPref(metrics::prefs::kStabilityExecutionPhase);
-
-#if defined(OS_ANDROID)
-  // Added 9/2018
-  local_state->ClearPref(
-      metrics::prefs::kStabilityCrashCountWithoutGmsCoreUpdateObsolete);
-#endif  // defined(OS_ANDROID)
-
-#if defined(OS_WIN)
-  // Added 9/2018
-  local_state->ClearPref(kLastWelcomedOSVersion);
-#endif
-#if defined(OS_CHROMEOS)
-  // Added 12/2018
-  local_state->ClearPref(prefs::kCarrierDealPromoShown);
-#endif
-
 #if defined(OS_WIN)
   // Added 6/2019.
   local_state->ClearPref(kHasSeenWin10PromoPage);
@@ -1190,57 +1104,9 @@
 void MigrateObsoleteProfilePrefs(Profile* profile) {
   PrefService* profile_prefs = profile->GetPrefs();
 
-  // Added 8/2018.
+  // Check MigrateDeprecatedAutofillPrefs() to see if this is safe to remove.
   autofill::prefs::MigrateDeprecatedAutofillPrefs(profile_prefs);
 
-  // Added 8/2018
-  profile_prefs->ClearPref(kDnsPrefetchingStartupList);
-  profile_prefs->ClearPref(kDnsPrefetchingHostReferralList);
-
-  // Added 9/2018
-  profile_prefs->ClearPref(kGeolocationAccessToken);
-  profile_prefs->ClearPref(kGoogleServicesPasswordHash);
-  profile_prefs->ClearPref(kModuleConflictBubbleShown);
-  profile_prefs->ClearPref(kOptionsWindowLastTabIndex);
-  profile_prefs->ClearPref(kTrustedDownloadSources);
-  profile_prefs->ClearPref(kSupervisedUserCreationAllowed);
-
-  // Added 10/2018
-  profile_prefs->ClearPref(kReverseAutologinEnabled);
-
-  // Added 11/2018.
-  profile_prefs->ClearPref(kNetworkQualities);
-  profile_prefs->ClearPref(kForceSessionSync);
-  profile_prefs->ClearPref(kOnboardDuringNUX);
-  profile_prefs->ClearPref(kNuxOnboardGroup);
-  profile_prefs->ClearPref(kHttpServerProperties);
-
-#if defined(OS_CHROMEOS)
-  // Added 12/2018.
-  profile_prefs->ClearPref(prefs::kDataSaverPromptsShown);
-#endif
-
-  // Added 1/2019.
-  profile_prefs->ClearPref(kLastUpdateCheck);
-  profile_prefs->ClearPref(kNextUpdateCheck);
-
-  syncer::MigrateSessionsToProxyTabsPrefs(profile_prefs);
-  syncer::ClearObsoleteUserTypePrefs(profile_prefs);
-
-  // Added 2/2019.
-  syncer::ClearObsoleteClearServerDataPrefs(profile_prefs);
-  syncer::ClearObsoleteAuthErrorPrefs(profile_prefs);
-
-  // Added 3/2019.
-  syncer::ClearObsoleteFirstSyncTime(profile_prefs);
-  syncer::ClearObsoleteSyncLongPollIntervalSeconds(profile_prefs);
-
-  // Added 3/2019.
-  profile_prefs->ClearPref(kCurrentThemeImages);
-  profile_prefs->ClearPref(kCurrentThemeColors);
-  profile_prefs->ClearPref(kCurrentThemeTints);
-  profile_prefs->ClearPref(kCurrentThemeDisplayProperties);
-
 #if defined(OS_ANDROID)
   // Added 4/2019.
   profile_prefs->ClearPref(kDismissedAssetDownloadSuggestions);
diff --git a/chrome/browser/printing/print_view_manager_base.cc b/chrome/browser/printing/print_view_manager_base.cc
index 3378f34..f767f223 100644
--- a/chrome/browser/printing/print_view_manager_base.cc
+++ b/chrome/browser/printing/print_view_manager_base.cc
@@ -180,7 +180,7 @@
 
   // Update the rendered document. It will send notifications to the listener.
   PrintedDocument* document = print_job_->document();
-  document->SetDocument(std::move(metafile), page_size, content_area);
+  document->SetDocument(std::move(metafile));
   ShouldQuitFromInnerMessageLoop();
 }
 
diff --git a/chrome/browser/resources/settings/metrics_browser_proxy.js b/chrome/browser/resources/settings/metrics_browser_proxy.js
index a3a67599..9981771 100644
--- a/chrome/browser/resources/settings/metrics_browser_proxy.js
+++ b/chrome/browser/resources/settings/metrics_browser_proxy.js
@@ -30,7 +30,7 @@
     PASSWORD_CHECK: 7,
     IMPROVE_SECURITY: 8,
     // Leave this at the end.
-    MAX_VALUE: 8,
+    COUNT: 9,
   };
 
   /**
@@ -97,8 +97,8 @@
     /** @override*/
     recordSettingsPageHistogram(interaction) {
       chrome.send('metricsHandler:recordInHistogram', [
-        'SettingsPage.PrivacyElementInteractions', interaction,
-        settings.PrivacyElementInteractions.MAX_VALUE
+        'Settings.PrivacyElementInteractions', interaction,
+        settings.PrivacyElementInteractions.COUNT
       ]);
     }
   }
diff --git a/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc b/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc
index 2fcf761..bdefbf76 100644
--- a/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc
@@ -225,8 +225,6 @@
 
   // Clear the "Sync paused" state again.
   GetClient(0)->ExitSyncPausedStateForPrimaryAccount();
-  // Once the auth error is gone, wait for Sync to start up again.
-  GetClient(0)->AwaitSyncSetupCompletion();
   ASSERT_TRUE(GetSyncService(0)->IsSyncFeatureActive());
 
   // Just checking that we don't see test_event isn't very convincing yet,
diff --git a/chrome/browser/translate/fake_translate_agent.cc b/chrome/browser/translate/fake_translate_agent.cc
index c8920cb..e4a2222e 100644
--- a/chrome/browser/translate/fake_translate_agent.cc
+++ b/chrome/browser/translate/fake_translate_agent.cc
@@ -38,8 +38,9 @@
 FakeTranslateAgent::FakeTranslateAgent()
     : called_translate_(false), called_revert_translation_(false) {}
 
-FakeTranslateAgent::~FakeTranslateAgent() {}
+FakeTranslateAgent::~FakeTranslateAgent() = default;
 
+// TODO(crbug.com/1064974) Remove with subframe translation launch.
 mojo::PendingRemote<translate::mojom::TranslateAgent>
 FakeTranslateAgent::BindToNewPageRemote() {
   receiver_.reset();
@@ -48,6 +49,11 @@
 }
 
 // translate::mojom::TranslateAgent implementation.
+void FakeTranslateAgent::GetWebLanguageDetectionDetails(
+    GetWebLanguageDetectionDetailsCallback callback) {
+  std::move(callback).Run("", "", GURL(), false);
+}
+
 void FakeTranslateAgent::TranslateFrame(const std::string& translate_script,
                                         const std::string& source_lang,
                                         const std::string& target_lang,
@@ -77,3 +83,10 @@
   std::move(translate_callback_pending_)
       .Run(cancelled, source_lang, target_lang, error);
 }
+
+void FakeTranslateAgent::BindRequest(
+    mojo::ScopedInterfaceEndpointHandle handle) {
+  per_frame_translate_agent_receivers_.Add(
+      this, mojo::PendingAssociatedReceiver<translate::mojom::TranslateAgent>(
+                std::move(handle)));
+}
diff --git a/chrome/browser/translate/fake_translate_agent.h b/chrome/browser/translate/fake_translate_agent.h
index 56fd66f..1a284ac 100644
--- a/chrome/browser/translate/fake_translate_agent.h
+++ b/chrome/browser/translate/fake_translate_agent.h
@@ -36,6 +36,7 @@
 #include "content/public/common/url_constants.h"
 #include "content/public/test/navigation_simulator.h"
 #include "content/public/test/test_renderer_host.h"
+#include "mojo/public/cpp/bindings/associated_receiver_set.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "url/gurl.h"
@@ -45,9 +46,13 @@
   FakeTranslateAgent();
   ~FakeTranslateAgent() override;
 
+  // TODO(crbug.com/1064974) Remove with subframe translation launch.
   mojo::PendingRemote<translate::mojom::TranslateAgent> BindToNewPageRemote();
 
   // translate::mojom::TranslateAgent implementation.
+  void GetWebLanguageDetectionDetails(
+      GetWebLanguageDetectionDetailsCallback callback) override;
+
   void TranslateFrame(const std::string& translate_script,
                       const std::string& source_lang,
                       const std::string& target_lang,
@@ -60,14 +65,21 @@
                       const std::string& target_lang,
                       translate::TranslateErrors::Type error);
 
+  void BindRequest(mojo::ScopedInterfaceEndpointHandle handle);
+
   bool called_translate_;
   base::Optional<std::string> source_lang_;
   base::Optional<std::string> target_lang_;
   bool called_revert_translation_;
+  std::string next_page_lang_;
+  bool next_page_translatable_;
 
  private:
   TranslateFrameCallback translate_callback_pending_;
+  // TODO(crbug.com/1064974) Remove with subframe translation launch.
   mojo::Receiver<translate::mojom::TranslateAgent> receiver_{this};
+  mojo::AssociatedReceiverSet<translate::mojom::TranslateAgent>
+      per_frame_translate_agent_receivers_;
   DISALLOW_COPY_AND_ASSIGN(FakeTranslateAgent);
 };
 
diff --git a/chrome/browser/ui/app_list/search/drive_quick_access_provider.cc b/chrome/browser/ui/app_list/search/drive_quick_access_provider.cc
index b019d41..e92a8f51 100644
--- a/chrome/browser/ui/app_list/search/drive_quick_access_provider.cc
+++ b/chrome/browser/ui/app_list/search/drive_quick_access_provider.cc
@@ -100,19 +100,24 @@
     : profile_(profile),
       drive_service_(
           drive::DriveIntegrationServiceFactory::GetForProfile(profile)),
-      search_controller_(search_controller) {
+      search_controller_(search_controller),
+      suggested_files_enabled_(app_list_features::IsSuggestedFilesEnabled()) {
   DCHECK(profile_);
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   task_runner_ = base::ThreadPool::CreateSequencedTaskRunner(
       {base::TaskPriority::BEST_EFFORT, base::MayBlock(),
        base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
 
-  if (drive_service_)
+  // Observe the drive integration service to warm the results cache once
+  // drivefs is mounted. This is necessary only if the suggested files
+  // experiment is enabled, so that results are ready for display in the
+  // suggested chips on the first launcher open after login.
+  if (suggested_files_enabled_ && drive_service_)
     drive_service_->AddObserver(this);
 }
 
 DriveQuickAccessProvider::~DriveQuickAccessProvider() {
-  if (drive_service_)
+  if (suggested_files_enabled_ && drive_service_)
     drive_service_->RemoveObserver(this);
 }
 
@@ -164,7 +169,7 @@
     results.emplace_back(std::make_unique<DriveQuickAccessResult>(
         path, result.confidence, profile_));
     // Add suggestion chip file results
-    if (app_list_features::IsSuggestedFilesEnabled()) {
+    if (suggested_files_enabled_) {
       results.emplace_back(std::make_unique<DriveQuickAccessChipResult>(
           path, result.confidence, profile_));
     }
diff --git a/chrome/browser/ui/app_list/search/drive_quick_access_provider.h b/chrome/browser/ui/app_list/search/drive_quick_access_provider.h
index 5be65a10..14f767b 100644
--- a/chrome/browser/ui/app_list/search/drive_quick_access_provider.h
+++ b/chrome/browser/ui/app_list/search/drive_quick_access_provider.h
@@ -53,6 +53,9 @@
   drive::DriveIntegrationService* const drive_service_;
   SearchController* const search_controller_;
 
+  // Whether the suggested files experiment is enabled.
+  const bool suggested_files_enabled_;
+
   // Stores the last-returned results from the QuickAccess API.
   std::vector<drive::QuickAccessItem> results_cache_;
 
diff --git a/chrome/browser/ui/ash/DEPS b/chrome/browser/ui/ash/DEPS
index 87c7d81..d2632bf8 100644
--- a/chrome/browser/ui/ash/DEPS
+++ b/chrome/browser/ui/ash/DEPS
@@ -16,6 +16,7 @@
    "+ash/public",
    "+ash/assistant/ui/assistant_ui_constants.h",
    "+ash/assistant/ui/main_stage/assistant_ui_element_view.h",
+   "+ui/message_center/message_center.h",
   ],
   # AshShellInit supports classic (non-mash) mode so allow ash/ includes.
   "ash_shell_init\.cc": [
diff --git a/chrome/browser/ui/ash/assistant/assistant_browsertest.cc b/chrome/browser/ui/ash/assistant/assistant_browsertest.cc
index 3226c808..dea4d0885 100644
--- a/chrome/browser/ui/ash/assistant/assistant_browsertest.cc
+++ b/chrome/browser/ui/ash/assistant/assistant_browsertest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/strings/string_util.h"
 #include "base/test/bind_test_util.h"
 #include "chrome/browser/ui/ash/assistant/assistant_test_mixin.h"
 #include "chrome/test/base/mixin_based_in_process_browser_test.h"
@@ -9,6 +10,8 @@
 #include "chromeos/dbus/power/power_manager_client.h"
 #include "chromeos/dbus/power_manager/backlight.pb.h"
 #include "chromeos/services/assistant/public/features.h"
+#include "ui/message_center/message_center.h"
+#include "ui/message_center/public/cpp/notification.h"
 
 namespace chromeos {
 namespace assistant {
@@ -17,6 +20,14 @@
 
 constexpr int kStartBrightnessPercent = 50;
 
+// Ensures that |str_| starts with |prefix_|. If it doesn't, this will print a
+// nice error message.
+#define EXPECT_STARTS_WITH(str_, prefix_)                                      \
+  ({                                                                           \
+    EXPECT_TRUE(base::StartsWith(str_, prefix_, base::CompareCase::SENSITIVE)) \
+        << "Expected '" << str_ << "'' to start with '" << prefix_ << "'";     \
+  })
+
 // Ensures that |value_| is within the range {min_, max_}. If it isn't, this
 // will print a nice error message.
 #define EXPECT_WITHIN_RANGE(min_, value_, max_)                \
@@ -326,5 +337,33 @@
   tester()->ExpectTimersResponse(timers);
 }
 
+IN_PROC_BROWSER_TEST_F(AssistantTimersV2BrowserTest,
+                       ShouldDismissTimerNotificationsWhenDisablingAssistant) {
+  tester()->StartAssistantAndWaitForReady();
+
+  ShowAssistantUi();
+  EXPECT_TRUE(tester()->IsVisible());
+
+  // Confirm no Assistant notifications are currently being shown.
+  auto* message_center = message_center::MessageCenter::Get();
+  EXPECT_TRUE(message_center->FindNotificationsByAppId("assistant").empty());
+
+  // Start a timer for one minute.
+  tester()->SendTextQuery("Set a timer for 1 minute.");
+  tester()->ExpectTextResponse("Alright, 1 min. And that's starting… now.");
+
+  // Confirm that an Assistant timer notification is now showing.
+  auto notifications = message_center->FindNotificationsByAppId("assistant");
+  EXPECT_EQ(1u, notifications.size());
+  EXPECT_STARTS_WITH((*notifications.begin())->id(), "assistant/timer");
+
+  // Disable Assistant.
+  tester()->SetAssistantEnabled(false);
+  base::RunLoop().RunUntilIdle();
+
+  // Confirm that our Assistant timer notification has been dismissed.
+  EXPECT_TRUE(message_center->FindNotificationsByAppId("assistant").empty());
+}
+
 }  // namespace assistant
 }  // namespace chromeos
diff --git a/chrome/browser/ui/ash/assistant/assistant_test_mixin.cc b/chrome/browser/ui/ash/assistant/assistant_test_mixin.cc
index ca35fbf..ff8c1a7 100644
--- a/chrome/browser/ui/ash/assistant/assistant_test_mixin.cc
+++ b/chrome/browser/ui/ash/assistant/assistant_test_mixin.cc
@@ -407,6 +407,10 @@
   DisableWarmerWelcome();
 }
 
+void AssistantTestMixin::SetAssistantEnabled(bool enabled) {
+  test_api_->SetAssistantEnabled(enabled);
+}
+
 void AssistantTestMixin::SetPreferVoice(bool prefer_voice) {
   test_api_->SetPreferVoice(prefer_voice);
 }
diff --git a/chrome/browser/ui/ash/assistant/assistant_test_mixin.h b/chrome/browser/ui/ash/assistant/assistant_test_mixin.h
index 7d2bbbe..d97826c1 100644
--- a/chrome/browser/ui/ash/assistant/assistant_test_mixin.h
+++ b/chrome/browser/ui/ash/assistant/assistant_test_mixin.h
@@ -60,8 +60,10 @@
   void StartAssistantAndWaitForReady(
       base::TimeDelta wait_timeout = kDefaultWaitTimeout);
 
-  // Changes the user setting controlling whether the user prefers voice or
-  // keyboard.
+  // Changes the user setting controlling if the user has enabled Assistant.
+  void SetAssistantEnabled(bool enabled);
+
+  // Changes the user setting controlling if the user prefers voice or keyboard.
   void SetPreferVoice(bool prefer_voice);
 
   // Submits a text query. Can only be used when the Assistant UI is visible and
diff --git a/chrome/browser/ui/chrome_pages.cc b/chrome/browser/ui/chrome_pages.cc
index 792c9c3..9ca0241 100644
--- a/chrome/browser/ui/chrome_pages.cc
+++ b/chrome/browser/ui/chrome_pages.cc
@@ -16,7 +16,6 @@
 #include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
-#include "base/system/sys_info.h"
 #include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/apps/app_service/app_launch_params.h"
@@ -110,7 +109,6 @@
 #if defined(OS_CHROMEOS) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
 const std::string BuildQueryString(Profile* profile) {
-  const std::string board_name = base::SysInfo::GetLsbReleaseBoard();
   std::string region;
   chromeos::system::StatisticsProvider::GetInstance()->GetMachineStatistic(
       "region", &region);
@@ -133,8 +131,8 @@
   }
 
   const std::string query_string = base::StrCat(
-      {kChromeReleaseNotesURL, "?version=", milestone, "&tags=", board_name,
-       ",", region, ",", language, ",", channel_name, ",", user_type});
+      {kChromeReleaseNotesURL, "?version=", milestone, "&tags=", region, ",",
+       language, ",", channel_name, ",", user_type});
   return query_string;
 }
 
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc b/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
index 7ced729..31b8d90 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
+++ b/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
@@ -520,7 +520,7 @@
   sync_harness()->EnterSyncPausedStateForPrimaryAccount();
   // Check that the setup was successful.
   ASSERT_TRUE(identity_manager()->HasPrimaryAccount());
-  ASSERT_TRUE(sync_service()->HasDisableReason(
+  ASSERT_FALSE(sync_service()->HasDisableReason(
       syncer::SyncService::DISABLE_REASON_PAUSED));
 
   RunTest();
diff --git a/chrome/browser/ui/webui/settings/safety_check_handler_unittest.cc b/chrome/browser/ui/webui/settings/safety_check_handler_unittest.cc
index 02c9048..82c7855 100644
--- a/chrome/browser/ui/webui/settings/safety_check_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/safety_check_handler_unittest.cc
@@ -475,8 +475,8 @@
           static_cast<int>(SafetyCheckHandler::SafeBrowsingStatus::kEnabled));
   ASSERT_TRUE(event);
   VerifyDisplayString(event,
-                      "Safe Browsing is up to date and protecting you from "
-                      "harmful sites and downloads");
+                      "Safe Browsing is on and protecting you from harmful "
+                      "sites and downloads");
   histogram_tester_.ExpectBucketCount(
       "Settings.SafetyCheck.SafeBrowsingResult",
       SafetyCheckHandler::SafeBrowsingStatus::kEnabled, 1);
diff --git a/chrome/browser/web_applications/components/BUILD.gn b/chrome/browser/web_applications/components/BUILD.gn
index 30b26f88..0236f9e 100644
--- a/chrome/browser/web_applications/components/BUILD.gn
+++ b/chrome/browser/web_applications/components/BUILD.gn
@@ -145,6 +145,7 @@
   sources = [
     "app_shortcut_manager_unittest.cc",
     "file_handler_manager_unittest.cc",
+    "install_finalizer_unittest.cc",
     "pending_app_manager_unittest.cc",
     "web_app_constants_unittest.cc",
     "web_app_data_retriever_unittest.cc",
@@ -180,7 +181,9 @@
     "//base/test:test_support",
     "//chrome/app/theme:theme_resources",
     "//chrome/browser/web_applications:web_app_test_group",
+    "//chrome/browser/web_applications:web_applications",
     "//chrome/browser/web_applications:web_applications_test_support",
+    "//chrome/browser/web_applications/extensions:extensions",
     "//chrome/test:test_support",
     "//content/public/browser",
     "//skia",
diff --git a/chrome/browser/web_applications/components/file_handler_manager.cc b/chrome/browser/web_applications/components/file_handler_manager.cc
index 3a66c82..4e796f8 100644
--- a/chrome/browser/web_applications/components/file_handler_manager.cc
+++ b/chrome/browser/web_applications/components/file_handler_manager.cc
@@ -133,8 +133,10 @@
 
 void FileHandlerManager::DisableForceEnabledFileHandlingOriginTrial(
     const AppId& app_id) {
-  double pref_expiry_time = GetDoubleWebAppPref(
-      profile()->GetPrefs(), app_id, kFileHandlingOriginTrialExpiryTime);
+  double pref_expiry_time =
+      GetDoubleWebAppPref(profile()->GetPrefs(), app_id,
+                          kFileHandlingOriginTrialExpiryTime)
+          .value_or(0);
   if (pref_expiry_time == kMaxOriginTrialExpiryTime) {
     UpdateFileHandlersForOriginTrialExpiryTime(app_id, base::Time());
   }
@@ -149,10 +151,12 @@
 }
 
 bool FileHandlerManager::IsFileHandlingAPIAvailable(const AppId& app_id) {
+  double pref_expiry_time =
+      GetDoubleWebAppPref(profile()->GetPrefs(), app_id,
+                          kFileHandlingOriginTrialExpiryTime)
+          .value_or(0);
   return base::FeatureList::IsEnabled(blink::features::kFileHandlingAPI) ||
-         base::Time::FromDoubleT(GetDoubleWebAppPref(
-             profile()->GetPrefs(), app_id,
-             kFileHandlingOriginTrialExpiryTime)) >= base::Time::Now();
+         base::Time::FromDoubleT(pref_expiry_time) >= base::Time::Now();
 }
 
 bool FileHandlerManager::AreFileHandlersEnabled(const AppId& app_id) const {
diff --git a/chrome/browser/web_applications/components/install_finalizer_unittest.cc b/chrome/browser/web_applications/components/install_finalizer_unittest.cc
new file mode 100644
index 0000000..ecd4144
--- /dev/null
+++ b/chrome/browser/web_applications/components/install_finalizer_unittest.cc
@@ -0,0 +1,177 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/web_applications/components/install_finalizer.h"
+
+#include <memory>
+
+#include "base/command_line.h"
+#include "base/optional.h"
+#include "base/run_loop.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/bind_test_util.h"
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/extensions/test_extension_system.h"
+#include "chrome/browser/web_applications/components/web_app_prefs_utils.h"
+#include "chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.h"
+#include "chrome/browser/web_applications/test/test_file_utils.h"
+#include "chrome/browser/web_applications/test/test_web_app_registry_controller.h"
+#include "chrome/browser/web_applications/test/test_web_app_ui_manager.h"
+#include "chrome/browser/web_applications/test/web_app_test.h"
+#include "chrome/browser/web_applications/web_app_icon_manager.h"
+#include "chrome/browser/web_applications/web_app_install_finalizer.h"
+#include "chrome/common/chrome_features.h"
+#include "chrome/common/web_application_info.h"
+#include "testing/gtest/include/gtest/gtest-param-test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace web_app {
+
+namespace {
+
+void InitializeEmptyExtensionService(Profile* profile) {
+  // CrxInstaller in BookmarkAppInstallFinalizer needs an ExtensionService, so
+  // create one for the profile.
+  auto* test_system = static_cast<extensions::TestExtensionSystem*>(
+      extensions::ExtensionSystem::Get(profile));
+  test_system->CreateExtensionService(base::CommandLine::ForCurrentProcess(),
+                                      profile->GetPath(),
+                                      false /* autoupdate_enabled */);
+}
+
+struct FinalizeInstallResult {
+  AppId installed_app_id;
+  InstallResultCode code;
+};
+
+}  // namespace
+
+// Tests both implementations of InstallFinalizer to ensure same behavior with
+// and without BMO enabled.
+// TODO(crbug.com/1068081): Migrate remaining tests from
+// bookmark_app_install_finalizer_unittest.
+class InstallFinalizerUnitTest
+    : public WebAppTest,
+      public ::testing::WithParamInterface<ProviderType> {
+ public:
+  InstallFinalizerUnitTest() {
+    switch (GetParam()) {
+      case ProviderType::kWebApps:
+        scoped_feature_list_.InitAndEnableFeature(
+            features::kDesktopPWAsWithoutExtensions);
+        break;
+      case ProviderType::kBookmarkApps:
+        scoped_feature_list_.InitAndDisableFeature(
+            features::kDesktopPWAsWithoutExtensions);
+        break;
+    }
+  }
+  ~InstallFinalizerUnitTest() override = default;
+
+  void SetUp() override {
+    WebAppTest::SetUp();
+
+    test_registry_controller_ =
+        std::make_unique<TestWebAppRegistryController>();
+    test_registry_controller_->SetUp(profile());
+    auto file_utils = std::make_unique<TestFileUtils>();
+    icon_manager_ = std::make_unique<WebAppIconManager>(profile(), registrar(),
+                                                        std::move(file_utils));
+    ui_manager_ = std::make_unique<TestWebAppUiManager>();
+
+    switch (GetParam()) {
+      case ProviderType::kWebApps:
+        finalizer_ = std::make_unique<WebAppInstallFinalizer>(
+            profile(), &test_registry_controller_->sync_bridge(),
+            icon_manager_.get());
+        break;
+      case ProviderType::kBookmarkApps:
+        InitializeEmptyExtensionService(profile());
+        finalizer_ = std::make_unique<extensions::BookmarkAppInstallFinalizer>(
+            profile());
+        break;
+    }
+
+    finalizer_->SetSubsystems(&registrar(), ui_manager_.get());
+    test_registry_controller_->Init();
+  }
+
+  void TearDown() override {
+    finalizer_.reset();
+    ui_manager_.reset();
+    icon_manager_.reset();
+    test_registry_controller_.reset();
+    WebAppTest::TearDown();
+  }
+
+  // Synchronous version of FinalizeInstall.
+  FinalizeInstallResult AwaitFinalizeInstall(
+      WebApplicationInfo info,
+      InstallFinalizer::FinalizeOptions options) {
+    FinalizeInstallResult result{};
+    base::RunLoop run_loop;
+    finalizer().FinalizeInstall(
+        info, options,
+        base::BindLambdaForTesting(
+            [&](const AppId& installed_app_id, InstallResultCode code) {
+              result.installed_app_id = installed_app_id;
+              result.code = code;
+              run_loop.Quit();
+            }));
+    run_loop.Run();
+    return result;
+  }
+
+  InstallFinalizer& finalizer() { return *finalizer_.get(); }
+  WebAppRegistrar& registrar() {
+    return test_registry_controller_->registrar();
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+  std::unique_ptr<TestWebAppRegistryController> test_registry_controller_;
+  std::unique_ptr<WebAppIconManager> icon_manager_;
+  std::unique_ptr<WebAppUiManager> ui_manager_;
+  std::unique_ptr<InstallFinalizer> finalizer_;
+
+  DISALLOW_COPY_AND_ASSIGN(InstallFinalizerUnitTest);
+};
+
+TEST_P(InstallFinalizerUnitTest, BasicInstallSucceeds) {
+  auto info = std::make_unique<WebApplicationInfo>();
+  info->app_url = GURL("https://foo.example");
+  info->title = base::ASCIIToUTF16("Foo Title");
+  InstallFinalizer::FinalizeOptions options;
+  options.install_source = WebappInstallSource::INTERNAL_DEFAULT;
+
+  FinalizeInstallResult result = AwaitFinalizeInstall(*info, options);
+
+  EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result.code);
+  EXPECT_FALSE(result.installed_app_id.empty());
+}
+
+TEST_P(InstallFinalizerUnitTest, InstallStoresLatestWebAppInstallSource) {
+  auto info = std::make_unique<WebApplicationInfo>();
+  info->app_url = GURL("https://foo.example");
+  info->title = base::ASCIIToUTF16("Foo Title");
+  InstallFinalizer::FinalizeOptions options;
+  options.install_source = WebappInstallSource::INTERNAL_DEFAULT;
+
+  FinalizeInstallResult result = AwaitFinalizeInstall(*info, options);
+
+  base::Optional<int> install_source =
+      GetIntWebAppPref(profile()->GetPrefs(), result.installed_app_id,
+                       kLatestWebAppInstallSource);
+  EXPECT_TRUE(install_source.has_value());
+  EXPECT_EQ(static_cast<WebappInstallSource>(*install_source),
+            WebappInstallSource::INTERNAL_DEFAULT);
+}
+
+INSTANTIATE_TEST_SUITE_P(All,
+                         InstallFinalizerUnitTest,
+                         ::testing::ValuesIn({ProviderType::kBookmarkApps,
+                                              ProviderType::kWebApps}));
+
+}  // namespace web_app
diff --git a/chrome/browser/web_applications/components/web_app_prefs_utils.cc b/chrome/browser/web_applications/components/web_app_prefs_utils.cc
index 4dcb325..edcdd6a7 100644
--- a/chrome/browser/web_applications/components/web_app_prefs_utils.cc
+++ b/chrome/browser/web_applications/components/web_app_prefs_utils.cc
@@ -76,6 +76,8 @@
 
 const char kExperimentalTabbedWindowMode[] = "experimental_tabbed_window_mode";
 
+const char kLatestWebAppInstallSource[] = "latest_web_app_install_source";
+
 void WebAppPrefsUtilsRegisterProfilePrefs(
     user_prefs::PrefRegistrySyncable* registry) {
   registry->RegisterDictionaryPref(::prefs::kWebAppsPreferences);
@@ -104,15 +106,36 @@
   web_app_prefs->SetBoolean(path, value);
 }
 
-double GetDoubleWebAppPref(const PrefService* pref_service,
-                           const AppId& app_id,
-                           base::StringPiece path) {
+base::Optional<int> GetIntWebAppPref(const PrefService* pref_service,
+                                     const AppId& app_id,
+                                     base::StringPiece path) {
   const base::DictionaryValue* web_app_prefs =
       GetWebAppDictionary(pref_service, app_id);
-  double pref_value = 0;
   if (web_app_prefs)
-    web_app_prefs->GetDouble(path, &pref_value);
-  return pref_value;
+    return web_app_prefs->FindIntPath(path);
+  return base::nullopt;
+}
+
+void UpdateIntWebAppPref(PrefService* pref_service,
+                         const AppId& app_id,
+                         base::StringPiece path,
+                         int value) {
+  prefs::ScopedDictionaryPrefUpdate update(pref_service,
+                                           prefs::kWebAppsPreferences);
+
+  std::unique_ptr<prefs::DictionaryValueUpdate> web_app_prefs =
+      UpdateWebAppDictionary(update.Get(), app_id);
+  web_app_prefs->SetInteger(path, value);
+}
+
+base::Optional<double> GetDoubleWebAppPref(const PrefService* pref_service,
+                                           const AppId& app_id,
+                                           base::StringPiece path) {
+  const base::DictionaryValue* web_app_prefs =
+      GetWebAppDictionary(pref_service, app_id);
+  if (web_app_prefs)
+    return web_app_prefs->FindDoublePath(path);
+  return base::nullopt;
 }
 
 void UpdateDoubleWebAppPref(PrefService* pref_service,
diff --git a/chrome/browser/web_applications/components/web_app_prefs_utils.h b/chrome/browser/web_applications/components/web_app_prefs_utils.h
index 64b2956c..d142aee 100644
--- a/chrome/browser/web_applications/components/web_app_prefs_utils.h
+++ b/chrome/browser/web_applications/components/web_app_prefs_utils.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_PREFS_UTILS_H_
 #define CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_PREFS_UTILS_H_
 
+#include "base/optional.h"
 #include "base/strings/string_piece.h"
 #include "chrome/browser/web_applications/components/web_app_id.h"
 
@@ -24,6 +25,8 @@
 
 extern const char kExperimentalTabbedWindowMode[];
 
+extern const char kLatestWebAppInstallSource[];
+
 bool GetBoolWebAppPref(const PrefService* pref_service,
                        const AppId& app_id,
                        base::StringPiece path);
@@ -33,9 +36,18 @@
                           base::StringPiece path,
                           bool value);
 
-double GetDoubleWebAppPref(const PrefService* pref_service,
-                           const AppId& app_id,
-                           base::StringPiece path);
+base::Optional<int> GetIntWebAppPref(const PrefService* pref_service,
+                                     const AppId& app_id,
+                                     base::StringPiece path);
+
+void UpdateIntWebAppPref(PrefService* pref_service,
+                         const AppId& app_id,
+                         base::StringPiece path,
+                         int value);
+
+base::Optional<double> GetDoubleWebAppPref(const PrefService* pref_service,
+                                           const AppId& app_id,
+                                           base::StringPiece path);
 
 void UpdateDoubleWebAppPref(PrefService* pref_service,
                             const AppId& app_id,
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.cc b/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.cc
index e2c4c428..c4b5505 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.cc
+++ b/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
+#include "chrome/browser/web_applications/components/web_app_prefs_utils.h"
 #include "chrome/browser/web_applications/components/web_app_utils.h"
 #include "chrome/browser/web_applications/extensions/bookmark_app_finalizer_utils.h"
 #include "chrome/browser/web_applications/extensions/bookmark_app_registrar.h"
@@ -111,6 +112,11 @@
       break;
   }
 
+  const web_app::AppId app_id =
+      web_app::GenerateAppIdFromURL(web_app_info.app_url);
+  web_app::UpdateIntWebAppPref(profile_->GetPrefs(), app_id,
+                               web_app::kLatestWebAppInstallSource,
+                               static_cast<int>(options.install_source));
   crx_installer->InstallWebApp(web_app_info);
 }
 
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer_unittest.cc b/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer_unittest.cc
index 505cc51..ac0d1a9a 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer_unittest.cc
+++ b/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer_unittest.cc
@@ -56,6 +56,9 @@
 
 }  // namespace
 
+// Do not add tests to this class. Instead, add tests to
+// |InstallFinalizerUnitTest| so that both |InstallFinalizer| implementations
+// are tested.
 class BookmarkAppInstallFinalizerTest : public ChromeRenderViewHostTestHarness {
  public:
   // Subclass that runs a closure when an extension is unpacked successfully.
@@ -204,31 +207,6 @@
   DISALLOW_COPY_AND_ASSIGN(BookmarkAppInstallFinalizerTest);
 };
 
-TEST_F(BookmarkAppInstallFinalizerTest, BasicInstallSucceeds) {
-  auto info = std::make_unique<WebApplicationInfo>();
-  info->app_url = WebAppUrl();
-  info->title = base::ASCIIToUTF16(kWebAppTitle);
-
-  base::RunLoop run_loop;
-  web_app::InstallFinalizer::FinalizeOptions options;
-  options.install_source = WebappInstallSource::INTERNAL_DEFAULT;
-  web_app::AppId app_id;
-  bool callback_called = false;
-
-  finalizer().FinalizeInstall(
-      *info, options,
-      base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id,
-                                     web_app::InstallResultCode code) {
-        EXPECT_EQ(web_app::InstallResultCode::kSuccessNewInstall, code);
-        app_id = installed_app_id;
-        callback_called = true;
-        run_loop.Quit();
-      }));
-  run_loop.Run();
-
-  EXPECT_TRUE(callback_called);
-}
-
 TEST_F(BookmarkAppInstallFinalizerTest, BasicInstallButExtensionIsDisabled) {
   base::HistogramTester histograms;
 
diff --git a/chrome/browser/web_applications/web_app_install_finalizer.cc b/chrome/browser/web_applications/web_app_install_finalizer.cc
index 44beb947..81717881 100644
--- a/chrome/browser/web_applications/web_app_install_finalizer.cc
+++ b/chrome/browser/web_applications/web_app_install_finalizer.cc
@@ -167,6 +167,8 @@
   web_app->AddSource(source);
   web_app->SetIsInSyncInstall(false);
 
+  UpdateIntWebAppPref(profile_->GetPrefs(), app_id, kLatestWebAppInstallSource,
+                      static_cast<int>(options.install_source));
   SetWebAppManifestFieldsAndWriteData(web_app_info, std::move(web_app),
                                       /*is_new_install=*/true,
                                       std::move(callback));
@@ -197,6 +199,9 @@
       GenerateIcons(web_app->sync_data().name, background_icon_color);
   web_app->SetDownloadedIconSizes(GetSquareSizePxs(icon_bitmaps));
 
+  UpdateIntWebAppPref(profile_->GetPrefs(), app_id, kLatestWebAppInstallSource,
+                      static_cast<int>(WebappInstallSource::SYNC));
+
   InstallFinalizedCallback fallback_install_callback =
       base::BindOnce(&WebAppInstallFinalizer::OnFallbackInstallFinalized,
                      weak_ptr_factory_.GetWeakPtr(),
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 2b74861..690514b 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -168,6 +168,11 @@
 const base::Feature kCrostiniArcSideload{"CrostiniArcSideload",
                                          base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Enables distributed model for TPM1.2, i.e., using tpm_managerd and
+// attestationd.
+const base::Feature kCryptohomeDistributedModel{
+    "CryptohomeDistributedModel", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enable support for "Plugin VMs" on Chrome OS.
 const base::Feature kPluginVm{"PluginVm", base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index d8623c4..4800c40 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -106,6 +106,8 @@
 extern const base::Feature kCrostiniForceClose;
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kCrostiniArcSideload;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kCryptohomeDistributedModel;
 COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kPluginVm;
 COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kPrintServerUi;
 COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kTerminalSystemApp;
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 3ad5fa7..b5e5a0c2 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -628,10 +628,6 @@
 const char kShowMobileDataNotification[] =
     "settings.internet.mobile.show_3g_promo_notification";
 
-// An integer pref counting times Data Saver prompt has been shown.
-const char kDataSaverPromptsShown[] =
-    "settings.internet.mobile.datasaver_prompts_shown";
-
 // A string pref that contains version where "What's new" promo was shown.
 const char kChromeOSReleaseNotesVersion[] = "settings.release_notes.version";
 
@@ -2090,11 +2086,6 @@
 // "xkb:us::eng".
 const char kHardwareKeyboardLayout[] = "intl.hardware_keyboard";
 
-// An integer pref which shows number of times carrier deal promo
-// notification has been shown to user.
-const char kCarrierDealPromoShown[] =
-    "settings.internet.mobile.carrier_deal_promo_shown";
-
 // A boolean pref of the auto-enrollment decision. Its value is only valid if
 // it's not the default value; otherwise, no auto-enrollment decision has been
 // made yet.
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index c5d2db9..53cf03d 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -242,7 +242,6 @@
 extern const char kLabsAdvancedFilesystemEnabled[];
 extern const char kLabsMediaplayerEnabled[];
 extern const char kShowMobileDataNotification[];
-extern const char kDataSaverPromptsShown[];
 extern const char kChromeOSReleaseNotesVersion[];
 extern const char kNoteTakingAppId[];
 extern const char kNoteTakingAppEnabledOnLockScreen[];
@@ -674,7 +673,6 @@
 extern const char kDemoModeDefaultLocale[];
 extern const char kDeviceSettingsCache[];
 extern const char kHardwareKeyboardLayout[];
-extern const char kCarrierDealPromoShown[];
 extern const char kShouldAutoEnroll[];
 extern const char kAutoEnrollmentPowerLimit[];
 extern const char kDeviceActivityTimes[];
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
index f2c36a0d..6dd8726 100644
--- a/chrome/renderer/chrome_content_renderer_client.cc
+++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -92,6 +92,8 @@
 #include "components/subresource_filter/content/renderer/unverified_ruleset_dealer.h"
 #include "components/subresource_filter/core/common/common_features.h"
 #include "components/sync/engine/sync_engine_switches.h"
+#include "components/translate/content/renderer/per_frame_translate_agent.h"
+#include "components/translate/core/common/translate_util.h"
 #include "components/variations/net/variations_http_headers.h"
 #include "components/variations/variations_switches.h"
 #include "components/version_info/version_info.h"
@@ -593,6 +595,10 @@
     new previews::ResourceLoadingHintsAgent(
         render_frame_observer->associated_interfaces(), render_frame);
   }
+  if (translate::IsSubFrameTranslationEnabled()) {
+    new translate::PerFrameTranslateAgent(
+        render_frame, ISOLATED_WORLD_ID_TRANSLATE, associated_interfaces);
+  }
 
 #if !defined(OS_ANDROID)
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
diff --git a/chrome/renderer/chrome_render_frame_observer.cc b/chrome/renderer/chrome_render_frame_observer.cc
index fc5ba67..ac6ba14b9 100644
--- a/chrome/renderer/chrome_render_frame_observer.cc
+++ b/chrome/renderer/chrome_render_frame_observer.cc
@@ -30,6 +30,7 @@
 #include "components/crash/core/common/crash_key.h"
 #include "components/offline_pages/buildflags/buildflags.h"
 #include "components/translate/content/renderer/translate_agent.h"
+#include "components/translate/core/common/translate_util.h"
 #include "components/web_cache/renderer/web_cache_impl.h"
 #include "content/public/common/bindings_policy.h"
 #include "content/public/renderer/render_frame.h"
@@ -135,8 +136,11 @@
   if (!command_line.HasSwitch(switches::kDisableClientSidePhishingDetection))
     SetClientSidePhishingDetection(true);
 #endif
-  translate_agent_ = new translate::TranslateAgent(
-      render_frame, ISOLATED_WORLD_ID_TRANSLATE, extensions::kExtensionScheme);
+  if (!translate::IsSubFrameTranslationEnabled()) {
+    translate_agent_ =
+        new translate::TranslateAgent(render_frame, ISOLATED_WORLD_ID_TRANSLATE,
+                                      extensions::kExtensionScheme);
+  }
 }
 
 ChromeRenderFrameObserver::~ChromeRenderFrameObserver() {
@@ -473,6 +477,16 @@
   if (prerender::PrerenderHelper::IsPrerendering(render_frame()))
     return;
 
+    // Don't capture contents unless there is either a translate agent or a
+    // phishing classifier to consume them.
+#if BUILDFLAG(SAFE_BROWSING_CSD)
+  if (!translate_agent_ && !phishing_classifier_)
+    return;
+#else
+  if (!translate_agent_)
+    return;
+#endif
+
   base::TimeTicks capture_begin_time = base::TimeTicks::Now();
 
   // Retrieve the frame's full text (up to kMaxIndexChars), and pass it to the
diff --git a/chrome/renderer/translate/per_frame_translate_agent_browsertest.cc b/chrome/renderer/translate/per_frame_translate_agent_browsertest.cc
new file mode 100644
index 0000000..ffe84b4
--- /dev/null
+++ b/chrome/renderer/translate/per_frame_translate_agent_browsertest.cc
@@ -0,0 +1,516 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <tuple>
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/time/time.h"
+#include "chrome/common/chrome_isolated_world_ids.h"
+#include "chrome/test/base/chrome_render_view_test.h"
+#include "components/translate/content/common/translate.mojom.h"
+#include "components/translate/content/renderer/per_frame_translate_agent.h"
+#include "components/translate/core/common/translate_constants.h"
+#include "content/public/renderer/render_frame.h"
+#include "content/public/renderer/render_view.h"
+#include "extensions/common/constants.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::AtLeast;
+using testing::Return;
+
+class PerFrameTranslateAgent : public translate::PerFrameTranslateAgent {
+ public:
+  explicit PerFrameTranslateAgent(content::RenderFrame* render_frame)
+      : translate::PerFrameTranslateAgent(
+            render_frame,
+            ISOLATED_WORLD_ID_TRANSLATE,
+            render_frame->GetAssociatedInterfaceRegistry()) {}
+
+  base::TimeDelta AdjustDelay(int delayInMs) override {
+    // Just returns base::TimeDelta() which has initial value 0.
+    // Tasks doesn't need to be delayed in tests.
+    return base::TimeDelta();
+  }
+
+  void CallGetWebLanguageDetectionDetails() {
+    // Reset result values firstly.
+    detected_language_details_ = false;
+    detected_content_meta_lang_ = base::nullopt;
+    detected_html_root_lang_ = base::nullopt;
+    detected_has_notranslate_meta_ = false;
+
+    // Will get new result values via OnWebLanguageDetectionDetails.
+    GetWebLanguageDetectionDetails(
+        base::Bind(&PerFrameTranslateAgent::OnWebLanguageDetectionDetails,
+                   base::Unretained(this)));
+  }
+
+  bool GetDetectedDetails(std::string* content_meta_lang,
+                          std::string* html_root_lang,
+                          bool* has_notranslate_meta) {
+    if (!detected_language_details_)
+      return false;
+    if (content_meta_lang)
+      *content_meta_lang = *detected_content_meta_lang_;
+    if (html_root_lang)
+      *html_root_lang = *detected_html_root_lang_;
+    if (has_notranslate_meta)
+      *has_notranslate_meta = detected_has_notranslate_meta_;
+    return true;
+  }
+
+  void CallTranslateFrame(const std::string& source_lang,
+                          const std::string& target_lang,
+                          const std::string& translate_script) {
+    // Reset result values firstly.
+    page_translated_ = false;
+    trans_result_cancelled_ = false;
+    trans_result_original_lang_ = base::nullopt;
+    trans_result_translated_lang_ = base::nullopt;
+    trans_result_error_type_ = translate::TranslateErrors::NONE;
+
+    // Will get new result values via OnPageTranslated.
+    TranslateFrame(translate_script, source_lang, target_lang,
+                   base::BindOnce(&PerFrameTranslateAgent::OnPageTranslated,
+                                  base::Unretained(this)));
+  }
+
+  bool GetPageTranslatedResult(std::string* original_lang,
+                               std::string* target_lang,
+                               translate::TranslateErrors::Type* error) {
+    if (!page_translated_)
+      return false;
+    if (original_lang)
+      *original_lang = *trans_result_original_lang_;
+    if (target_lang)
+      *target_lang = *trans_result_translated_lang_;
+    if (error)
+      *error = trans_result_error_type_;
+    return true;
+  }
+
+  MOCK_METHOD0(IsTranslateLibAvailable, bool());
+  MOCK_METHOD0(IsTranslateLibReady, bool());
+  MOCK_METHOD0(HasTranslationFinished, bool());
+  MOCK_METHOD0(HasTranslationFailed, bool());
+  MOCK_METHOD0(GetOriginalPageLanguage, std::string());
+  MOCK_METHOD0(GetErrorCode, int64_t());
+  MOCK_METHOD0(StartTranslation, bool());
+  MOCK_METHOD1(ExecuteScript, void(const std::string&));
+  MOCK_METHOD2(ExecuteScriptAndGetBoolResult, bool(const std::string&, bool));
+  MOCK_METHOD1(ExecuteScriptAndGetStringResult,
+               std::string(const std::string&));
+  MOCK_METHOD1(ExecuteScriptAndGetDoubleResult, double(const std::string&));
+  MOCK_METHOD1(ExecuteScriptAndGetIntegerResult, int64_t(const std::string&));
+
+ private:
+  void OnWebLanguageDetectionDetails(const std::string& content_meta_language,
+                                     const std::string& html_root_lang,
+                                     const GURL& url,
+                                     bool has_notranslate_meta) {
+    detected_language_details_ = true;
+    detected_content_meta_lang_ = content_meta_language;
+    detected_html_root_lang_ = html_root_lang;
+    detected_has_notranslate_meta_ = has_notranslate_meta;
+  }
+
+  void OnPageTranslated(bool cancelled,
+                        const std::string& original_lang,
+                        const std::string& translated_lang,
+                        translate::TranslateErrors::Type error_type) {
+    page_translated_ = true;
+    trans_result_cancelled_ = cancelled;
+    trans_result_original_lang_ = original_lang;
+    trans_result_translated_lang_ = translated_lang;
+    trans_result_error_type_ = error_type;
+  }
+
+  bool detected_language_details_;
+  base::Optional<std::string> detected_content_meta_lang_;
+  base::Optional<std::string> detected_html_root_lang_;
+  bool detected_has_notranslate_meta_;
+
+  bool page_translated_;
+  bool trans_result_cancelled_;
+  base::Optional<std::string> trans_result_original_lang_;
+  base::Optional<std::string> trans_result_translated_lang_;
+  translate::TranslateErrors::Type trans_result_error_type_;
+
+  DISALLOW_COPY_AND_ASSIGN(PerFrameTranslateAgent);
+};
+
+class PerFrameTranslateAgentBrowserTest : public ChromeRenderViewTest {
+ public:
+  PerFrameTranslateAgentBrowserTest() : translate_agent_(nullptr) {}
+
+ protected:
+  void SetUp() override {
+    ChromeRenderViewTest::SetUp();
+    translate_agent_ = new PerFrameTranslateAgent(view_->GetMainRenderFrame());
+  }
+
+  void TearDown() override {
+    delete translate_agent_;
+    ChromeRenderViewTest::TearDown();
+  }
+
+  PerFrameTranslateAgent* translate_agent_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PerFrameTranslateAgentBrowserTest);
+};
+
+// Tests that the browser gets notified of the translation failure if the
+// translate library fails/times-out during initialization.
+TEST_F(PerFrameTranslateAgentBrowserTest, TranslateLibNeverReady) {
+  // We make IsTranslateLibAvailable true so we don't attempt to inject the
+  // library.
+  EXPECT_CALL(*translate_agent_, IsTranslateLibAvailable())
+      .Times(AtLeast(1))
+      .WillRepeatedly(Return(true));
+
+  EXPECT_CALL(*translate_agent_, IsTranslateLibReady())
+      .Times(AtLeast(5))  // See kMaxTranslateInitCheckAttempts in
+                          // translate_agent.cc
+      .WillRepeatedly(Return(false));
+
+  EXPECT_CALL(*translate_agent_, GetErrorCode())
+      .Times(AtLeast(5))
+      .WillRepeatedly(Return(translate::TranslateErrors::NONE));
+
+  translate_agent_->CallTranslateFrame("en", "fr", std::string());
+  base::RunLoop().RunUntilIdle();
+
+  translate::TranslateErrors::Type error;
+  ASSERT_TRUE(
+      translate_agent_->GetPageTranslatedResult(nullptr, nullptr, &error));
+  EXPECT_EQ(translate::TranslateErrors::TRANSLATION_TIMEOUT, error);
+}
+
+// Tests that the browser gets notified of the translation success when the
+// translation succeeds.
+TEST_F(PerFrameTranslateAgentBrowserTest, TranslateSuccess) {
+  // We make IsTranslateLibAvailable true so we don't attempt to inject the
+  // library.
+  EXPECT_CALL(*translate_agent_, IsTranslateLibAvailable())
+      .Times(AtLeast(1))
+      .WillRepeatedly(Return(true));
+
+  EXPECT_CALL(*translate_agent_, IsTranslateLibReady())
+      .WillOnce(Return(false))
+      .WillOnce(Return(true));
+
+  EXPECT_CALL(*translate_agent_, GetErrorCode())
+      .WillOnce(Return(translate::TranslateErrors::NONE));
+
+  EXPECT_CALL(*translate_agent_, StartTranslation()).WillOnce(Return(true));
+
+  // Succeed after few checks.
+  EXPECT_CALL(*translate_agent_, HasTranslationFailed())
+      .WillRepeatedly(Return(false));
+  EXPECT_CALL(*translate_agent_, HasTranslationFinished())
+      .WillOnce(Return(false))
+      .WillOnce(Return(false))
+      .WillOnce(Return(true));
+
+  // V8 call for performance monitoring should be ignored.
+  EXPECT_CALL(*translate_agent_, ExecuteScriptAndGetDoubleResult(_)).Times(3);
+
+  std::string original_lang("en");
+  std::string target_lang("fr");
+  translate_agent_->CallTranslateFrame(original_lang, target_lang,
+                                       std::string());
+  base::RunLoop().RunUntilIdle();
+
+  std::string received_original_lang;
+  std::string received_target_lang;
+  translate::TranslateErrors::Type error;
+  ASSERT_TRUE(translate_agent_->GetPageTranslatedResult(
+      &received_original_lang, &received_target_lang, &error));
+  EXPECT_EQ(original_lang, received_original_lang);
+  EXPECT_EQ(target_lang, received_target_lang);
+  EXPECT_EQ(translate::TranslateErrors::NONE, error);
+}
+
+// Tests that the browser gets notified of the translation failure when the
+// translation fails.
+TEST_F(PerFrameTranslateAgentBrowserTest, TranslateFailure) {
+  // We make IsTranslateLibAvailable true so we don't attempt to inject the
+  // library.
+  EXPECT_CALL(*translate_agent_, IsTranslateLibAvailable())
+      .Times(AtLeast(1))
+      .WillRepeatedly(Return(true));
+
+  EXPECT_CALL(*translate_agent_, IsTranslateLibReady()).WillOnce(Return(true));
+
+  EXPECT_CALL(*translate_agent_, StartTranslation()).WillOnce(Return(true));
+
+  // Fail after few checks.
+  EXPECT_CALL(*translate_agent_, HasTranslationFailed())
+      .WillOnce(Return(false))
+      .WillOnce(Return(false))
+      .WillOnce(Return(false))
+      .WillOnce(Return(true));
+
+  EXPECT_CALL(*translate_agent_, HasTranslationFinished())
+      .Times(AtLeast(1))
+      .WillRepeatedly(Return(false));
+
+  EXPECT_CALL(*translate_agent_, GetErrorCode())
+      .WillOnce(Return(translate::TranslateErrors::TRANSLATION_ERROR));
+
+  // V8 call for performance monitoring should be ignored.
+  EXPECT_CALL(*translate_agent_, ExecuteScriptAndGetDoubleResult(_)).Times(2);
+
+  translate_agent_->CallTranslateFrame("en", "fr", std::string());
+  base::RunLoop().RunUntilIdle();
+
+  translate::TranslateErrors::Type error;
+  ASSERT_TRUE(
+      translate_agent_->GetPageTranslatedResult(nullptr, nullptr, &error));
+  EXPECT_EQ(translate::TranslateErrors::TRANSLATION_ERROR, error);
+}
+
+// Tests that when the browser translate a page for which the language is
+// undefined we query the translate element to get the language.
+TEST_F(PerFrameTranslateAgentBrowserTest, UndefinedSourceLang) {
+  // We make IsTranslateLibAvailable true so we don't attempt to inject the
+  // library.
+  EXPECT_CALL(*translate_agent_, IsTranslateLibAvailable())
+      .Times(AtLeast(1))
+      .WillRepeatedly(Return(true));
+
+  EXPECT_CALL(*translate_agent_, IsTranslateLibReady()).WillOnce(Return(true));
+
+  EXPECT_CALL(*translate_agent_, GetOriginalPageLanguage())
+      .WillOnce(Return("de"));
+
+  EXPECT_CALL(*translate_agent_, StartTranslation()).WillOnce(Return(true));
+  EXPECT_CALL(*translate_agent_, HasTranslationFailed())
+      .WillOnce(Return(false));
+  EXPECT_CALL(*translate_agent_, HasTranslationFinished())
+      .Times(AtLeast(1))
+      .WillRepeatedly(Return(true));
+
+  // V8 call for performance monitoring should be ignored.
+  EXPECT_CALL(*translate_agent_, ExecuteScriptAndGetDoubleResult(_)).Times(3);
+
+  translate_agent_->CallTranslateFrame(translate::kUnknownLanguageCode, "fr",
+                                       std::string());
+  base::RunLoop().RunUntilIdle();
+
+  translate::TranslateErrors::Type error;
+  std::string original_lang;
+  std::string target_lang;
+  ASSERT_TRUE(translate_agent_->GetPageTranslatedResult(&original_lang,
+                                                        &target_lang, &error));
+  EXPECT_EQ("de", original_lang);
+  EXPECT_EQ("fr", target_lang);
+  EXPECT_EQ(translate::TranslateErrors::NONE, error);
+}
+
+// Tests that starting a translation while a similar one is pending does not
+// break anything.
+TEST_F(PerFrameTranslateAgentBrowserTest, MultipleSimilarTranslations) {
+  // We make IsTranslateLibAvailable true so we don't attempt to inject the
+  // library.
+  EXPECT_CALL(*translate_agent_, IsTranslateLibAvailable())
+      .Times(AtLeast(1))
+      .WillRepeatedly(Return(true));
+
+  EXPECT_CALL(*translate_agent_, IsTranslateLibReady())
+      .WillRepeatedly(Return(true));
+  EXPECT_CALL(*translate_agent_, StartTranslation())
+      .WillRepeatedly(Return(true));
+  EXPECT_CALL(*translate_agent_, HasTranslationFailed())
+      .WillRepeatedly(Return(false));
+  EXPECT_CALL(*translate_agent_, HasTranslationFinished())
+      .WillOnce(Return(true));
+
+  // V8 call for performance monitoring should be ignored.
+  EXPECT_CALL(*translate_agent_, ExecuteScriptAndGetDoubleResult(_)).Times(3);
+
+  std::string original_lang("en");
+  std::string target_lang("fr");
+  translate_agent_->CallTranslateFrame(original_lang, target_lang,
+                                       std::string());
+  // While this is running call again CallTranslateFrame to make sure noting bad
+  // happens.
+  translate_agent_->CallTranslateFrame(original_lang, target_lang,
+                                       std::string());
+  base::RunLoop().RunUntilIdle();
+
+  std::string received_original_lang;
+  std::string received_target_lang;
+  translate::TranslateErrors::Type error;
+  ASSERT_TRUE(translate_agent_->GetPageTranslatedResult(
+      &received_original_lang, &received_target_lang, &error));
+  EXPECT_EQ(original_lang, received_original_lang);
+  EXPECT_EQ(target_lang, received_target_lang);
+  EXPECT_EQ(translate::TranslateErrors::NONE, error);
+}
+
+// Tests that starting a translation while a different one is pending works.
+TEST_F(PerFrameTranslateAgentBrowserTest, MultipleDifferentTranslations) {
+  EXPECT_CALL(*translate_agent_, IsTranslateLibAvailable())
+      .Times(AtLeast(1))
+      .WillRepeatedly(Return(true));
+  EXPECT_CALL(*translate_agent_, IsTranslateLibReady())
+      .WillRepeatedly(Return(true));
+  EXPECT_CALL(*translate_agent_, StartTranslation())
+      .WillRepeatedly(Return(true));
+  EXPECT_CALL(*translate_agent_, HasTranslationFailed())
+      .WillRepeatedly(Return(false));
+  EXPECT_CALL(*translate_agent_, HasTranslationFinished())
+      .WillOnce(Return(true));
+
+  // V8 call for performance monitoring should be ignored.
+  EXPECT_CALL(*translate_agent_, ExecuteScriptAndGetDoubleResult(_)).Times(5);
+
+  std::string original_lang("en");
+  std::string target_lang("fr");
+  translate_agent_->CallTranslateFrame(original_lang, target_lang,
+                                       std::string());
+  // While this is running call again CallTranslateFrame with a new target lang.
+  std::string new_target_lang("de");
+  translate_agent_->CallTranslateFrame(original_lang, new_target_lang,
+                                       std::string());
+  base::RunLoop().RunUntilIdle();
+
+  std::string received_original_lang;
+  std::string received_target_lang;
+  translate::TranslateErrors::Type error;
+  ASSERT_TRUE(translate_agent_->GetPageTranslatedResult(
+      &received_original_lang, &received_target_lang, &error));
+  EXPECT_EQ(original_lang, received_original_lang);
+  EXPECT_EQ(new_target_lang, received_target_lang);
+  EXPECT_EQ(translate::TranslateErrors::NONE, error);
+}
+
+// Tests web language detection of the "notranslate" meta-tag.
+TEST_F(PerFrameTranslateAgentBrowserTest,
+       GetWebLanguageDetectionDetails_NoTranslateMetadata) {
+  LoadHTML("<html><body>A random page with random content.</body></html>");
+  translate_agent_->CallGetWebLanguageDetectionDetails();
+
+  base::RunLoop().RunUntilIdle();
+  std::string detected_content_meta_lang;
+  std::string detected_html_root_lang;
+  bool has_notranslate_meta;
+  ASSERT_TRUE(translate_agent_->GetDetectedDetails(&detected_content_meta_lang,
+                                                   &detected_html_root_lang,
+                                                   &has_notranslate_meta));
+  ASSERT_FALSE(has_notranslate_meta);
+
+  // Now the page specifies the META tag to prevent translation.
+  LoadHTML(
+      "<html lang=\"en\"><head><meta name=\"google\" "
+      "value=\"notranslate\"></head>"
+      "<body>A random page with random content.</body></html>");
+  translate_agent_->CallGetWebLanguageDetectionDetails();
+
+  base::RunLoop().RunUntilIdle();
+  ASSERT_TRUE(translate_agent_->GetDetectedDetails(&detected_content_meta_lang,
+                                                   &detected_html_root_lang,
+                                                   &has_notranslate_meta));
+  ASSERT_TRUE(has_notranslate_meta);
+  EXPECT_EQ("en", detected_html_root_lang);
+  EXPECT_EQ("", detected_content_meta_lang);
+
+  // Try the alternate version of the META tag (content instead of value).
+  LoadHTML(
+      "<html lang=\"en\"><head><meta name=\"google\" "
+      "content=\"notranslate\"></head>"
+      "<body>A random page with random content.</body></html>");
+  translate_agent_->CallGetWebLanguageDetectionDetails();
+
+  base::RunLoop().RunUntilIdle();
+  ASSERT_TRUE(translate_agent_->GetDetectedDetails(&detected_content_meta_lang,
+                                                   &detected_html_root_lang,
+                                                   &has_notranslate_meta));
+  ASSERT_TRUE(has_notranslate_meta);
+  EXPECT_EQ("en", detected_html_root_lang);
+  EXPECT_EQ("", detected_content_meta_lang);
+}
+
+// Tests web language detection of content-language meta tag.
+TEST_F(PerFrameTranslateAgentBrowserTest,
+       GetWebLanguageDetectionDetails_LanguageMetaTag) {
+  LoadHTML(
+      "<html><head><meta http-equiv=\"content-language\" content=\"es\">"
+      "</head><body>A random page with random content.</body></html>");
+  translate_agent_->CallGetWebLanguageDetectionDetails();
+
+  base::RunLoop().RunUntilIdle();
+  std::string detected_content_meta_lang;
+  std::string detected_html_root_lang;
+  bool has_notranslate_meta;
+  ASSERT_TRUE(translate_agent_->GetDetectedDetails(&detected_content_meta_lang,
+                                                   &detected_html_root_lang,
+                                                   &has_notranslate_meta));
+  ASSERT_FALSE(has_notranslate_meta);
+  EXPECT_EQ("es", detected_content_meta_lang);
+  EXPECT_EQ("", detected_html_root_lang);
+
+  // Makes sure we support multiple languages specified.
+  LoadHTML(
+      "<html lang=\"en,fr\"><head><meta http-equiv=\"content-language\" "
+      "content=\" fr , es,en \">"
+      "</head><body>A random page with random content.</body></html>");
+  translate_agent_->CallGetWebLanguageDetectionDetails();
+
+  base::RunLoop().RunUntilIdle();
+  ASSERT_TRUE(translate_agent_->GetDetectedDetails(&detected_content_meta_lang,
+                                                   &detected_html_root_lang,
+                                                   &has_notranslate_meta));
+  EXPECT_EQ(" fr , es,en ", detected_content_meta_lang);
+  EXPECT_EQ("en,fr", detected_html_root_lang);
+}
+
+// Tests web language detection for a back navigation.
+TEST_F(PerFrameTranslateAgentBrowserTest,
+       GetWebLanguageDetectionDetails_NavBack) {
+  LoadHTML(
+      "<html><head><meta http-equiv=\"content-language\" content=\"es\">"
+      "</head><body>This page is in Spanish.</body></html>");
+  translate_agent_->CallGetWebLanguageDetectionDetails();
+
+  base::RunLoop().RunUntilIdle();
+  std::string detected_content_meta_lang;
+  std::string detected_html_root_lang;
+  bool has_notranslate_meta;
+  ASSERT_TRUE(translate_agent_->GetDetectedDetails(&detected_content_meta_lang,
+                                                   &detected_html_root_lang,
+                                                   &has_notranslate_meta));
+  EXPECT_EQ("es", detected_content_meta_lang);
+
+  content::PageState back_state = GetCurrentPageState();
+
+  LoadHTML(
+      "<html><head><meta http-equiv=\"content-language\" content=\"fr\">"
+      "</head><body>This page is in French.</body></html>");
+  translate_agent_->CallGetWebLanguageDetectionDetails();
+
+  base::RunLoop().RunUntilIdle();
+  ASSERT_TRUE(translate_agent_->GetDetectedDetails(&detected_content_meta_lang,
+                                                   &detected_html_root_lang,
+                                                   &has_notranslate_meta));
+  EXPECT_EQ("fr", detected_content_meta_lang);
+
+  GoBack(GURL("data:text/html;charset=utf-8,<html><head>"
+              "<meta http-equiv=\"content-language\" content=\"es\">"
+              "</head><body>This page is in Spanish.</body></html>"),
+         back_state);
+  translate_agent_->CallGetWebLanguageDetectionDetails();
+
+  base::RunLoop().RunUntilIdle();
+  ASSERT_TRUE(translate_agent_->GetDetectedDetails(&detected_content_meta_lang,
+                                                   &detected_html_root_lang,
+                                                   &has_notranslate_meta));
+  EXPECT_EQ("es", detected_content_meta_lang);
+}
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 28b8ba1..b0f3565 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1396,6 +1396,7 @@
       "../renderer/chrome_render_frame_observer_browsertest.cc",
       "../renderer/content_settings_agent_impl_browsertest.cc",
       "../renderer/media/cast_session_browsertest.cc",
+      "../renderer/translate/per_frame_translate_agent_browsertest.cc",
       "../renderer/translate/translate_agent_browsertest.cc",
       "../renderer/translate/translate_script_browsertest.cc",
       "base/chrome_render_view_test.cc",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeTabUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeTabUtils.java
index a126fd7..d4b2b2e 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeTabUtils.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeTabUtils.java
@@ -225,19 +225,37 @@
      * Waits for the given tab to start loading its current page.
      *
      * @param tab The tab to wait for the page loading to be started.
+     * @param expectedUrl The expected url of the started page load.  Pass in null if starting
+     *                    any load is sufficient.
+     * @param loadTrigger The trigger action that will result in a page load started event
+     *                    to be fired (not run on the UI thread by default).
+     */
+    public static void waitForTabPageLoadStart(
+            final Tab tab, @Nullable final String expectedUrl, Runnable loadTrigger) {
+        waitForTabPageLoadStart(tab, expectedUrl, loadTrigger, CallbackHelper.WAIT_TIMEOUT_SECONDS);
+    }
+
+    /**
+     * Waits for the given tab to start loading its current page.
+     *
+     * @param tab The tab to wait for the page loading to be started.
+     * @param expectedUrl The expected url of the started page load.  Pass in null if starting
+     *                    any load is sufficient.
      * @param loadTrigger The trigger action that will result in a page load started event
      *                    to be fired (not run on the UI thread by default).
      * @param secondsToWait The number of seconds to wait for the page to be load to be started.
      */
-    public static void waitForTabPageLoadStart(
-            final Tab tab, Runnable loadTrigger, long secondsToWait) {
+    public static void waitForTabPageLoadStart(final Tab tab, @Nullable final String expectedUrl,
+            Runnable loadTrigger, long secondsToWait) {
         final CallbackHelper startedCallback = new CallbackHelper();
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             tab.addObserver(new EmptyTabObserver() {
                 @Override
                 public void onPageLoadStarted(Tab tab, String url) {
-                    startedCallback.notifyCalled();
-                    tab.removeObserver(this);
+                    if (expectedUrl == null || TextUtils.equals(url, expectedUrl)) {
+                        startedCallback.notifyCalled();
+                        tab.removeObserver(this);
+                    }
                 }
             });
         });
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
index 52ad200..21e85c5 100644
--- a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
@@ -751,7 +751,7 @@
   }
 };
 
-TEST_F('OSSettingsSearchBoxBrowserTest', 'AllJsTests', () => {
+TEST_F('OSSettingsSearchBoxBrowserTest', 'DISABLED_AllJsTests', () => {
   mocha.run();
 });
 
diff --git a/chromeos/services/assistant/assistant_manager_service_impl.cc b/chromeos/services/assistant/assistant_manager_service_impl.cc
index 09f2d62..dbcf775c 100644
--- a/chromeos/services/assistant/assistant_manager_service_impl.cc
+++ b/chromeos/services/assistant/assistant_manager_service_impl.cc
@@ -537,6 +537,11 @@
 
 void AssistantManagerServiceImpl::DismissNotification(
     mojom::AssistantNotificationPtr notification) {
+  // |assistant_manager_internal_| may not exist if we are dismissing
+  // notifications as part of a shutdown sequence.
+  if (!assistant_manager_internal_)
+    return;
+
   const std::string& notification_id = notification->server_id;
   const std::string& consistency_token = notification->consistency_token;
   const std::string& opaque_token = notification->opaque_token;
@@ -1388,6 +1393,14 @@
 void AssistantManagerServiceImpl::OnAlarmTimerStateChanged() {
   ENSURE_MAIN_THREAD(&AssistantManagerServiceImpl::OnAlarmTimerStateChanged);
 
+  // |assistant_manager_internal_| may not exist if we are receiving this event
+  // as part of a shutdown sequence. When this occurs, we notify our alarm/timer
+  // controller to clear its cache to remain in sync with LibAssistant.
+  if (!assistant_manager_internal_) {
+    assistant_alarm_timer_controller()->OnTimerStateChanged({});
+    return;
+  }
+
   std::vector<ash::mojom::AssistantTimerPtr> timers;
 
   auto* manager = assistant_manager_internal_->GetAlarmTimerManager();
diff --git a/components/autofill/core/browser/form_structure.h b/components/autofill/core/browser/form_structure.h
index 4117c49..59c1dbd 100644
--- a/components/autofill/core/browser/form_structure.h
+++ b/components/autofill/core/browser/form_structure.h
@@ -248,6 +248,8 @@
 
   bool has_password_field() const { return has_password_field_; }
 
+  bool is_form_tag() const { return is_form_tag_; }
+
   void set_submission_event(mojom::SubmissionIndicatorEvent submission_event) {
     submission_event_ = submission_event;
   }
diff --git a/components/autofill/core/browser/ui/accessory_sheet_data.cc b/components/autofill/core/browser/ui/accessory_sheet_data.cc
index a245825..fd1a0d9 100644
--- a/components/autofill/core/browser/ui/accessory_sheet_data.cc
+++ b/components/autofill/core/browser/ui/accessory_sheet_data.cc
@@ -187,7 +187,8 @@
 
 bool AccessorySheetData::operator==(const AccessorySheetData& data) const {
   return sheet_type_ == data.sheet_type_ && title_ == data.title_ &&
-         warning_ == data.warning_ && user_info_list_ == data.user_info_list_ &&
+         warning_ == data.warning_ && option_toggle_ == data.option_toggle_ &&
+         user_info_list_ == data.user_info_list_ &&
          footer_commands_ == data.footer_commands_;
 }
 
diff --git a/components/external_intents/android/BUILD.gn b/components/external_intents/android/BUILD.gn
index 2930dfa..702433e 100644
--- a/components/external_intents/android/BUILD.gn
+++ b/components/external_intents/android/BUILD.gn
@@ -12,6 +12,7 @@
     "java/src/org/chromium/components/external_intents/ExternalNavigationHandler.java",
     "java/src/org/chromium/components/external_intents/ExternalNavigationParams.java",
     "java/src/org/chromium/components/external_intents/RedirectHandler.java",
+    "java/src/org/chromium/components/external_intents/RedirectHandlerImpl.java",
   ]
 
   annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
@@ -41,3 +42,16 @@
     "//base",
   ]
 }
+
+android_library("javatests") {
+  testonly = true
+
+  sources = [ "javatests/src/org/chromium/components/external_intents/RedirectHandlerTest.java" ]
+  deps = [
+    ":java",
+    "//base:base_java",
+    "//base:base_java_test_support",
+    "//third_party/android_deps:androidx_core_core_java",
+    "//ui/android:ui_java",
+  ]
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabRedirectHandler.java b/components/external_intents/android/java/src/org/chromium/components/external_intents/RedirectHandlerImpl.java
similarity index 95%
rename from chrome/android/java/src/org/chromium/chrome/browser/tab/TabRedirectHandler.java
rename to components/external_intents/android/java/src/org/chromium/components/external_intents/RedirectHandlerImpl.java
index 6b17c24..d9800ee 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabRedirectHandler.java
+++ b/components/external_intents/android/java/src/org/chromium/components/external_intents/RedirectHandlerImpl.java
@@ -2,7 +2,7 @@
 // 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.tab;
+package org.chromium.components.external_intents;
 
 import android.content.ComponentName;
 import android.content.Intent;
@@ -14,7 +14,6 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.IntentUtils;
 import org.chromium.base.PackageManagerUtils;
-import org.chromium.components.external_intents.RedirectHandler;
 import org.chromium.ui.base.PageTransition;
 
 import java.util.HashSet;
@@ -23,7 +22,7 @@
 /**
  * This class contains the logic to determine effective navigation/redirect.
  */
-public class TabRedirectHandler implements RedirectHandler {
+public class RedirectHandlerImpl implements RedirectHandler {
     /**
      * An invalid entry index.
      */
@@ -50,11 +49,11 @@
 
     private boolean mShouldNotOverrideUrlLoadingOnCurrentRedirectChain;
 
-    public static TabRedirectHandler create() {
-        return new TabRedirectHandler();
+    public static RedirectHandlerImpl create() {
+        return new RedirectHandlerImpl();
     }
 
-    protected TabRedirectHandler() {}
+    protected RedirectHandlerImpl() {}
 
     /**
      * Updates |mIntentHistory| and |mLastIntentUpdatedTime|. If |intent| comes from chrome and
@@ -92,8 +91,8 @@
     private static boolean isIntentToChrome(Intent intent) {
         String chromePackageName = ContextUtils.getApplicationContext().getPackageName();
         return TextUtils.equals(chromePackageName, intent.getPackage())
-                || TextUtils.equals(chromePackageName, IntentUtils.safeGetStringExtra(intent,
-                        Browser.EXTRA_APPLICATION_ID));
+                || TextUtils.equals(chromePackageName,
+                        IntentUtils.safeGetStringExtra(intent, Browser.EXTRA_APPLICATION_ID));
     }
 
     private void clearIntentHistory() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabRedirectHandlerTest.java b/components/external_intents/android/javatests/src/org/chromium/components/external_intents/RedirectHandlerTest.java
similarity index 92%
rename from chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabRedirectHandlerTest.java
rename to components/external_intents/android/javatests/src/org/chromium/components/external_intents/RedirectHandlerTest.java
index 027de0e..d529bd94 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabRedirectHandlerTest.java
+++ b/components/external_intents/android/javatests/src/org/chromium/components/external_intents/RedirectHandlerTest.java
@@ -2,7 +2,7 @@
 // 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.tab;
+package org.chromium.components.external_intents;
 
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -21,10 +21,10 @@
 import org.chromium.base.CommandLine;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.PackageManagerUtils;
+import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.AdvancedMockContext;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.RetryOnFailure;
-import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.ui.base.PageTransition;
 
 import java.net.URISyntaxException;
@@ -34,8 +34,8 @@
 /**
  * Unittests for tab redirect handler.
  */
-@RunWith(ChromeJUnit4ClassRunner.class)
-public class TabRedirectHandlerTest {
+@RunWith(BaseJUnit4ClassRunner.class)
+public class RedirectHandlerTest {
     private static final int TRANS_TYPE_OF_LINK_FROM_INTENT =
             PageTransition.LINK | PageTransition.FROM_API;
     private static final String TEST_PACKAGE_NAME = "test.package.name";
@@ -67,7 +67,7 @@
     @SmallTest
     @Feature({"IntentHandling"})
     public void testRealIntentRedirect() {
-        TabRedirectHandler handler = TabRedirectHandler.create();
+        RedirectHandlerImpl handler = RedirectHandlerImpl.create();
         handler.updateIntent(sYtIntent, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
 
@@ -87,7 +87,7 @@
     @SmallTest
     @Feature({"IntentHandling"})
     public void testEffectiveIntentRedirect_linkNavigation() {
-        TabRedirectHandler handler = TabRedirectHandler.create();
+        RedirectHandlerImpl handler = RedirectHandlerImpl.create();
         handler.updateIntent(sYtIntent, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
 
@@ -107,7 +107,7 @@
     @SmallTest
     @Feature({"IntentHandling"})
     public void testEffectiveIntentRedirect_formSubmit() {
-        TabRedirectHandler handler = TabRedirectHandler.create();
+        RedirectHandlerImpl handler = RedirectHandlerImpl.create();
         handler.updateIntent(sYtIntent, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
 
@@ -127,7 +127,7 @@
     @SmallTest
     @Feature({"IntentHandling"})
     public void testNoIntent() {
-        TabRedirectHandler handler = TabRedirectHandler.create();
+        RedirectHandlerImpl handler = RedirectHandlerImpl.create();
         handler.updateIntent(null, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
 
@@ -147,7 +147,7 @@
     @SmallTest
     @Feature({"IntentHandling"})
     public void testClear() {
-        TabRedirectHandler handler = TabRedirectHandler.create();
+        RedirectHandlerImpl handler = RedirectHandlerImpl.create();
         handler.updateIntent(sYtIntent, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
 
@@ -172,7 +172,7 @@
     @SmallTest
     @Feature({"IntentHandling"})
     public void testNonLinkFromIntent() {
-        TabRedirectHandler handler = TabRedirectHandler.create();
+        RedirectHandlerImpl handler = RedirectHandlerImpl.create();
         handler.updateIntent(sYtIntent, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
 
@@ -192,7 +192,7 @@
     @SmallTest
     @Feature({"IntentHandling"})
     public void testUserInteraction() {
-        TabRedirectHandler handler = TabRedirectHandler.create();
+        RedirectHandlerImpl handler = RedirectHandlerImpl.create();
         handler.updateIntent(sYtIntent, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
 
@@ -221,7 +221,7 @@
     @SmallTest
     @Feature({"IntentHandling"})
     public void testIntentFromChrome() {
-        TabRedirectHandler handler = TabRedirectHandler.create();
+        RedirectHandlerImpl handler = RedirectHandlerImpl.create();
         Intent fooIntent = new Intent(sFooIntent);
         fooIntent.putExtra(Browser.EXTRA_APPLICATION_ID, TEST_PACKAGE_NAME);
         handler.updateIntent(fooIntent, false, false, false);
@@ -253,7 +253,7 @@
     @SmallTest
     @Feature({"IntentHandling"})
     public void testNavigationFromUserTyping() {
-        TabRedirectHandler handler = TabRedirectHandler.create();
+        RedirectHandlerImpl handler = RedirectHandlerImpl.create();
         handler.updateIntent(sYtIntent, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
         Assert.assertFalse(handler.isNavigationFromUserTyping());
@@ -279,7 +279,7 @@
     @SmallTest
     @Feature({"IntentHandling"})
     public void testIntentHavingChromePackageName() {
-        TabRedirectHandler handler = TabRedirectHandler.create();
+        RedirectHandlerImpl handler = RedirectHandlerImpl.create();
         Intent fooIntent = new Intent(sFooIntent);
         fooIntent.setPackage(TEST_PACKAGE_NAME);
         handler.updateIntent(fooIntent, false, false, false);
@@ -314,7 +314,7 @@
         /////////////////////////////////////////////////////
         // 1. 3XX redirection should not override URL loading.
         /////////////////////////////////////////////////////
-        TabRedirectHandler handler = TabRedirectHandler.create();
+        RedirectHandlerImpl handler = RedirectHandlerImpl.create();
         handler.updateIntent(sYtIntent, false, false, false);
         Assert.assertFalse(handler.shouldNotOverrideUrlLoading());
 
@@ -328,7 +328,7 @@
         /////////////////////////////////////////////////////
         // 2. Effective redirection should not override URL loading.
         /////////////////////////////////////////////////////
-        handler = TabRedirectHandler.create();
+        handler = RedirectHandlerImpl.create();
         handler.updateIntent(sYtIntent, false, false, false);
         Assert.assertFalse(handler.shouldNotOverrideUrlLoading());
 
@@ -355,7 +355,7 @@
     @Feature({"IntentHandling"})
     @RetryOnFailure
     public void testNavigationFromLinkWithoutUserGesture() {
-        TabRedirectHandler handler = TabRedirectHandler.create();
+        RedirectHandlerImpl handler = RedirectHandlerImpl.create();
         handler.updateIntent(sYtIntent, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
         Assert.assertFalse(handler.shouldStayInApp(false));
@@ -388,7 +388,7 @@
     @Feature({"IntentHandling"})
     @RetryOnFailure
     public void testNavigationFromReload() {
-        TabRedirectHandler handler = TabRedirectHandler.create();
+        RedirectHandlerImpl handler = RedirectHandlerImpl.create();
         handler.updateIntent(sYtIntent, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
         Assert.assertFalse(handler.shouldStayInApp(false));
@@ -421,14 +421,14 @@
     @Feature({"IntentHandling"})
     @RetryOnFailure
     public void testNavigationWithForwardBack() {
-        TabRedirectHandler handler = TabRedirectHandler.create();
+        RedirectHandlerImpl handler = RedirectHandlerImpl.create();
         handler.updateIntent(sYtIntent, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
         Assert.assertFalse(handler.shouldStayInApp(false));
         Assert.assertFalse(handler.shouldStayInApp(true));
 
-        handler.updateNewUrlLoading(PageTransition.FORM_SUBMIT | PageTransition.FORWARD_BACK,
-                false, true, SystemClock.elapsedRealtime(), 0);
+        handler.updateNewUrlLoading(PageTransition.FORM_SUBMIT | PageTransition.FORWARD_BACK, false,
+                true, SystemClock.elapsedRealtime(), 0);
         Assert.assertTrue(handler.shouldStayInApp(false));
         Assert.assertTrue(handler.shouldStayInApp(true));
         handler.updateNewUrlLoading(
@@ -456,13 +456,13 @@
         // User interaction time could be uninitialized when a new document activity is opened after
         // clicking a link. In that case, the value is 0.
         final long uninitializedUserInteractionTime = 0;
-        TabRedirectHandler handler = TabRedirectHandler.create();
+        RedirectHandlerImpl handler = RedirectHandlerImpl.create();
 
         Assert.assertFalse(handler.isOnNavigation());
         handler.updateNewUrlLoading(PageTransition.LINK, false, true,
-                uninitializedUserInteractionTime, TabRedirectHandler.INVALID_ENTRY_INDEX);
+                uninitializedUserInteractionTime, RedirectHandlerImpl.INVALID_ENTRY_INDEX);
         Assert.assertTrue(handler.isOnNavigation());
-        Assert.assertEquals(TabRedirectHandler.INVALID_ENTRY_INDEX,
+        Assert.assertEquals(RedirectHandlerImpl.INVALID_ENTRY_INDEX,
                 handler.getLastCommittedEntryIndexBeforeStartingNavigation());
     }
 
@@ -474,7 +474,7 @@
     @SmallTest
     @Feature({"IntentHandling"})
     public void testClientRedirectWithoutUserGesture() {
-        TabRedirectHandler handler = TabRedirectHandler.create();
+        RedirectHandlerImpl handler = RedirectHandlerImpl.create();
         handler.updateIntent(sFooIntent, false, false, false);
         Assert.assertFalse(handler.isOnNavigation());
 
@@ -488,7 +488,7 @@
         public List<ResolveInfo> queryIntentActivities(Intent intent, int flags) {
             List<ResolveInfo> resolves = new ArrayList<ResolveInfo>();
             if (intent.getDataString().startsWith("http://m.youtube.com")
-                    ||  intent.getDataString().startsWith("http://youtube.com")) {
+                    || intent.getDataString().startsWith("http://youtube.com")) {
                 ResolveInfo youTubeApp = new ResolveInfo();
                 youTubeApp.activityInfo = new ActivityInfo();
                 youTubeApp.activityInfo.packageName = "youtube";
diff --git a/components/metrics/metrics_pref_names.cc b/components/metrics/metrics_pref_names.cc
index 5ab8d56..63250e1 100644
--- a/components/metrics/metrics_pref_names.cc
+++ b/components/metrics/metrics_pref_names.cc
@@ -103,12 +103,6 @@
 const char kStabilityCrashCountDueToGmsCoreUpdate[] =
     "user_experience_metrics.stability.crash_count_due_to_gms_core_update";
 
-// Number of times the application exited uncleanly since the last report
-// without gms core update (Deprecated 2018-09).
-// TODO(wnwen): Remove this after 2019-09.
-const char kStabilityCrashCountWithoutGmsCoreUpdateObsolete[] =
-    "user_experience_metrics.stability.crash_count_without_gms_core_update";
-
 // Number of times the initial stability log upload was deferred to the next
 // startup.
 const char kStabilityDeferredCount[] =
@@ -127,11 +121,6 @@
 const char kStabilityDebuggerNotPresent[] =
     "user_experience_metrics.stability.debugger_not_present";
 
-// An enum value to indicate the execution phase the browser was in.
-// TODO(asvitkine): Remove this after 2019-12.
-const char kStabilityExecutionPhase[] =
-    "user_experience_metrics.stability.execution_phase";
-
 // True if the previous run of the program exited cleanly.
 const char kStabilityExitedCleanly[] =
     "user_experience_metrics.stability.exited_cleanly";
diff --git a/components/metrics/metrics_pref_names.h b/components/metrics/metrics_pref_names.h
index 297e97a..ae1376cb 100644
--- a/components/metrics/metrics_pref_names.h
+++ b/components/metrics/metrics_pref_names.h
@@ -37,12 +37,10 @@
 extern const char kStabilityChildProcessCrashCount[];
 extern const char kStabilityCrashCount[];
 extern const char kStabilityCrashCountDueToGmsCoreUpdate[];
-extern const char kStabilityCrashCountWithoutGmsCoreUpdateObsolete[];
 extern const char kStabilityDebuggerNotPresent[];
 extern const char kStabilityDebuggerPresent[];
 extern const char kStabilityDeferredCount[];
 extern const char kStabilityDiscardCount[];
-extern const char kStabilityExecutionPhase[];
 extern const char kStabilityExitedCleanly[];
 extern const char kStabilityExtensionRendererCrashCount[];
 extern const char kStabilityExtensionRendererFailedLaunchCount[];
diff --git a/components/metrics/stability_metrics_provider.cc b/components/metrics/stability_metrics_provider.cc
index f13597fa..5e080db 100644
--- a/components/metrics/stability_metrics_provider.cc
+++ b/components/metrics/stability_metrics_provider.cc
@@ -71,9 +71,6 @@
   registry->RegisterStringPref(prefs::kStabilityGmsCoreVersion, "");
   registry->RegisterIntegerPref(prefs::kStabilityCrashCountDueToGmsCoreUpdate,
                                 0);
-  // Obsolete. See MigrateObsoleteBrowserPrefs().
-  registry->RegisterIntegerPref(
-      prefs::kStabilityCrashCountWithoutGmsCoreUpdateObsolete, 0);
 #endif
 #if defined(OS_WIN)
   registry->RegisterIntegerPref(prefs::kStabilitySystemCrashCount, 0);
diff --git a/components/openscreen_platform/BUILD.gn b/components/openscreen_platform/BUILD.gn
index 7521443..7418f68 100644
--- a/components/openscreen_platform/BUILD.gn
+++ b/components/openscreen_platform/BUILD.gn
@@ -15,9 +15,7 @@
     "trace_logging_platform.cc",
   ]
 
-  public_deps = [
-    "//third_party/openscreen/src/platform",
-  ]
+  public_deps = [ "//third_party/openscreen/src/platform" ]
 
   deps = [
     "//base",
@@ -27,6 +25,8 @@
 
 source_set("openscreen_platform_network_service") {
   sources = [
+    "network_context.cc",
+    "network_context.h",
     "tls_client_connection.cc",
     "tls_client_connection.h",
     "tls_connection_factory.cc",
diff --git a/components/openscreen_platform/network_context.cc b/components/openscreen_platform/network_context.cc
new file mode 100644
index 0000000..0dfa5e0
--- /dev/null
+++ b/components/openscreen_platform/network_context.cc
@@ -0,0 +1,35 @@
+// Copyright 2020 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/openscreen_platform/network_context.h"
+
+namespace openscreen_platform {
+namespace {
+
+static NetworkContextGetter* GetInstance() {
+  static NetworkContextGetter* getter = new NetworkContextGetter();
+  return getter;
+}
+
+}  // namespace
+
+void SetNetworkContextGetter(NetworkContextGetter network_context_getter) {
+  NetworkContextGetter* getter = GetInstance();
+  DCHECK(getter->is_null() || network_context_getter.is_null());
+  *getter = std::move(network_context_getter);
+}
+
+bool HasNetworkContextGetter() {
+  return !GetInstance()->is_null();
+}
+
+network::mojom::NetworkContext* GetNetworkContext() {
+  NetworkContextGetter* getter = GetInstance();
+  if (getter->is_null()) {
+    return nullptr;
+  }
+  return getter->Run();
+}
+
+}  // namespace openscreen_platform
diff --git a/components/openscreen_platform/network_context.h b/components/openscreen_platform/network_context.h
new file mode 100644
index 0000000..0cc5b52
--- /dev/null
+++ b/components/openscreen_platform/network_context.h
@@ -0,0 +1,31 @@
+// Copyright 2020 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_OPENSCREEN_PLATFORM_NETWORK_CONTEXT_H_
+#define COMPONENTS_OPENSCREEN_PLATFORM_NETWORK_CONTEXT_H_
+
+#include "base/bind.h"
+#include "services/network/public/mojom/network_context.mojom.h"
+
+namespace openscreen_platform {
+
+using NetworkContextGetter =
+    base::RepeatingCallback<network::mojom::NetworkContext*()>;
+
+void SetNetworkContextGetter(NetworkContextGetter network_context_getter);
+bool HasNetworkContextGetter();
+
+// This and all subsequent NetworkContext calls made must obey the thread safety
+// requirements of |network_context_getter|.  This must be called each time a
+// mojom::NetworkContext is needed; any returned pointer should not be stored
+// beyond the scope in which it is received.
+//
+// In Chrome, the |network_context_getter| will always return the NetworkContext
+// from the SystemNetworkContextManager; therefore, GetNetworkContext must be
+// called on the UI thread.
+network::mojom::NetworkContext* GetNetworkContext();
+
+}  // namespace openscreen_platform
+
+#endif  // COMPONENTS_OPENSCREEN_PLATFORM_NETWORK_CONTEXT_H_
diff --git a/components/openscreen_platform/tls_connection_factory.cc b/components/openscreen_platform/tls_connection_factory.cc
index 94a9f49..b417cf20 100644
--- a/components/openscreen_platform/tls_connection_factory.cc
+++ b/components/openscreen_platform/tls_connection_factory.cc
@@ -8,12 +8,14 @@
 #include <utility>
 
 #include "base/logging.h"
+#include "components/openscreen_platform/network_context.h"
 #include "components/openscreen_platform/network_util.h"
 #include "components/openscreen_platform/tls_client_connection.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/net_errors.h"
 #include "net/ssl/ssl_info.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/public/mojom/network_context.mojom.h"
 #include "third_party/openscreen/src/platform/api/tls_connection.h"
 #include "third_party/openscreen/src/platform/base/tls_connect_options.h"
 #include "third_party/openscreen/src/platform/base/tls_credentials.h"
@@ -25,7 +27,7 @@
     Client* client,
     TaskRunner* task_runner) {
   return std::make_unique<openscreen_platform::TlsConnectionFactory>(
-      client, task_runner, nullptr /* network context */);
+      client, task_runner);
 }
 
 }  // namespace openscreen
@@ -70,8 +72,8 @@
 
 void TlsConnectionFactory::Connect(const IPEndpoint& remote_address,
                                    const TlsConnectOptions& options) {
-  network::mojom::NetworkContext* network_context = network_context_;
-  // TODO(btolsch): Add fall-back lookup in follow-up NetworkContext patch.
+  network::mojom::NetworkContext* network_context =
+      openscreen_platform::GetNetworkContext();
   if (!network_context) {
     client_->OnError(this, openscreen::Error::Code::kItemNotFound);
     return;
@@ -107,11 +109,8 @@
 
 TlsConnectionFactory::TlsConnectionFactory(
     openscreen::TlsConnectionFactory::Client* client,
-    openscreen::TaskRunner* task_runner,
-    network::mojom::NetworkContext* network_context)
-    : client_(client),
-      task_runner_(task_runner),
-      network_context_(network_context) {}
+    openscreen::TaskRunner* task_runner)
+    : client_(client), task_runner_(task_runner) {}
 
 TlsConnectionFactory::TcpConnectRequest::TcpConnectRequest(
     openscreen::TlsConnectOptions options_in,
diff --git a/components/openscreen_platform/tls_connection_factory.h b/components/openscreen_platform/tls_connection_factory.h
index 9690089..2aaad864 100644
--- a/components/openscreen_platform/tls_connection_factory.h
+++ b/components/openscreen_platform/tls_connection_factory.h
@@ -11,7 +11,6 @@
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
-#include "services/network/public/mojom/network_context.mojom.h"
 #include "services/network/public/mojom/tcp_socket.mojom.h"
 #include "services/network/public/mojom/tls_socket.mojom.h"
 #include "third_party/openscreen/src/platform/api/tls_connection_factory.h"
@@ -34,11 +33,8 @@
 
 class TlsConnectionFactory : public openscreen::TlsConnectionFactory {
  public:
-  // If provided, the network context is stored and dereferenced when attempting
-  // to connect. If not provided, the network context is dynamically looked up.
   TlsConnectionFactory(openscreen::TlsConnectionFactory::Client* client,
-                       openscreen::TaskRunner* task_runner,
-                       network::mojom::NetworkContext* network_context);
+                       openscreen::TaskRunner* task_runner);
 
   ~TlsConnectionFactory() final;
 
@@ -108,7 +104,6 @@
 
   openscreen::TlsConnectionFactory::Client* client_;
   openscreen::TaskRunner* const task_runner_;
-  network::mojom::NetworkContext* const network_context_;
   base::WeakPtrFactory<TlsConnectionFactory> weak_factory_{this};
 };
 
diff --git a/components/openscreen_platform/tls_connection_factory_unittest.cc b/components/openscreen_platform/tls_connection_factory_unittest.cc
index 7e6f4ab..e92fc7e 100644
--- a/components/openscreen_platform/tls_connection_factory_unittest.cc
+++ b/components/openscreen_platform/tls_connection_factory_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/sequenced_task_runner.h"
 #include "base/task/post_task.h"
 #include "base/test/task_environment.h"
+#include "components/openscreen_platform/network_context.h"
 #include "components/openscreen_platform/task_runner.h"
 #include "components/openscreen_platform/tls_client_connection.h"
 #include "net/base/net_errors.h"
@@ -99,19 +100,27 @@
         task_environment_->GetMainThreadTaskRunner());
 
     mock_network_context = std::make_unique<FakeNetworkContext>();
+    SetNetworkContextGetter(base::BindRepeating(
+        &TlsConnectionFactoryTest::GetNetworkContext, base::Unretained(this)));
+  }
+
+  void TearDown() override {
+    SetNetworkContextGetter(openscreen_platform::NetworkContextGetter());
+  }
+
+ protected:
+  network::mojom::NetworkContext* GetNetworkContext() {
+    return mock_network_context.get();
   }
 
   std::unique_ptr<openscreen_platform::TaskRunner> task_runner;
   std::unique_ptr<FakeNetworkContext> mock_network_context;
-
- private:
   std::unique_ptr<base::test::TaskEnvironment> task_environment_;
 };
 
 TEST_F(TlsConnectionFactoryTest, CallsNetworkContextCreateMethod) {
   StrictMock<MockTlsConnectionFactoryClient> mock_client;
-  TlsConnectionFactory factory(&mock_client, task_runner.get(),
-                               mock_network_context.get());
+  TlsConnectionFactory factory(&mock_client, task_runner.get());
 
   factory.Connect(kValidOpenscreenEndpoint, TlsConnectOptions{});
 
@@ -122,8 +131,7 @@
 TEST_F(TlsConnectionFactoryTest,
        CallsOnConnectionFailedWhenNetworkContextReportsError) {
   StrictMock<MockTlsConnectionFactoryClient> mock_client;
-  TlsConnectionFactory factory(&mock_client, task_runner.get(),
-                               mock_network_context.get());
+  TlsConnectionFactory factory(&mock_client, task_runner.get());
   EXPECT_CALL(mock_client,
               OnConnectionFailed(&factory, kValidOpenscreenEndpoint));
 
diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc
index 56ecba4..b05d227 100644
--- a/components/password_manager/core/browser/password_manager.cc
+++ b/components/password_manager/core/browser/password_manager.cc
@@ -109,19 +109,9 @@
   return false;
 }
 
-// Finds the matched form manager for |form| in |form_managers|.
-PasswordFormManager* FindMatchedManager(
-    const FormData& form,
-    const std::vector<std::unique_ptr<PasswordFormManager>>& form_managers,
-    const PasswordManagerDriver* driver) {
-  for (const auto& form_manager : form_managers) {
-    if (form_manager->DoesManage(form, driver))
-      return form_manager.get();
-  }
-  return nullptr;
-}
-
-// Finds the matched form manager with id |form_renderer_id| in |form_managers|.
+#if !defined(OS_IOS)
+// Finds the matched form manager with id |form_renderer_id| in
+// |form_managers|.
 PasswordFormManager* FindMatchedManagerByRendererId(
     uint32_t form_renderer_id,
     const std::vector<std::unique_ptr<PasswordFormManager>>& form_managers,
@@ -132,6 +122,7 @@
   }
   return nullptr;
 }
+#endif  // !defined(OS_IOS)
 
 bool HasSingleUsernameVote(const FormPredictions& form) {
   if (!base::FeatureList::IsEnabled(
@@ -191,6 +182,15 @@
   }
 }
 
+FormData SimplifiedFormDataFromFormStructure(
+    const FormStructure& form_structure) {
+  FormData form_data;
+  form_data.name = form_structure.form_name();
+  form_data.is_form_tag = form_structure.is_form_tag();
+  form_data.unique_renderer_id = form_structure.unique_renderer_id();
+  return form_data;
+}
+
 }  // namespace
 
 // static
@@ -534,8 +534,7 @@
     if (!client_->IsFillingEnabled(form_data.url))
       continue;
 
-    PasswordFormManager* manager =
-        FindMatchedManager(form_data, form_managers_, driver);
+    PasswordFormManager* manager = GetMatchedManager(driver, form_data);
 
     if (manager) {
       // This extra filling is just duplicating redundancy that was in
@@ -643,6 +642,7 @@
   return matched_manager;
 }
 
+#if !defined(OS_IOS)
 void PasswordManager::LogFirstFillingResult(PasswordManagerDriver* driver,
                                             uint32_t form_renderer_id,
                                             int32_t result) {
@@ -652,6 +652,7 @@
     return;
   matching_manager->GetMetricsRecorder()->RecordFirstFillingResult(result);
 }
+#endif  // !defined(OS_IOS)
 
 void PasswordManager::NotifyStorePasswordCalled() {
   store_password_called_ = true;
@@ -664,8 +665,7 @@
     const FormData& form,
     const base::string16& generated_password,
     const base::string16& generation_element) {
-  PasswordFormManager* form_manager =
-      FindMatchedManager(form, form_managers_, driver);
+  PasswordFormManager* form_manager = GetMatchedManager(driver, form);
   UMA_HISTOGRAM_BOOLEAN("PasswordManager.GeneratedFormHasNoFormManager",
                         !form_manager);
 
@@ -1007,8 +1007,8 @@
   for (const FormStructure* form : forms) {
     if (logger)
       logger->LogFormStructure(Logger::STRING_SERVER_PREDICTIONS, *form);
-    if (FindMatchedManagerByRendererId(form->unique_renderer_id(),
-                                       form_managers_, driver)) {
+    FormData form_data = SimplifiedFormDataFromFormStructure(*form);
+    if (GetMatchedManager(driver, form_data)) {
       // The form manager is already created.
       continue;
     }
diff --git a/components/password_manager/core/browser/password_manager.h b/components/password_manager/core/browser/password_manager.h
index daaf90fb..914121a 100644
--- a/components/password_manager/core/browser/password_manager.h
+++ b/components/password_manager/core/browser/password_manager.h
@@ -194,12 +194,14 @@
 
 #endif  // defined(UNIT_TEST)
 
+#if !defined(OS_IOS)
   // Reports the success from the renderer's PasswordAutofillAgent to fill
   // credentials into a site. This may be called multiple times, but only
   // the first result will be recorded for each PasswordFormManager.
   void LogFirstFillingResult(PasswordManagerDriver* driver,
                              uint32_t form_renderer_id,
                              int32_t result);
+#endif  // !defined(OS_IOS)
 
   // Notifies that Credential Management API function store() is called.
   void NotifyStorePasswordCalled();
diff --git a/components/password_manager/core/browser/password_manager_unittest.cc b/components/password_manager/core/browser/password_manager_unittest.cc
index 20e7e036..fad261c 100644
--- a/components/password_manager/core/browser/password_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_manager_unittest.cc
@@ -485,6 +485,27 @@
     return form;
   }
 
+  PasswordForm MakeSimpleFormWithOnlyUsernameField() {
+    PasswordForm form;
+    form.origin = GURL("http://www.google.com/a/LoginAuth");
+    form.username_element = ASCIIToUTF16("Email");
+    form.submit_element = ASCIIToUTF16("signIn");
+    form.signon_realm = "http://www.google.com/";
+    form.form_data.name = ASCIIToUTF16("username_only_form");
+    form.form_data.url = GURL("http://www.google.com/a/LoginAuth");
+    form.form_data.unique_renderer_id = 10;
+
+    FormFieldData field;
+    field.name = ASCIIToUTF16("Email");
+    field.id_attribute = field.name;
+    field.name_attribute = field.name;
+    field.form_control_type = "text";
+    field.unique_renderer_id = 2;
+    form.form_data.fields.push_back(field);
+
+    return form;
+  }
+
   PasswordForm MakeSimpleFormWithOnlyPasswordField() {
     PasswordForm form(MakeSimpleForm());
     form.username_element.clear();
@@ -2907,22 +2928,69 @@
       .WillRepeatedly(Return(true));
 
   PasswordForm form(MakeSimpleForm());
-  // Simulate that the form is incorrectly marked as sign-up, which means it can
-  // not be filled without server predictions.
-  form.form_data.fields[1].autocomplete_attribute = "new-password";
 
   // Server predictions says that this is a sign-in form. Since they have higher
   // priority than autocomplete attributes then the form should be filled.
   FormStructure form_structure(form.form_data);
   form_structure.field(1)->set_server_type(autofill::PASSWORD);
+#if !defined(OS_IOS)
   manager()->ProcessAutofillPredictions(&driver_, {&form_structure});
+#else  // On iOS predictions are propagated with nullptr driver.
+  manager()->ProcessAutofillPredictions(nullptr, {&form_structure});
+#endif
 
   EXPECT_CALL(*store_, GetLogins(_, _))
       .WillRepeatedly(WithArg<1>(InvokeConsumer(form)));
   EXPECT_CALL(driver_, FillPasswordForm(_));
 
+  // Simulate that the form is incorrectly marked as sign-up, which means it can
+  // not be filled without server predictions.
+  form.form_data.fields[1].autocomplete_attribute = "new-password";
+
   manager()->OnPasswordFormsParsed(&driver_, {form.form_data});
-  task_runner_->FastForwardUntilNoTasksRemain();
+}
+
+// Check that when autofill predictions are received before a form is found then
+// server predictions are not ignored and used for filling in case there are
+// multiple forms on a page, including forms that have UsernameFirstFlow votes.
+TEST_F(PasswordManagerTest, AutofillPredictionBeforeMultipleFormsParsed) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(features::kUsernameFirstFlow);
+  PasswordFormManager::set_wait_for_server_predictions_for_filling(true);
+  EXPECT_CALL(client_, IsSavingAndFillingEnabled(_))
+      .WillRepeatedly(Return(true));
+
+  PasswordForm form1(MakeSimpleFormWithOnlyUsernameField());
+  PasswordForm form2(MakeSimpleForm());
+
+  EXPECT_CALL(*store_, GetLogins)
+      .WillRepeatedly(WithArg<1>(InvokeConsumer(form2)));
+
+  FormStructure form_structure1(form1.form_data);
+  form_structure1.field(0)->set_server_type(autofill::SINGLE_USERNAME);
+  // Server predictions says that this is a sign-in form. Since they have higher
+  // priority than autocomplete attributes then the form should be filled.
+  FormStructure form_structure2(form2.form_data);
+  form_structure2.field(1)->set_server_type(autofill::PASSWORD);
+
+#if !defined(OS_IOS)
+  manager()->ProcessAutofillPredictions(&driver_,
+                                        {&form_structure1, &form_structure2});
+  // Both forms should be filled.
+  EXPECT_CALL(driver_, FillPasswordForm(_)).Times(2);
+#else  // On iOS predictions are propagated with nullptr driver.
+  manager()->ProcessAutofillPredictions(nullptr,
+                                        {&form_structure1, &form_structure2});
+  // Only one form should be filled, as username first flow is not supported
+  // yet on iOS.
+  EXPECT_CALL(driver_, FillPasswordForm(_));
+#endif
+
+  // Simulate that the form is incorrectly marked as sign-up, which means it can
+  // not be filled without server predictions.
+  form2.form_data.fields[1].autocomplete_attribute = "new-password";
+  manager()->OnPasswordFormsParsed(&driver_,
+                                   {form1.form_data, form2.form_data});
 }
 
 // Checks the following scenario:
diff --git a/components/password_manager/core/browser/sync/password_sync_bridge.cc b/components/password_manager/core/browser/sync/password_sync_bridge.cc
index 673b323..1a921cf9 100644
--- a/components/password_manager/core/browser/sync/password_sync_bridge.cc
+++ b/components/password_manager/core/browser/sync/password_sync_bridge.cc
@@ -846,7 +846,9 @@
   std::unique_ptr<syncer::MetadataBatch> batch =
       metadata_store->GetAllSyncMetadata();
   for (const auto& metadata_entry : batch->GetAllMetadata()) {
-    if (change_processor()->IsEntityUnsynced(metadata_entry.first)) {
+    // Ignore unsynced deletions.
+    if (!metadata_entry.second->is_deleted() &&
+        change_processor()->IsEntityUnsynced(metadata_entry.first)) {
       storage_keys.insert(ParsePrimaryKey(metadata_entry.first));
     }
   }
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 266c59e..565bbb77 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
@@ -902,32 +902,53 @@
   ON_CALL(*mock_password_store_sync(), IsAccountStore())
       .WillByDefault(Return(true));
 
-  const int kPrimaryKeyUnsyncedEntry = 1000;
-  const int kPrimaryKeySyncedEntry = 1001;
-  const std::string kPrimaryKeyUnsyncedEntryStr = "1000";
-  const std::string kPrimaryKeySyncedEntryStr = "1001";
-  ON_CALL(mock_processor(), IsEntityUnsynced(kPrimaryKeyUnsyncedEntryStr))
+  const int kPrimaryKeyUnsyncedCredential = 1000;
+  const int kPrimaryKeySyncedCredential = 1001;
+  const int kPrimaryKeyUnsyncedDeletion = 1002;
+  const std::string kPrimaryKeyUnsyncedCredentialStr = "1000";
+  const std::string kPrimaryKeySyncedCredentialStr = "1001";
+  const std::string kPrimaryKeyUnsyncedDeletionStr = "1002";
+  ON_CALL(mock_processor(), IsEntityUnsynced(kPrimaryKeyUnsyncedCredentialStr))
       .WillByDefault(Return(true));
-  ON_CALL(mock_processor(), IsEntityUnsynced(kPrimaryKeySyncedEntryStr))
+  ON_CALL(mock_processor(), IsEntityUnsynced(kPrimaryKeySyncedCredentialStr))
       .WillByDefault(Return(false));
+  ON_CALL(mock_processor(), IsEntityUnsynced(kPrimaryKeyUnsyncedDeletionStr))
+      .WillByDefault(Return(true));
+
+  sync_pb::EntityMetadata is_deletion_metadata;
+  is_deletion_metadata.set_is_deleted(true);
+  sync_pb::EntityMetadata is_not_deletion_metadata;
+  is_not_deletion_metadata.set_is_deleted(false);
   ON_CALL(*mock_sync_metadata_store_sync(), GetAllSyncMetadata())
       .WillByDefault([&]() {
         auto batch = std::make_unique<syncer::MetadataBatch>();
-        batch->AddMetadata(kPrimaryKeyUnsyncedEntryStr,
-                           std::make_unique<sync_pb::EntityMetadata>());
-        batch->AddMetadata(kPrimaryKeySyncedEntryStr,
-                           std::make_unique<sync_pb::EntityMetadata>());
+        batch->AddMetadata(kPrimaryKeyUnsyncedCredentialStr,
+                           std::make_unique<sync_pb::EntityMetadata>(
+                               is_not_deletion_metadata));
+        batch->AddMetadata(kPrimaryKeySyncedCredentialStr,
+                           std::make_unique<sync_pb::EntityMetadata>(
+                               is_not_deletion_metadata));
+        batch->AddMetadata(
+            kPrimaryKeyUnsyncedDeletionStr,
+            std::make_unique<sync_pb::EntityMetadata>(is_deletion_metadata));
         return batch;
       });
 
-  autofill::PasswordForm unsynced_entry = MakePasswordForm(kSignonRealm1);
-  autofill::PasswordForm synced_entry = MakePasswordForm(kSignonRealm2);
-  fake_db()->AddLoginForPrimaryKey(kPrimaryKeyUnsyncedEntry, unsynced_entry);
-  fake_db()->AddLoginForPrimaryKey(kPrimaryKeySyncedEntry, synced_entry);
+  autofill::PasswordForm unsynced_credential = MakePasswordForm(kSignonRealm1);
+  autofill::PasswordForm synced_credential = MakePasswordForm(kSignonRealm2);
+  autofill::PasswordForm unsynced_deletion = MakePasswordForm(kSignonRealm3);
+  fake_db()->AddLoginForPrimaryKey(kPrimaryKeyUnsyncedCredential,
+                                   unsynced_credential);
+  fake_db()->AddLoginForPrimaryKey(kPrimaryKeySyncedCredential,
+                                   synced_credential);
+  fake_db()->AddLoginForPrimaryKey(kPrimaryKeyUnsyncedDeletion,
+                                   unsynced_deletion);
 
+  // The notification should only contain new credentials that are unsynced,
+  // ignoring both synced ones and deletion entries.
   EXPECT_CALL(*mock_password_store_sync(),
               NotifyUnsyncedCredentialsWillBeDeleted(
-                  UnorderedElementsAre(unsynced_entry)));
+                  UnorderedElementsAre(unsynced_credential)));
 
   // The content of the metadata change list does not matter in this case.
   bridge()->ApplyStopSyncChanges(bridge()->CreateMetadataChangeList());
@@ -938,28 +959,25 @@
   ON_CALL(*mock_password_store_sync(), IsAccountStore())
       .WillByDefault(Return(false));
 
-  const int kPrimaryKeyUnsyncedEntry = 1000;
-  const int kPrimaryKeySyncedEntry = 1001;
-  const std::string kPrimaryKeyUnsyncedEntryStr = "1000";
-  const std::string kPrimaryKeySyncedEntryStr = "1001";
-  ON_CALL(mock_processor(), IsEntityUnsynced(kPrimaryKeyUnsyncedEntryStr))
+  const int kPrimaryKeyUnsyncedCredential = 1000;
+  const std::string kPrimaryKeyUnsyncedCredentialStr = "1000";
+  ON_CALL(mock_processor(), IsEntityUnsynced(kPrimaryKeyUnsyncedCredentialStr))
       .WillByDefault(Return(true));
-  ON_CALL(mock_processor(), IsEntityUnsynced(kPrimaryKeySyncedEntryStr))
-      .WillByDefault(Return(false));
+
+  sync_pb::EntityMetadata is_not_deletion_metadata;
+  is_not_deletion_metadata.set_is_deleted(false);
   ON_CALL(*mock_sync_metadata_store_sync(), GetAllSyncMetadata())
       .WillByDefault([&]() {
         auto batch = std::make_unique<syncer::MetadataBatch>();
-        batch->AddMetadata(kPrimaryKeyUnsyncedEntryStr,
-                           std::make_unique<sync_pb::EntityMetadata>());
-        batch->AddMetadata(kPrimaryKeySyncedEntryStr,
-                           std::make_unique<sync_pb::EntityMetadata>());
+        batch->AddMetadata(kPrimaryKeyUnsyncedCredentialStr,
+                           std::make_unique<sync_pb::EntityMetadata>(
+                               is_not_deletion_metadata));
         return batch;
       });
 
-  fake_db()->AddLoginForPrimaryKey(kPrimaryKeyUnsyncedEntry,
+  autofill::PasswordForm unsynced_deletion = MakePasswordForm(kSignonRealm3);
+  fake_db()->AddLoginForPrimaryKey(kPrimaryKeyUnsyncedCredential,
                                    MakePasswordForm(kSignonRealm1));
-  fake_db()->AddLoginForPrimaryKey(kPrimaryKeySyncedEntry,
-                                   MakePasswordForm(kSignonRealm2));
 
   EXPECT_CALL(*mock_password_store_sync(),
               NotifyUnsyncedCredentialsWillBeDeleted)
diff --git a/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacade.java b/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacade.java
index 2d8b9e0e..095d9da 100644
--- a/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacade.java
+++ b/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacade.java
@@ -84,7 +84,6 @@
     /**
      * @param delegate the AccountManagerDelegate to use as a backend
      */
-    @VisibleForTesting
     public AccountManagerFacade(AccountManagerDelegate delegate) {
         ThreadUtils.assertOnUiThread();
         mDelegate = delegate;
diff --git a/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacadeProvider.java b/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacadeProvider.java
index 3bdf9c0..75250faf 100644
--- a/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacadeProvider.java
+++ b/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacadeProvider.java
@@ -25,18 +25,17 @@
     private AccountManagerFacadeProvider() {}
 
     /**
-     * Initializes AccountManagerFacade singleton instance. Can only be called once.
+     * Sets AccountManagerFacade singleton instance. Can only be called once.
      * Tests can override the instance with {@link #setInstanceForTests}.
      *
-     * @param delegate the AccountManagerDelegate to use
      */
     @MainThread
-    public static void initializeAccountManagerFacade(AccountManagerDelegate delegate) {
+    public static void setInstance(AccountManagerFacade accountManagerFacade) {
         ThreadUtils.assertOnUiThread();
         if (sInstance != null) {
             throw new IllegalStateException("AccountManagerFacade is already initialized!");
         }
-        sInstance = new AccountManagerFacade(delegate);
+        sInstance = accountManagerFacade;
         if (sTestingInstance != null) return;
         sAtomicInstance.set(sInstance);
     }
@@ -67,7 +66,7 @@
 
     /**
      * Singleton instance getter. Singleton must be initialized before calling this by
-     * {@link #initializeAccountManagerFacade} or {@link #setInstanceForTests}.
+     * {@link #setInstance} or {@link #setInstanceForTests}.
      *
      * @return a singleton instance
      */
diff --git a/components/sync/driver/sync_driver_switches.cc b/components/sync/driver/sync_driver_switches.cc
index 08eed99..0d0ce801 100644
--- a/components/sync/driver/sync_driver_switches.cc
+++ b/components/sync/driver/sync_driver_switches.cc
@@ -51,7 +51,7 @@
 
 // If enabled, the sync engine will be shut down in the "paused" state.
 const base::Feature kStopSyncInPausedState{"StopSyncInPausedState",
-                                           base::FEATURE_ENABLED_BY_DEFAULT};
+                                           base::FEATURE_DISABLED_BY_DEFAULT};
 
 // Enable USS implementation of Nigori datatype.
 const base::Feature kSyncUSSNigori{"SyncUSSNigori",
diff --git a/components/translate/content/common/translate.mojom b/components/translate/content/common/translate.mojom
index 09f0282..aaf8fa4e 100644
--- a/components/translate/content/common/translate.mojom
+++ b/components/translate/content/common/translate.mojom
@@ -36,9 +36,17 @@
 };
 
 // Handles language translation. This is used by the browser process to
-// direct a renderer to translate the language of a frame (or revert a
-// previous translation of the contents of a frame).
+// direct a renderer to detect the language details of a frame and translate
+// the language of a frame (or revert a previous translation of the contents
+// of a frame.
 interface TranslateAgent {
+  // Requests that the frame's language details be detected and returned to
+  // the browser process. This includes the html root language, the content
+  // language metadata, and whether the notranslate metadata is present.
+  GetWebLanguageDetectionDetails()
+        => (string content_meta_language, string html_root_lang,
+          url.mojom.Url url, bool has_notranslate_meta);
+
   // Requests that the frame be translated from |source_lang| to
   // |target_lang|.
   //
diff --git a/components/translate/content/renderer/BUILD.gn b/components/translate/content/renderer/BUILD.gn
index 1d903e0..bae4efd 100644
--- a/components/translate/content/renderer/BUILD.gn
+++ b/components/translate/content/renderer/BUILD.gn
@@ -6,6 +6,8 @@
 
 static_library("renderer") {
   sources = [
+    "per_frame_translate_agent.cc",
+    "per_frame_translate_agent.h",
     "translate_agent.cc",
     "translate_agent.h",
   ]
diff --git a/components/translate/content/renderer/DEPS b/components/translate/content/renderer/DEPS
index 617796b..6c8903ef 100644
--- a/components/translate/content/renderer/DEPS
+++ b/components/translate/content/renderer/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   "+content/public/renderer",
   "+services/service_manager/public",
+  "+third_party/blink/public/common",
   "+third_party/blink/public/platform",
   "+third_party/blink/public/common/browser_interface_broker_proxy.h",
   "+third_party/blink/public/web",
diff --git a/components/translate/content/renderer/per_frame_translate_agent.cc b/components/translate/content/renderer/per_frame_translate_agent.cc
new file mode 100644
index 0000000..d6ac5c2a
--- /dev/null
+++ b/components/translate/content/renderer/per_frame_translate_agent.cc
@@ -0,0 +1,417 @@
+// Copyright (c) 2020 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/translate/content/renderer/per_frame_translate_agent.h"
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/json/string_escape.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/translate/core/common/translate_constants.h"
+#include "components/translate/core/common/translate_metrics.h"
+#include "components/translate/core/common/translate_util.h"
+#include "components/translate/core/language_detection/language_detection_util.h"
+#include "content/public/common/content_constants.h"
+#include "content/public/common/url_constants.h"
+#include "content/public/renderer/render_frame.h"
+#include "content/public/renderer/v8_value_converter.h"
+#include "services/service_manager/public/cpp/interface_provider.h"
+#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
+#include "third_party/blink/public/platform/web_isolated_world_info.h"
+#include "third_party/blink/public/web/web_document.h"
+#include "third_party/blink/public/web/web_language_detection_details.h"
+#include "third_party/blink/public/web/web_local_frame.h"
+#include "third_party/blink/public/web/web_script_source.h"
+#include "url/gurl.h"
+#include "v8/include/v8.h"
+
+using blink::WebDocument;
+using blink::WebLanguageDetectionDetails;
+using blink::WebLocalFrame;
+using blink::WebScriptSource;
+using blink::WebSecurityOrigin;
+using blink::WebString;
+using blink::WebVector;
+
+namespace {
+
+// The delay in milliseconds that we'll wait before checking to see if the
+// translate library injected in the page is ready.
+// TODO(crbug.com/1064974): switch from int time values to base::TimeDelta.
+const int kTranslateInitCheckDelayMs = 150;
+
+// The maximum number of times we'll check to see if the translate library
+// injected in the page is ready.
+const int kMaxTranslateInitCheckAttempts = 5;
+
+// The delay we wait in milliseconds before checking whether the translation has
+// finished.
+const int kTranslateStatusCheckDelayMs = 400;
+
+// Language name passed to the Translate element for it to detect the language.
+const char kAutoDetectionLanguage[] = "auto";
+
+// Isolated world sets following content-security-policy.
+const char kContentSecurityPolicy[] = "script-src 'self' 'unsafe-eval'";
+
+}  // namespace
+
+namespace translate {
+
+////////////////////////////////////////////////////////////////////////////////
+// PerFrameTranslateAgent, public:
+PerFrameTranslateAgent::PerFrameTranslateAgent(
+    content::RenderFrame* render_frame,
+    int world_id,
+    blink::AssociatedInterfaceRegistry* registry)
+    : content::RenderFrameObserver(render_frame), world_id_(world_id) {
+  registry->AddInterface(base::BindRepeating(
+      &PerFrameTranslateAgent::BindReceiver, base::Unretained(this)));
+
+  // Set up v8 isolated world with proper content-security-policy and
+  // security-origin.
+  blink::WebIsolatedWorldInfo info;
+  info.security_origin =
+      WebSecurityOrigin::Create(GetTranslateSecurityOrigin());
+  info.content_security_policy = WebString::FromUTF8(kContentSecurityPolicy);
+  render_frame->GetWebFrame()->SetIsolatedWorldInfo(world_id_, info);
+}
+
+PerFrameTranslateAgent::~PerFrameTranslateAgent() = default;
+
+// mojom::TranslateAgent implementations.
+void PerFrameTranslateAgent::GetWebLanguageDetectionDetails(
+    GetWebLanguageDetectionDetailsCallback callback) {
+  // Get the document language as set by WebKit from the http-equiv
+  // meta tag for "content-language".  This may or may not also
+  // have a value derived from the actual Content-Language HTTP
+  // header.  The two actually have different meanings (despite the
+  // original intent of http-equiv to be an equivalent) with the former
+  // being the language of the document and the latter being the
+  // language of the intended audience (a distinction really only
+  // relevant for things like language textbooks).  This distinction
+  // shouldn't affect translation.
+  WebLocalFrame* local_frame = render_frame()->GetWebFrame();
+  WebDocument document = local_frame->GetDocument();
+  WebLanguageDetectionDetails web_detection_details =
+      WebLanguageDetectionDetails::CollectLanguageDetectionDetails(document);
+
+  std::move(callback).Run(web_detection_details.content_language.Utf8(),
+                          web_detection_details.html_language.Utf8(),
+                          web_detection_details.url,
+                          web_detection_details.has_no_translate_meta);
+}
+
+void PerFrameTranslateAgent::TranslateFrame(const std::string& translate_script,
+                                            const std::string& source_lang,
+                                            const std::string& target_lang,
+                                            TranslateFrameCallback callback) {
+  // A similar translation is already under way, nothing to do.
+  if (translate_callback_pending_ && target_lang_ == target_lang) {
+    // This request is ignored.
+    std::move(callback).Run(true /* cancelled */, source_lang, target_lang,
+                            TranslateErrors::NONE);
+    return;
+  }
+
+  // Any pending translation is now irrelevant.
+  CancelPendingTranslation();
+
+  // Set our states.
+  translate_callback_pending_ = std::move(callback);
+
+  // If the source language is undetermined, we'll let the translate element
+  // detect it.
+  source_lang_ = (source_lang != kUnknownLanguageCode) ? source_lang
+                                                       : kAutoDetectionLanguage;
+  target_lang_ = target_lang;
+
+  GURL url(render_frame()->GetWebFrame()->GetDocument().Url());
+  ReportPageScheme(url.scheme());
+
+  if (!IsTranslateLibAvailable()) {
+    // Evaluate the script to add the translation related method to the global
+    // context of the page.
+    ExecuteScript(translate_script);
+    DCHECK(IsTranslateLibAvailable());
+  }
+
+  TranslateFrameImpl(0 /* try_count */);
+}
+
+void PerFrameTranslateAgent::RevertTranslation() {
+  if (!IsTranslateLibAvailable()) {
+    NOTREACHED();
+    return;
+  }
+
+  CancelPendingTranslation();
+
+  ExecuteScript("cr.googleTranslate.revert()");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// PerFrameTranslateAgent, protected:
+bool PerFrameTranslateAgent::IsTranslateLibAvailable() {
+  return ExecuteScriptAndGetBoolResult(
+      "typeof cr != 'undefined' && typeof cr.googleTranslate != 'undefined' && "
+      "typeof cr.googleTranslate.translate == 'function'",
+      false);
+}
+
+bool PerFrameTranslateAgent::IsTranslateLibReady() {
+  return ExecuteScriptAndGetBoolResult("cr.googleTranslate.libReady", false);
+}
+
+bool PerFrameTranslateAgent::HasTranslationFinished() {
+  return ExecuteScriptAndGetBoolResult("cr.googleTranslate.finished", true);
+}
+
+bool PerFrameTranslateAgent::HasTranslationFailed() {
+  return ExecuteScriptAndGetBoolResult("cr.googleTranslate.error", true);
+}
+
+int64_t PerFrameTranslateAgent::GetErrorCode() {
+  int64_t error_code =
+      ExecuteScriptAndGetIntegerResult("cr.googleTranslate.errorCode");
+  DCHECK_LT(error_code, static_cast<int>(TranslateErrors::TRANSLATE_ERROR_MAX));
+  return error_code;
+}
+
+bool PerFrameTranslateAgent::StartTranslation() {
+  return ExecuteScriptAndGetBoolResult(
+      BuildTranslationScript(source_lang_, target_lang_), false);
+}
+
+std::string PerFrameTranslateAgent::GetOriginalPageLanguage() {
+  return ExecuteScriptAndGetStringResult("cr.googleTranslate.sourceLang");
+}
+
+base::TimeDelta PerFrameTranslateAgent::AdjustDelay(int delay_in_milliseconds) {
+  // Just converts |delay_in_milliseconds| without any modification in practical
+  // cases. Tests will override this function to return modified value.
+  return base::TimeDelta::FromMilliseconds(delay_in_milliseconds);
+}
+
+void PerFrameTranslateAgent::ExecuteScript(const std::string& script) {
+  WebLocalFrame* local_frame = render_frame()->GetWebFrame();
+  if (!local_frame)
+    return;
+
+  WebScriptSource source = WebScriptSource(WebString::FromASCII(script));
+  local_frame->ExecuteScriptInIsolatedWorld(world_id_, source);
+}
+
+bool PerFrameTranslateAgent::ExecuteScriptAndGetBoolResult(
+    const std::string& script,
+    bool fallback) {
+  WebLocalFrame* local_frame = render_frame()->GetWebFrame();
+  if (!local_frame)
+    return fallback;
+
+  v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
+  WebScriptSource source = WebScriptSource(WebString::FromASCII(script));
+  v8::Local<v8::Value> result =
+      local_frame->ExecuteScriptInIsolatedWorldAndReturnValue(world_id_,
+                                                              source);
+  DCHECK(result->IsBoolean());
+
+  return result.As<v8::Boolean>()->Value();
+}
+
+std::string PerFrameTranslateAgent::ExecuteScriptAndGetStringResult(
+    const std::string& script) {
+  WebLocalFrame* local_frame = render_frame()->GetWebFrame();
+  if (!local_frame)
+    return std::string();
+
+  v8::Isolate* isolate = v8::Isolate::GetCurrent();
+  v8::HandleScope handle_scope(isolate);
+  WebScriptSource source = WebScriptSource(WebString::FromASCII(script));
+  v8::Local<v8::Value> result =
+      local_frame->ExecuteScriptInIsolatedWorldAndReturnValue(world_id_,
+                                                              source);
+  DCHECK(result->IsString());
+
+  std::unique_ptr<base::Value> string_result =
+      content::V8ValueConverter::Create()->FromV8Value(
+          result, isolate->GetCurrentContext());
+  return string_result->GetString();
+}
+
+double PerFrameTranslateAgent::ExecuteScriptAndGetDoubleResult(
+    const std::string& script) {
+  WebLocalFrame* local_frame = render_frame()->GetWebFrame();
+  if (!local_frame)
+    return 0.0;
+
+  v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
+  WebScriptSource source = WebScriptSource(WebString::FromASCII(script));
+  v8::Local<v8::Value> result =
+      local_frame->ExecuteScriptInIsolatedWorldAndReturnValue(world_id_,
+                                                              source);
+  DCHECK(result->IsNumber());
+
+  return result.As<v8::Number>()->Value();
+}
+
+int64_t PerFrameTranslateAgent::ExecuteScriptAndGetIntegerResult(
+    const std::string& script) {
+  WebLocalFrame* local_frame = render_frame()->GetWebFrame();
+  if (!local_frame)
+    return 0;
+
+  v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
+  WebScriptSource source = WebScriptSource(WebString::FromASCII(script));
+  v8::Local<v8::Value> result =
+      local_frame->ExecuteScriptInIsolatedWorldAndReturnValue(world_id_,
+                                                              source);
+  DCHECK(result->IsNumber());
+
+  return result.As<v8::Integer>()->Value();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// PerFrameTranslateAgent, private:
+void PerFrameTranslateAgent::CheckTranslateStatus() {
+  // First check if there was an error.
+  if (HasTranslationFailed()) {
+    NotifyBrowserTranslationFailed(
+        static_cast<translate::TranslateErrors::Type>(GetErrorCode()));
+    return;  // There was an error.
+  }
+
+  if (HasTranslationFinished()) {
+    std::string actual_source_lang;
+    // Translation was successful, if it was auto, retrieve the source
+    // language the Translate Element detected.
+    if (source_lang_ == kAutoDetectionLanguage) {
+      actual_source_lang = GetOriginalPageLanguage();
+      if (actual_source_lang.empty()) {
+        NotifyBrowserTranslationFailed(TranslateErrors::UNKNOWN_LANGUAGE);
+        return;
+      } else if (actual_source_lang == target_lang_) {
+        NotifyBrowserTranslationFailed(TranslateErrors::IDENTICAL_LANGUAGES);
+        return;
+      }
+    } else {
+      actual_source_lang = source_lang_;
+    }
+
+    if (!translate_callback_pending_) {
+      NOTREACHED();
+      return;
+    }
+
+    // Check JavaScript performance counters for UMA reports.
+    ReportTimeToTranslate(
+        ExecuteScriptAndGetDoubleResult("cr.googleTranslate.translationTime"));
+
+    // Notify the browser we are done.
+    std::move(translate_callback_pending_)
+        .Run(false /* cancelled */, actual_source_lang, target_lang_,
+             TranslateErrors::NONE);
+    return;
+  }
+
+  // The translation is still pending, check again later.
+  render_frame()
+      ->GetTaskRunner(blink::TaskType::kInternalTranslation)
+      ->PostDelayedTask(
+          FROM_HERE,
+          base::BindOnce(&PerFrameTranslateAgent::CheckTranslateStatus,
+                         weak_method_factory_.GetWeakPtr()),
+          AdjustDelay(kTranslateStatusCheckDelayMs));
+}
+
+void PerFrameTranslateAgent::TranslateFrameImpl(int try_count) {
+  DCHECK_LT(try_count, kMaxTranslateInitCheckAttempts);
+  if (!IsTranslateLibReady()) {
+    // There was an error during initialization of library.
+    TranslateErrors::Type error =
+        static_cast<translate::TranslateErrors::Type>(GetErrorCode());
+    if (error != TranslateErrors::NONE) {
+      NotifyBrowserTranslationFailed(error);
+      return;
+    }
+
+    // The library is not ready, try again later, unless we have tried several
+    // times unsuccessfully already.
+    if (++try_count >= kMaxTranslateInitCheckAttempts) {
+      NotifyBrowserTranslationFailed(TranslateErrors::TRANSLATION_TIMEOUT);
+      return;
+    }
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE,
+        base::BindOnce(&PerFrameTranslateAgent::TranslateFrameImpl,
+                       weak_method_factory_.GetWeakPtr(), try_count),
+        AdjustDelay(try_count * kTranslateInitCheckDelayMs));
+    return;
+  }
+
+  // The library is loaded, and ready for translation now.
+  // Check JavaScript performance counters for UMA reports.
+  ReportTimeToBeReady(
+      ExecuteScriptAndGetDoubleResult("cr.googleTranslate.readyTime"));
+  ReportTimeToLoad(
+      ExecuteScriptAndGetDoubleResult("cr.googleTranslate.loadTime"));
+
+  if (!StartTranslation()) {
+    CheckTranslateStatus();
+    return;
+  }
+  // Check the status of the translation.
+  render_frame()
+      ->GetTaskRunner(blink::TaskType::kInternalTranslation)
+      ->PostDelayedTask(
+          FROM_HERE,
+          base::BindOnce(&PerFrameTranslateAgent::CheckTranslateStatus,
+                         weak_method_factory_.GetWeakPtr()),
+          AdjustDelay(kTranslateStatusCheckDelayMs));
+}
+
+void PerFrameTranslateAgent::NotifyBrowserTranslationFailed(
+    TranslateErrors::Type error) {
+  DCHECK(translate_callback_pending_);
+  // Notify the browser there was an error.
+  std::move(translate_callback_pending_)
+      .Run(false /* cancelled */, source_lang_, target_lang_, error);
+}
+
+void PerFrameTranslateAgent::OnDestruct() {
+  delete this;
+}
+
+void PerFrameTranslateAgent::CancelPendingTranslation() {
+  weak_method_factory_.InvalidateWeakPtrs();
+  // Make sure to send the cancelled response back.
+  if (translate_callback_pending_) {
+    std::move(translate_callback_pending_)
+        .Run(true /* cancelled */, source_lang_, target_lang_,
+             TranslateErrors::NONE);
+  }
+  source_lang_.clear();
+  target_lang_.clear();
+}
+
+void PerFrameTranslateAgent::BindReceiver(
+    mojo::PendingAssociatedReceiver<mojom::TranslateAgent> receiver) {
+  receiver_.Bind(std::move(receiver));
+}
+
+/* static */
+std::string PerFrameTranslateAgent::BuildTranslationScript(
+    const std::string& source_lang,
+    const std::string& target_lang) {
+  return "cr.googleTranslate.translate(" +
+         base::GetQuotedJSONString(source_lang) + "," +
+         base::GetQuotedJSONString(target_lang) + ")";
+}
+
+}  // namespace translate
diff --git a/components/translate/content/renderer/per_frame_translate_agent.h b/components/translate/content/renderer/per_frame_translate_agent.h
new file mode 100644
index 0000000..1e5edd93c
--- /dev/null
+++ b/components/translate/content/renderer/per_frame_translate_agent.h
@@ -0,0 +1,157 @@
+// Copyright (c) 2020 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_TRANSLATE_CONTENT_RENDERER_PER_FRAME_TRANSLATE_AGENT_H_
+#define COMPONENTS_TRANSLATE_CONTENT_RENDERER_PER_FRAME_TRANSLATE_AGENT_H_
+
+#include "components/translate/content/common/translate.mojom.h"
+#include "content/public/renderer/render_frame.h"
+#include "content/public/renderer/render_frame_observer.h"
+#include "mojo/public/cpp/bindings/associated_receiver.h"
+#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
+#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
+
+namespace translate {
+
+// This class deals with page translation. It is a RenderFrame's
+// IPC client for translation requests from the browser process.
+//
+// This class supports translating sub frames as well as the main
+// frame. It is intended to replace TranslateAgent (which only
+// translates the main frame. Both classes will exist for a transition
+// period in order to control an experiment for proving out sub frame
+// translation.
+class PerFrameTranslateAgent : public content::RenderFrameObserver,
+                               public mojom::TranslateAgent {
+ public:
+  PerFrameTranslateAgent(content::RenderFrame* render_frame,
+                         int world_id,
+                         blink::AssociatedInterfaceRegistry* registry);
+  ~PerFrameTranslateAgent() override;
+
+  // mojom::TranslateAgent implementation.
+  void GetWebLanguageDetectionDetails(
+      GetWebLanguageDetectionDetailsCallback callback) override;
+  void TranslateFrame(const std::string& translate_script,
+                      const std::string& source_lang,
+                      const std::string& target_lang,
+                      TranslateFrameCallback callback) override;
+  void RevertTranslation() override;
+
+ protected:
+  // Returns true if the translate library is available, meaning the JavaScript
+  // has already been injected in that page.
+  virtual bool IsTranslateLibAvailable();
+
+  // Returns true if the translate library has been initialized successfully.
+  virtual bool IsTranslateLibReady();
+
+  // Returns true if the translation script has finished translating the page.
+  virtual bool HasTranslationFinished();
+
+  // Returns true if the translation script has reported an error performing the
+  // translation.
+  virtual bool HasTranslationFailed();
+
+  // Returns the error code generated in translate library.
+  virtual int64_t GetErrorCode();
+
+  // Starts the translation by calling the translate library.  This method
+  // should only be called when the translate script has been injected in the
+  // page.  Returns false if the call failed immediately.
+  virtual bool StartTranslation();
+
+  // Asks the Translate element in the page what the language of the page is.
+  // Can only be called if a translation has happened and was successful.
+  // Returns the language code on success, an empty string on failure.
+  virtual std::string GetOriginalPageLanguage();
+
+  // Adjusts a delay time for a posted task. This is overridden in tests to do
+  // tasks immediately by returning 0.
+  virtual base::TimeDelta AdjustDelay(int delay_in_milliseconds);
+
+  // Executes the JavaScript code in |script| in the main frame of RenderView.
+  virtual void ExecuteScript(const std::string& script);
+
+  // Executes the JavaScript code in |script| in the main frame of RenderView,
+  // and returns the boolean returned by the script evaluation if the script was
+  // run successfully. Otherwise, returns |fallback| value.
+  virtual bool ExecuteScriptAndGetBoolResult(const std::string& script,
+                                             bool fallback);
+
+  // Executes the JavaScript code in |script| in the main frame of RenderView,
+  // and returns the string returned by the script evaluation if the script was
+  // run successfully. Otherwise, returns empty string.
+  virtual std::string ExecuteScriptAndGetStringResult(
+      const std::string& script);
+
+  // Executes the JavaScript code in |script| in the main frame of RenderView.
+  // and returns the number returned by the script evaluation if the script was
+  // run successfully. Otherwise, returns 0.0.
+  virtual double ExecuteScriptAndGetDoubleResult(const std::string& script);
+
+  // Executes the JavaScript code in |script| in the main frame of RenderView.
+  // and returns the integer value returned by the script evaluation if the
+  // script was run successfully. Otherwise, returns 0.
+  virtual int64_t ExecuteScriptAndGetIntegerResult(const std::string& script);
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(PerFrameTranslateAgentTest,
+                           TestBuildTranslationScript);
+
+  // Converts language code to the one used in server supporting list.
+  static void ConvertLanguageCodeSynonym(std::string* code);
+
+  // Sets receiver for translate messages from browser process.
+  void BindReceiver(
+      mojo::PendingAssociatedReceiver<mojom::TranslateAgent> receiver);
+
+  // Builds the translation JS used to translate from source_lang to
+  // target_lang.
+  static std::string BuildTranslationScript(const std::string& source_lang,
+                                            const std::string& target_lang);
+
+  // RenderFrameObserver implementation.
+  void OnDestruct() override;
+
+  // Cancels any translation that is currently being performed.  This does not
+  // revert existing translations.
+  void CancelPendingTranslation();
+
+  // Checks if the current running page translation is finished or errored and
+  // notifies the browser accordingly.  If the translation has not terminated,
+  // posts a task to check again later.
+  void CheckTranslateStatus();
+
+  // Called by TranslateFrame to do the actual translation.  |count| is used to
+  // limit the number of retries.
+  void TranslateFrameImpl(int count);
+
+  // Sends a message to the browser to notify it that the translation failed
+  // with |error|.
+  void NotifyBrowserTranslationFailed(TranslateErrors::Type error);
+
+  // Convenience method to access the main frame.  Can return nullptr, typically
+  // if the page is being closed.
+  blink::WebLocalFrame* GetMainFrame();
+
+  // The states associated with the current translation.
+  TranslateFrameCallback translate_callback_pending_;
+  std::string source_lang_;
+  std::string target_lang_;
+
+  // The world ID to use for script execution.
+  int world_id_;
+
+  mojo::AssociatedReceiver<mojom::TranslateAgent> receiver_{this};
+
+  // Method factory used to make calls to TranslateFrameImpl.
+  base::WeakPtrFactory<PerFrameTranslateAgent> weak_method_factory_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(PerFrameTranslateAgent);
+};
+
+}  // namespace translate
+
+#endif  // COMPONENTS_TRANSLATE_CONTENT_RENDERER_PER_FRAME_TRANSLATE_AGENT_H_
diff --git a/components/translate/content/renderer/translate_agent.cc b/components/translate/content/renderer/translate_agent.cc
index bab6f8ea..174f68a 100644
--- a/components/translate/content/renderer/translate_agent.cc
+++ b/components/translate/content/renderer/translate_agent.cc
@@ -184,10 +184,10 @@
   return ExecuteScriptAndGetStringResult("cr.googleTranslate.sourceLang");
 }
 
-base::TimeDelta TranslateAgent::AdjustDelay(int delayInMs) {
-  // Just converts |delayInMs| without any modification in practical cases.
-  // Tests will override this function to return modified value.
-  return base::TimeDelta::FromMilliseconds(delayInMs);
+base::TimeDelta TranslateAgent::AdjustDelay(int delay_in_milliseconds) {
+  // Just converts |delay_in_milliseconds| without any modification in practical
+  // cases. Tests will override this function to return modified value.
+  return base::TimeDelta::FromMilliseconds(delay_in_milliseconds);
 }
 
 void TranslateAgent::ExecuteScript(const std::string& script) {
@@ -277,6 +277,11 @@
 }
 
 // mojom::TranslateAgent implementations.
+void TranslateAgent::GetWebLanguageDetectionDetails(
+    GetWebLanguageDetectionDetailsCallback callback) {
+  NOTREACHED() << "This interface supported by PerFrameTranslateAgent";
+}
+
 void TranslateAgent::TranslateFrame(const std::string& translate_script,
                                     const std::string& source_lang,
                                     const std::string& target_lang,
diff --git a/components/translate/content/renderer/translate_agent.h b/components/translate/content/renderer/translate_agent.h
index f60be1b..162684e 100644
--- a/components/translate/content/renderer/translate_agent.h
+++ b/components/translate/content/renderer/translate_agent.h
@@ -28,6 +28,9 @@
 
 // This class deals with page translation.
 // There is one TranslateAgent per RenderView.
+//
+// Note: this class only supports translation of the main frame. See
+// PerFrameTranslateAgent for sub frame translation support.
 class TranslateAgent : public content::RenderFrameObserver,
                        public mojom::TranslateAgent {
  public:
@@ -45,6 +48,8 @@
   void PrepareForUrl(const GURL& url);
 
   // mojom::TranslateAgent implementation.
+  void GetWebLanguageDetectionDetails(
+      GetWebLanguageDetectionDetailsCallback callback) override;
   void TranslateFrame(const std::string& translate_script,
                       const std::string& source_lang,
                       const std::string& target_lang,
@@ -79,9 +84,9 @@
   // Returns the language code on success, an empty string on failure.
   virtual std::string GetOriginalPageLanguage();
 
-  // Adjusts a delay time for a posted task. This is used in tests to do tasks
-  // immediately by returning 0.
-  virtual base::TimeDelta AdjustDelay(int delayInMs);
+  // Adjusts a delay time for a posted task. This is overridden in tests to do
+  // tasks immediately by returning 0.
+  virtual base::TimeDelta AdjustDelay(int delay_in_milliseconds);
 
   // Executes the JavaScript code in |script| in the main frame of RenderView.
   virtual void ExecuteScript(const std::string& script);
diff --git a/components/translate/core/common/translate_util.cc b/components/translate/core/common/translate_util.cc
index e2c4a61..7bb1abbb 100644
--- a/components/translate/core/common/translate_util.cc
+++ b/components/translate/core/common/translate_util.cc
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "base/command_line.h"
+#include "base/feature_list.h"
 #include "base/logging.h"
 #include "base/stl_util.h"
 #include "components/language/core/common/locale_util.h"
@@ -20,6 +21,9 @@
 
 const char kSecurityOrigin[] = "https://translate.googleapis.com/";
 
+const base::Feature kTranslateSubFrames{"TranslateSubFrames",
+                                        base::FEATURE_DISABLED_BY_DEFAULT};
+
 GURL GetTranslateSecurityOrigin() {
   std::string security_origin(kSecurityOrigin);
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
@@ -30,4 +34,8 @@
   return GURL(security_origin);
 }
 
+bool IsSubFrameTranslationEnabled() {
+  return base::FeatureList::IsEnabled(kTranslateSubFrames);
+}
+
 }  // namespace translate
diff --git a/components/translate/core/common/translate_util.h b/components/translate/core/common/translate_util.h
index 7c4385ce..ed9d632 100644
--- a/components/translate/core/common/translate_util.h
+++ b/components/translate/core/common/translate_util.h
@@ -8,10 +8,16 @@
 #include <string>
 #include <vector>
 
+#include "base/feature_list.h"
+
 class GURL;
 
 namespace translate {
 
+// Controls whether translation applies to sub frames as well as the
+// main frame.
+extern const base::Feature kTranslateSubFrames;
+
 // Isolated world sets following security-origin by default.
 extern const char kSecurityOrigin[];
 
@@ -19,6 +25,9 @@
 // language checks and to obtain the list of available languages.
 GURL GetTranslateSecurityOrigin();
 
+// Return whether sub frame translation is enabled.
+bool IsSubFrameTranslationEnabled();
+
 }  // namespace translate
 
 #endif  // COMPONENTS_TRANSLATE_CORE_COMMON_TRANSLATE_UTIL_H_
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index f6a99add..457061c1 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -947,17 +947,6 @@
   return this;
 }
 
-void BrowserAccessibility::Destroy() {
-  node_ = nullptr;
-  manager_ = nullptr;
-
-  NativeReleaseReference();
-}
-
-void BrowserAccessibility::NativeReleaseReference() {
-  delete this;
-}
-
 bool BrowserAccessibility::HasBoolAttribute(
     ax::mojom::BoolAttribute attribute) const {
   return GetData().HasBoolAttribute(attribute);
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h
index 4de8492..cbddbe6 100644
--- a/content/browser/accessibility/browser_accessibility.h
+++ b/content/browser/accessibility/browser_accessibility.h
@@ -84,6 +84,7 @@
   static BrowserAccessibility* FromAXPlatformNodeDelegate(
       ui::AXPlatformNodeDelegate* delegate);
 
+  BrowserAccessibility();
   ~BrowserAccessibility() override;
 
   // Called only once, immediately after construction. The constructor doesn't
@@ -287,23 +288,6 @@
   BrowserAccessibility* ApproximateHitTest(
       const gfx::Point& blink_screen_point);
 
-  // Marks this object for deletion, releases our reference to it, and
-  // nulls out the pointer to the underlying AXNode.  May not delete
-  // the object immediately due to reference counting.
-  //
-  // Reference counting is used on some platforms because the
-  // operating system may hold onto a reference to a BrowserAccessibility
-  // object even after we're through with it. When a BrowserAccessibility
-  // has had Destroy() called but its reference count is not yet zero,
-  // instance_active() returns false and queries on this object return failure.
-  virtual void Destroy();
-
-  // Subclasses should override this to support platform reference counting.
-  virtual void NativeAddReference() {}
-
-  // Subclasses should override this to support platform reference counting.
-  virtual void NativeReleaseReference();
-
   //
   // Accessors
   //
@@ -616,8 +600,6 @@
 
   virtual ui::TextAttributeList ComputeTextAttributes() const;
 
-  BrowserAccessibility();
-
   // The manager of this tree of accessibility objects.
   BrowserAccessibilityManager* manager_ = nullptr;
 
diff --git a/content/browser/accessibility/browser_accessibility_auralinux_unittest.cc b/content/browser/accessibility/browser_accessibility_auralinux_unittest.cc
index 6ba656b..5e588ed 100644
--- a/content/browser/accessibility/browser_accessibility_auralinux_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_auralinux_unittest.cc
@@ -55,8 +55,7 @@
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root_data),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   ui::AXPlatformNodeAuraLinux* root_obj =
       ToBrowserAccessibilityAuraLinux(manager->GetRoot())->GetNode();
@@ -109,8 +108,7 @@
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, text1, text2),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   ui::AXPlatformNodeAuraLinux* root_obj =
       ToBrowserAccessibilityAuraLinux(manager->GetRoot())->GetNode();
@@ -213,8 +211,7 @@
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, text1, combo_box, text2, check_box,
                            radio_button, radio_button_text, link, link_text),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   ui::AXPlatformNodeAuraLinux* root_obj =
       ToBrowserAccessibilityAuraLinux(manager->GetRoot())->GetNode();
@@ -398,8 +395,7 @@
 
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
-          update, test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          update, test_browser_accessibility_delegate_.get()));
 
   ASSERT_NE(nullptr, manager->GetRoot());
   BrowserAccessibilityAuraLinux* ax_root =
@@ -586,8 +582,7 @@
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, container, combo_box, menu_list, menu_option_1,
                            menu_option_2),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   ui::AXPlatformNodeAuraLinux* combo_box_node =
       ToBrowserAccessibilityAuraLinux(manager->GetFromID(combo_box.id))
@@ -670,8 +665,7 @@
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, combo_box, combo_box_div, static_text1,
                            static_text2),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   ASSERT_NE(nullptr, manager->GetRoot());
   BrowserAccessibilityAuraLinux* ax_root =
@@ -756,8 +750,7 @@
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, div_editable, text),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   text.SetName("Text2");
   ui::AXTree* tree = const_cast<ui::AXTree*>(manager->ax_tree());
diff --git a/content/browser/accessibility/browser_accessibility_mac.h b/content/browser/accessibility/browser_accessibility_mac.h
index 53c3e87..9b14ad2b3 100644
--- a/content/browser/accessibility/browser_accessibility_mac.h
+++ b/content/browser/accessibility/browser_accessibility_mac.h
@@ -27,7 +27,7 @@
 class BrowserAccessibilityMac : public BrowserAccessibility {
  public:
   // BrowserAccessibility overrides.
-  void NativeReleaseReference() override;
+  ~BrowserAccessibilityMac() override;
   bool IsNative() const override;
   void OnDataChanged() override;
   uint32_t PlatformChildCount() const override;
diff --git a/content/browser/accessibility/browser_accessibility_mac.mm b/content/browser/accessibility/browser_accessibility_mac.mm
index 34964ec..92fafed8 100644
--- a/content/browser/accessibility/browser_accessibility_mac.mm
+++ b/content/browser/accessibility/browser_accessibility_mac.mm
@@ -21,19 +21,18 @@
 BrowserAccessibilityMac::BrowserAccessibilityMac()
     : browser_accessibility_cocoa_(NULL) {}
 
-bool BrowserAccessibilityMac::IsNative() const {
-  return true;
-}
-
-void BrowserAccessibilityMac::NativeReleaseReference() {
+BrowserAccessibilityMac::~BrowserAccessibilityMac() {
   // Detach this object from |browser_accessibility_cocoa_| so it
   // no longer has a pointer to this object.
   [browser_accessibility_cocoa_ detach];
+
   // Now, release it - but at this point, other processes may have a
   // reference to the cocoa object.
   [browser_accessibility_cocoa_ release];
-  // Finally, it's safe to delete this since we've detached.
-  delete this;
+}
+
+bool BrowserAccessibilityMac::IsNative() const {
+  return true;
 }
 
 void BrowserAccessibilityMac::OnDataChanged() {
diff --git a/content/browser/accessibility/browser_accessibility_manager.cc b/content/browser/accessibility/browser_accessibility_manager.cc
index f197636..5a7f44a 100644
--- a/content/browser/accessibility/browser_accessibility_manager.cc
+++ b/content/browser/accessibility/browser_accessibility_manager.cc
@@ -122,10 +122,6 @@
   return update;
 }
 
-BrowserAccessibility* BrowserAccessibilityFactory::Create() {
-  return BrowserAccessibility::Create();
-}
-
 BrowserAccessibilityFindInPageInfo::BrowserAccessibilityFindInPageInfo()
     : request_id(-1),
       match_index(-1),
@@ -139,9 +135,8 @@
 // static
 BrowserAccessibilityManager* BrowserAccessibilityManager::Create(
     const ui::AXTreeUpdate& initial_tree,
-    BrowserAccessibilityDelegate* delegate,
-    BrowserAccessibilityFactory* factory) {
-  return new BrowserAccessibilityManager(initial_tree, delegate, factory);
+    BrowserAccessibilityDelegate* delegate) {
+  return new BrowserAccessibilityManager(initial_tree, delegate);
 }
 #endif
 
@@ -153,12 +148,10 @@
 }
 
 BrowserAccessibilityManager::BrowserAccessibilityManager(
-    BrowserAccessibilityDelegate* delegate,
-    BrowserAccessibilityFactory* factory)
+    BrowserAccessibilityDelegate* delegate)
     : WebContentsObserver(delegate ? delegate->AccessibilityWebContents()
                                    : nullptr),
       delegate_(delegate),
-      factory_(factory),
       user_is_navigating_away_(false),
       connected_to_parent_tree_node_(false),
       ax_tree_id_(ui::AXTreeIDUnknown()),
@@ -171,12 +164,10 @@
 
 BrowserAccessibilityManager::BrowserAccessibilityManager(
     const ui::AXTreeUpdate& initial_tree,
-    BrowserAccessibilityDelegate* delegate,
-    BrowserAccessibilityFactory* factory)
+    BrowserAccessibilityDelegate* delegate)
     : WebContentsObserver(delegate ? delegate->AccessibilityWebContents()
                                    : nullptr),
       delegate_(delegate),
-      factory_(factory),
       user_is_navigating_away_(false),
       ax_tree_id_(ui::AXTreeIDUnknown()),
       device_scale_factor_(1.0f),
@@ -1272,7 +1263,7 @@
 void BrowserAccessibilityManager::OnNodeCreated(ui::AXTree* tree,
                                                 ui::AXNode* node) {
   DCHECK(node);
-  BrowserAccessibility* wrapper = factory_->Create();
+  BrowserAccessibility* wrapper = BrowserAccessibility::Create();
   id_wrapper_map_[node->id()] = wrapper;
   wrapper->Init(this, node);
 }
@@ -1282,7 +1273,7 @@
   DCHECK_NE(node_id, ui::AXNode::kInvalidAXID);
   if (BrowserAccessibility* wrapper = GetFromID(node_id)) {
     id_wrapper_map_.erase(node_id);
-    wrapper->Destroy();
+    delete wrapper;
   }
 }
 
@@ -1291,7 +1282,7 @@
   DCHECK(node);
   BrowserAccessibility* wrapper = GetFromAXNode(node);
   if (!wrapper) {
-    wrapper = factory_->Create();
+    wrapper = BrowserAccessibility::Create();
     id_wrapper_map_[node->id()] = wrapper;
   }
   wrapper->Init(this, node);
diff --git a/content/browser/accessibility/browser_accessibility_manager.h b/content/browser/accessibility/browser_accessibility_manager.h
index 49e4d198..0db55c3 100644
--- a/content/browser/accessibility/browser_accessibility_manager.h
+++ b/content/browser/accessibility/browser_accessibility_manager.h
@@ -102,15 +102,6 @@
   virtual bool AccessibilityIsMainFrame() const = 0;
 };
 
-class CONTENT_EXPORT BrowserAccessibilityFactory {
- public:
-  virtual ~BrowserAccessibilityFactory() {}
-
-  // Create an instance of BrowserAccessibility and return a new
-  // reference to it.
-  virtual BrowserAccessibility* Create();
-};
-
 // This is all of the information about the current find in page result,
 // so we can activate it if requested.
 struct BrowserAccessibilityFindInPageInfo {
@@ -146,8 +137,7 @@
   // with no parent window pointer. Only useful for unit tests.
   static BrowserAccessibilityManager* Create(
       const ui::AXTreeUpdate& initial_tree,
-      BrowserAccessibilityDelegate* delegate,
-      BrowserAccessibilityFactory* factory = new BrowserAccessibilityFactory());
+      BrowserAccessibilityDelegate* delegate);
 
   static BrowserAccessibilityManager* FromID(ui::AXTreeID ax_tree_id);
 
@@ -465,12 +455,10 @@
   void OnPortalActivated();
 
  protected:
-  BrowserAccessibilityManager(BrowserAccessibilityDelegate* delegate,
-                              BrowserAccessibilityFactory* factory);
+  explicit BrowserAccessibilityManager(BrowserAccessibilityDelegate* delegate);
 
   BrowserAccessibilityManager(const ui::AXTreeUpdate& initial_tree,
-                              BrowserAccessibilityDelegate* delegate,
-                              BrowserAccessibilityFactory* factory);
+                              BrowserAccessibilityDelegate* delegate);
 
   // Send platform-specific notifications to each of these objects that
   // their location has changed. This is called by OnLocationChanges
@@ -492,9 +480,6 @@
   // The object that can perform actions on our behalf.
   BrowserAccessibilityDelegate* delegate_;
 
-  // Factory to create BrowserAccessibility objects (for dependency injection).
-  std::unique_ptr<BrowserAccessibilityFactory> factory_;
-
   // A mapping from a node id to its wrapper of type BrowserAccessibility.
   std::map<int32_t, BrowserAccessibility*> id_wrapper_map_;
 
diff --git a/content/browser/accessibility/browser_accessibility_manager_android.cc b/content/browser/accessibility/browser_accessibility_manager_android.cc
index ef060dd..2bdbef83 100644
--- a/content/browser/accessibility/browser_accessibility_manager_android.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_android.cc
@@ -18,18 +18,16 @@
 // static
 BrowserAccessibilityManager* BrowserAccessibilityManager::Create(
     const ui::AXTreeUpdate& initial_tree,
-    BrowserAccessibilityDelegate* delegate,
-    BrowserAccessibilityFactory* factory) {
-  return new BrowserAccessibilityManagerAndroid(initial_tree, nullptr, delegate,
-                                                factory);
+    BrowserAccessibilityDelegate* delegate) {
+  return new BrowserAccessibilityManagerAndroid(initial_tree, nullptr,
+                                                delegate);
 }
 
 BrowserAccessibilityManagerAndroid::BrowserAccessibilityManagerAndroid(
     const ui::AXTreeUpdate& initial_tree,
     base::WeakPtr<WebContentsAccessibilityAndroid> web_contents_accessibility,
-    BrowserAccessibilityDelegate* delegate,
-    BrowserAccessibilityFactory* factory)
-    : BrowserAccessibilityManager(delegate, factory),
+    BrowserAccessibilityDelegate* delegate)
+    : BrowserAccessibilityManager(delegate),
       web_contents_accessibility_(std::move(web_contents_accessibility)),
       prune_tree_for_screen_reader_(true) {
   if (web_contents_accessibility_)
diff --git a/content/browser/accessibility/browser_accessibility_manager_android.h b/content/browser/accessibility/browser_accessibility_manager_android.h
index 52426d9b..367c503a 100644
--- a/content/browser/accessibility/browser_accessibility_manager_android.h
+++ b/content/browser/accessibility/browser_accessibility_manager_android.h
@@ -43,8 +43,7 @@
   BrowserAccessibilityManagerAndroid(
       const ui::AXTreeUpdate& initial_tree,
       base::WeakPtr<WebContentsAccessibilityAndroid> web_contents_accessibility,
-      BrowserAccessibilityDelegate* delegate,
-      BrowserAccessibilityFactory* factory = new BrowserAccessibilityFactory());
+      BrowserAccessibilityDelegate* delegate);
 
   ~BrowserAccessibilityManagerAndroid() override;
 
diff --git a/content/browser/accessibility/browser_accessibility_manager_auralinux.cc b/content/browser/accessibility/browser_accessibility_manager_auralinux.cc
index 035c84e..62ecc196 100644
--- a/content/browser/accessibility/browser_accessibility_manager_auralinux.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_auralinux.cc
@@ -17,10 +17,8 @@
 // static
 BrowserAccessibilityManager* BrowserAccessibilityManager::Create(
     const ui::AXTreeUpdate& initial_tree,
-    BrowserAccessibilityDelegate* delegate,
-    BrowserAccessibilityFactory* factory) {
-  return new BrowserAccessibilityManagerAuraLinux(initial_tree, delegate,
-                                                  factory);
+    BrowserAccessibilityDelegate* delegate) {
+  return new BrowserAccessibilityManagerAuraLinux(initial_tree, delegate);
 }
 
 BrowserAccessibilityManagerAuraLinux*
@@ -30,9 +28,8 @@
 
 BrowserAccessibilityManagerAuraLinux::BrowserAccessibilityManagerAuraLinux(
     const ui::AXTreeUpdate& initial_tree,
-    BrowserAccessibilityDelegate* delegate,
-    BrowserAccessibilityFactory* factory)
-    : BrowserAccessibilityManager(delegate, factory) {
+    BrowserAccessibilityDelegate* delegate)
+    : BrowserAccessibilityManager(delegate) {
   Initialize(initial_tree);
 }
 
diff --git a/content/browser/accessibility/browser_accessibility_manager_auralinux.h b/content/browser/accessibility/browser_accessibility_manager_auralinux.h
index 7ee8c62..91653161 100644
--- a/content/browser/accessibility/browser_accessibility_manager_auralinux.h
+++ b/content/browser/accessibility/browser_accessibility_manager_auralinux.h
@@ -17,10 +17,8 @@
 class CONTENT_EXPORT BrowserAccessibilityManagerAuraLinux
     : public BrowserAccessibilityManager {
  public:
-  BrowserAccessibilityManagerAuraLinux(
-      const ui::AXTreeUpdate& initial_tree,
-      BrowserAccessibilityDelegate* delegate,
-      BrowserAccessibilityFactory* factory = new BrowserAccessibilityFactory());
+  BrowserAccessibilityManagerAuraLinux(const ui::AXTreeUpdate& initial_tree,
+                                       BrowserAccessibilityDelegate* delegate);
 
   ~BrowserAccessibilityManagerAuraLinux() override;
 
diff --git a/content/browser/accessibility/browser_accessibility_manager_mac.h b/content/browser/accessibility/browser_accessibility_manager_mac.h
index 5f85185..8fb447a7 100644
--- a/content/browser/accessibility/browser_accessibility_manager_mac.h
+++ b/content/browser/accessibility/browser_accessibility_manager_mac.h
@@ -22,10 +22,8 @@
 class CONTENT_EXPORT BrowserAccessibilityManagerMac
     : public BrowserAccessibilityManager {
  public:
-  BrowserAccessibilityManagerMac(
-      const ui::AXTreeUpdate& initial_tree,
-      BrowserAccessibilityDelegate* delegate,
-      BrowserAccessibilityFactory* factory = new BrowserAccessibilityFactory());
+  BrowserAccessibilityManagerMac(const ui::AXTreeUpdate& initial_tree,
+                                 BrowserAccessibilityDelegate* delegate);
 
   ~BrowserAccessibilityManagerMac() override;
 
diff --git a/content/browser/accessibility/browser_accessibility_manager_mac.mm b/content/browser/accessibility/browser_accessibility_manager_mac.mm
index 8e8b6b78..ebe4e42 100644
--- a/content/browser/accessibility/browser_accessibility_manager_mac.mm
+++ b/content/browser/accessibility/browser_accessibility_manager_mac.mm
@@ -106,9 +106,8 @@
 // static
 BrowserAccessibilityManager* BrowserAccessibilityManager::Create(
     const ui::AXTreeUpdate& initial_tree,
-    BrowserAccessibilityDelegate* delegate,
-    BrowserAccessibilityFactory* factory) {
-  return new BrowserAccessibilityManagerMac(initial_tree, delegate, factory);
+    BrowserAccessibilityDelegate* delegate) {
+  return new BrowserAccessibilityManagerMac(initial_tree, delegate);
 }
 
 BrowserAccessibilityManagerMac*
@@ -118,9 +117,8 @@
 
 BrowserAccessibilityManagerMac::BrowserAccessibilityManagerMac(
     const ui::AXTreeUpdate& initial_tree,
-    BrowserAccessibilityDelegate* delegate,
-    BrowserAccessibilityFactory* factory)
-    : BrowserAccessibilityManager(delegate, factory) {
+    BrowserAccessibilityDelegate* delegate)
+    : BrowserAccessibilityManager(delegate) {
   Initialize(initial_tree);
   ax_tree()->SetEnableExtraMacNodes(true);
 }
diff --git a/content/browser/accessibility/browser_accessibility_manager_unittest.cc b/content/browser/accessibility/browser_accessibility_manager_unittest.cc
index f9aaaa5..362362f 100644
--- a/content/browser/accessibility/browser_accessibility_manager_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
+#include "build/buildflag.h"
 #include "content/browser/accessibility/browser_accessibility.h"
 #include "content/browser/accessibility/browser_accessibility_manager.h"
 #if defined(OS_WIN)
@@ -21,47 +22,6 @@
 namespace content {
 namespace {
 
-// Subclass of BrowserAccessibility that counts the number of instances.
-class CountedBrowserAccessibility : public BrowserAccessibility {
- public:
-  CountedBrowserAccessibility() {
-    global_obj_count_++;
-    native_ref_count_ = 1;
-  }
-  ~CountedBrowserAccessibility() override { global_obj_count_--; }
-
-  // TODO: Existing cross-platform BrowserAccessibiltity hypertext tests rely on
-  // the default behavior of inner text. Since hypertext implementations are
-  // platform specific and are unavailable here, refactor tests which rely on
-  // GetHypertext (such as GetRootFrameHypertextRangeBoundsRect) as platform
-  // unit tests.
-  base::string16 GetHypertext() const override { return GetInnerText(); }
-
-  void NativeAddReference() override { native_ref_count_++; }
-
-  void NativeReleaseReference() override {
-    native_ref_count_--;
-    if (native_ref_count_ == 0)
-      delete this;
-  }
-
-  bool CanFireEvents() const override { return false; }
-
-  int native_ref_count_;
-  static int global_obj_count_;
-};
-
-int CountedBrowserAccessibility::global_obj_count_ = 0;
-
-// Factory that creates a CountedBrowserAccessibility.
-class CountedBrowserAccessibilityFactory : public BrowserAccessibilityFactory {
- public:
-  ~CountedBrowserAccessibilityFactory() override {}
-  BrowserAccessibility* Create() override {
-    return new CountedBrowserAccessibility();
-  }
-};
-
 class CountingAXTreeObserver : public ui::AXTreeObserver {
  public:
   CountingAXTreeObserver() {}
@@ -104,427 +64,6 @@
       std::make_unique<TestBrowserAccessibilityDelegate>();
 }
 
-TEST_F(BrowserAccessibilityManagerTest, TestNoLeaks) {
-  // Create ui::AXNodeData objects for a simple document tree,
-  // representing the accessibility information used to initialize
-  // BrowserAccessibilityManager.
-  ui::AXNodeData button;
-  button.id = 2;
-  button.SetName("Button");
-  button.role = ax::mojom::Role::kButton;
-
-  ui::AXNodeData checkbox;
-  checkbox.id = 3;
-  checkbox.SetName("Checkbox");
-  checkbox.role = ax::mojom::Role::kCheckBox;
-
-  ui::AXNodeData root;
-  root.id = 1;
-  root.SetName("Document");
-  root.role = ax::mojom::Role::kRootWebArea;
-  root.child_ids.push_back(2);
-  root.child_ids.push_back(3);
-
-  // Construct a BrowserAccessibilityManager with this
-  // ui::AXNodeData tree and a factory for an instance-counting
-  // BrowserAccessibility, and ensure that exactly 3 instances were
-  // created. Note that the manager takes ownership of the factory.
-  CountedBrowserAccessibility::global_obj_count_ = 0;
-  BrowserAccessibilityManager* manager = BrowserAccessibilityManager::Create(
-      MakeAXTreeUpdate(root, button, checkbox),
-      test_browser_accessibility_delegate_.get(),
-      new CountedBrowserAccessibilityFactory());
-
-  ASSERT_EQ(3, CountedBrowserAccessibility::global_obj_count_);
-
-  // Delete the manager and test that all 3 instances are deleted.
-  delete manager;
-  ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_);
-
-  // Construct a manager again, and this time save references to two of
-  // the three nodes in the tree.
-  manager = BrowserAccessibilityManager::Create(
-      MakeAXTreeUpdate(root, button, checkbox),
-      test_browser_accessibility_delegate_.get(),
-      new CountedBrowserAccessibilityFactory());
-  ASSERT_EQ(3, CountedBrowserAccessibility::global_obj_count_);
-
-  CountedBrowserAccessibility* root_accessible =
-      static_cast<CountedBrowserAccessibility*>(manager->GetRoot());
-  root_accessible->NativeAddReference();
-  CountedBrowserAccessibility* child1_accessible =
-      static_cast<CountedBrowserAccessibility*>(
-          root_accessible->PlatformGetChild(1));
-  child1_accessible->NativeAddReference();
-
-  // Now delete the manager, and only one of the three nodes in the tree
-  // should be released.
-  delete manager;
-  ASSERT_EQ(2, CountedBrowserAccessibility::global_obj_count_);
-
-  // Release each of our references and make sure that each one results in
-  // the instance being deleted as its reference count hits zero.
-  root_accessible->NativeReleaseReference();
-  ASSERT_EQ(1, CountedBrowserAccessibility::global_obj_count_);
-  child1_accessible->NativeReleaseReference();
-  ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_);
-}
-
-TEST_F(BrowserAccessibilityManagerTest, TestReuseBrowserAccessibilityObjects) {
-  // Make sure that changes to a subtree reuse as many objects as possible.
-
-  // Tree 1:
-  //
-  // root
-  //   child1
-  //   child2
-  //   child3
-
-  ui::AXNodeData tree1_child1;
-  tree1_child1.id = 2;
-  tree1_child1.SetName("Child1");
-  tree1_child1.role = ax::mojom::Role::kButton;
-
-  ui::AXNodeData tree1_child2;
-  tree1_child2.id = 3;
-  tree1_child2.SetName("Child2");
-  tree1_child2.role = ax::mojom::Role::kButton;
-
-  ui::AXNodeData tree1_child3;
-  tree1_child3.id = 4;
-  tree1_child3.SetName("Child3");
-  tree1_child3.role = ax::mojom::Role::kButton;
-
-  ui::AXNodeData tree1_root;
-  tree1_root.id = 1;
-  tree1_root.SetName("Document");
-  tree1_root.role = ax::mojom::Role::kRootWebArea;
-  tree1_root.child_ids.push_back(2);
-  tree1_root.child_ids.push_back(3);
-  tree1_root.child_ids.push_back(4);
-
-  // Tree 2:
-  //
-  // root
-  //   child0  <-- inserted
-  //   child1
-  //   child2
-  //           <-- child3 deleted
-
-  ui::AXNodeData tree2_child0;
-  tree2_child0.id = 5;
-  tree2_child0.SetName("Child0");
-  tree2_child0.role = ax::mojom::Role::kButton;
-
-  ui::AXNodeData tree2_root;
-  tree2_root.id = 1;
-  tree2_root.SetName("DocumentChanged");
-  tree2_root.role = ax::mojom::Role::kRootWebArea;
-  tree2_root.child_ids.push_back(5);
-  tree2_root.child_ids.push_back(2);
-  tree2_root.child_ids.push_back(3);
-
-  // Construct a BrowserAccessibilityManager with tree1.
-  CountedBrowserAccessibility::global_obj_count_ = 0;
-  BrowserAccessibilityManager* manager = BrowserAccessibilityManager::Create(
-      MakeAXTreeUpdate(tree1_root, tree1_child1, tree1_child2, tree1_child3),
-      test_browser_accessibility_delegate_.get(),
-      new CountedBrowserAccessibilityFactory());
-  ASSERT_EQ(4, CountedBrowserAccessibility::global_obj_count_);
-
-  // Save references to all of the objects.
-  CountedBrowserAccessibility* root_accessible =
-      static_cast<CountedBrowserAccessibility*>(manager->GetRoot());
-  root_accessible->NativeAddReference();
-  CountedBrowserAccessibility* child1_accessible =
-      static_cast<CountedBrowserAccessibility*>(
-          root_accessible->PlatformGetChild(0));
-  child1_accessible->NativeAddReference();
-  CountedBrowserAccessibility* child2_accessible =
-      static_cast<CountedBrowserAccessibility*>(
-          root_accessible->PlatformGetChild(1));
-  child2_accessible->NativeAddReference();
-  CountedBrowserAccessibility* child3_accessible =
-      static_cast<CountedBrowserAccessibility*>(
-          root_accessible->PlatformGetChild(2));
-  child3_accessible->NativeAddReference();
-
-  // Check the index in parent.
-  EXPECT_EQ(0, child1_accessible->GetIndexInParent());
-  EXPECT_EQ(1, child2_accessible->GetIndexInParent());
-  EXPECT_EQ(2, child3_accessible->GetIndexInParent());
-
-  // Process a notification containing the changed subtree.
-  AXEventNotificationDetails notification;
-  notification.updates.resize(1);
-  notification.updates[0].nodes.push_back(tree2_root);
-  notification.updates[0].nodes.push_back(tree2_child0);
-  ASSERT_TRUE(manager->OnAccessibilityEvents(notification));
-
-  // There should be 5 objects now: the 4 from the new tree, plus the
-  // reference to child3 we kept.
-  EXPECT_EQ(5, CountedBrowserAccessibility::global_obj_count_);
-
-  // Check that our references to the root, child1, and child2 are still valid,
-  // but that the reference to child3 is now invalid.
-  EXPECT_TRUE(root_accessible->instance_active());
-  EXPECT_TRUE(child1_accessible->instance_active());
-  EXPECT_TRUE(child2_accessible->instance_active());
-  EXPECT_FALSE(child3_accessible->instance_active());
-
-  // Check that the index in parent has been updated.
-  EXPECT_EQ(1, child1_accessible->GetIndexInParent());
-  EXPECT_EQ(2, child2_accessible->GetIndexInParent());
-
-  // Release our references. The object count should only decrease by 1
-  // for child3.
-  root_accessible->NativeReleaseReference();
-  child1_accessible->NativeReleaseReference();
-  child2_accessible->NativeReleaseReference();
-  child3_accessible->NativeReleaseReference();
-
-  EXPECT_EQ(4, CountedBrowserAccessibility::global_obj_count_);
-
-  // Delete the manager and make sure all memory is cleaned up.
-  delete manager;
-  ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_);
-}
-
-TEST_F(BrowserAccessibilityManagerTest, TestReuseBrowserAccessibilityObjects2) {
-  // Similar to the test above, but with a more complicated tree.
-
-  // Tree 1:
-  //
-  // root
-  //   container
-  //     child1
-  //       grandchild1
-  //     child2
-  //       grandchild2
-  //     child3
-  //       grandchild3
-
-  ui::AXNodeData tree1_grandchild1;
-  tree1_grandchild1.id = 4;
-  tree1_grandchild1.SetName("GrandChild1");
-  tree1_grandchild1.role = ax::mojom::Role::kButton;
-
-  ui::AXNodeData tree1_child1;
-  tree1_child1.id = 3;
-  tree1_child1.SetName("Child1");
-  tree1_child1.role = ax::mojom::Role::kButton;
-  tree1_child1.child_ids.push_back(4);
-
-  ui::AXNodeData tree1_grandchild2;
-  tree1_grandchild2.id = 6;
-  tree1_grandchild2.SetName("GrandChild1");
-  tree1_grandchild2.role = ax::mojom::Role::kButton;
-
-  ui::AXNodeData tree1_child2;
-  tree1_child2.id = 5;
-  tree1_child2.SetName("Child2");
-  tree1_child2.role = ax::mojom::Role::kButton;
-  tree1_child2.child_ids.push_back(6);
-
-  ui::AXNodeData tree1_grandchild3;
-  tree1_grandchild3.id = 8;
-  tree1_grandchild3.SetName("GrandChild3");
-  tree1_grandchild3.role = ax::mojom::Role::kButton;
-
-  ui::AXNodeData tree1_child3;
-  tree1_child3.id = 7;
-  tree1_child3.SetName("Child3");
-  tree1_child3.role = ax::mojom::Role::kButton;
-  tree1_child3.child_ids.push_back(8);
-
-  ui::AXNodeData tree1_container;
-  tree1_container.id = 2;
-  tree1_container.SetName("Container");
-  tree1_container.role = ax::mojom::Role::kGroup;
-  tree1_container.child_ids.push_back(3);
-  tree1_container.child_ids.push_back(5);
-  tree1_container.child_ids.push_back(7);
-
-  ui::AXNodeData tree1_root;
-  tree1_root.id = 1;
-  tree1_root.SetName("Document");
-  tree1_root.role = ax::mojom::Role::kRootWebArea;
-  tree1_root.child_ids.push_back(2);
-
-  // Tree 2:
-  //
-  // root
-  //   container
-  //     child0         <-- inserted
-  //       grandchild0  <--
-  //     child1
-  //       grandchild1
-  //     child2
-  //       grandchild2
-  //                    <-- child3 (and grandchild3) deleted
-
-  ui::AXNodeData tree2_grandchild0;
-  tree2_grandchild0.id = 9;
-  tree2_grandchild0.SetName("GrandChild0");
-  tree2_grandchild0.role = ax::mojom::Role::kButton;
-
-  ui::AXNodeData tree2_child0;
-  tree2_child0.id = 10;
-  tree2_child0.SetName("Child0");
-  tree2_child0.role = ax::mojom::Role::kButton;
-  tree2_child0.child_ids.push_back(9);
-
-  ui::AXNodeData tree2_container;
-  tree2_container.id = 2;
-  tree2_container.SetName("Container");
-  tree2_container.role = ax::mojom::Role::kGroup;
-  tree2_container.child_ids.push_back(10);
-  tree2_container.child_ids.push_back(3);
-  tree2_container.child_ids.push_back(5);
-
-  // Construct a BrowserAccessibilityManager with tree1.
-  CountedBrowserAccessibility::global_obj_count_ = 0;
-  BrowserAccessibilityManager* manager = BrowserAccessibilityManager::Create(
-      MakeAXTreeUpdate(tree1_root, tree1_container, tree1_child1,
-                       tree1_grandchild1, tree1_child2, tree1_grandchild2,
-                       tree1_child3, tree1_grandchild3),
-      test_browser_accessibility_delegate_.get(),
-      new CountedBrowserAccessibilityFactory());
-  ASSERT_EQ(8, CountedBrowserAccessibility::global_obj_count_);
-
-  // Save references to some objects.
-  CountedBrowserAccessibility* root_accessible =
-      static_cast<CountedBrowserAccessibility*>(manager->GetRoot());
-  root_accessible->NativeAddReference();
-  CountedBrowserAccessibility* container_accessible =
-      static_cast<CountedBrowserAccessibility*>(
-          root_accessible->PlatformGetChild(0));
-  container_accessible->NativeAddReference();
-  CountedBrowserAccessibility* child2_accessible =
-      static_cast<CountedBrowserAccessibility*>(
-          container_accessible->PlatformGetChild(1));
-  child2_accessible->NativeAddReference();
-  CountedBrowserAccessibility* child3_accessible =
-      static_cast<CountedBrowserAccessibility*>(
-          container_accessible->PlatformGetChild(2));
-  child3_accessible->NativeAddReference();
-
-  // Check the index in parent.
-  EXPECT_EQ(1, child2_accessible->GetIndexInParent());
-  EXPECT_EQ(2, child3_accessible->GetIndexInParent());
-
-  // Process a notification containing the changed subtree rooted at
-  // the container.
-  AXEventNotificationDetails notification;
-  notification.updates.resize(1);
-  notification.updates[0].nodes.push_back(tree2_container);
-  notification.updates[0].nodes.push_back(tree2_child0);
-  notification.updates[0].nodes.push_back(tree2_grandchild0);
-  ASSERT_TRUE(manager->OnAccessibilityEvents(notification));
-
-  // There should be 9 objects now: the 8 from the new tree, plus the
-  // reference to child3 we kept.
-  EXPECT_EQ(9, CountedBrowserAccessibility::global_obj_count_);
-
-  // Check that our references to the root and container and child2 are
-  // still valid, but that the reference to child3 is now invalid.
-  EXPECT_TRUE(root_accessible->instance_active());
-  EXPECT_TRUE(container_accessible->instance_active());
-  EXPECT_TRUE(child2_accessible->instance_active());
-  EXPECT_FALSE(child3_accessible->instance_active());
-
-  // Ensure that we retain the parent of the detached subtree.
-  EXPECT_EQ(root_accessible, container_accessible->PlatformGetParent());
-  EXPECT_EQ(0, container_accessible->GetIndexInParent());
-
-  // Check that the index in parent has been updated.
-  EXPECT_EQ(2, child2_accessible->GetIndexInParent());
-
-  // Release our references. The object count should only decrease by 1
-  // for child3.
-  root_accessible->NativeReleaseReference();
-  container_accessible->NativeReleaseReference();
-  child2_accessible->NativeReleaseReference();
-  child3_accessible->NativeReleaseReference();
-
-  EXPECT_EQ(8, CountedBrowserAccessibility::global_obj_count_);
-
-  // Delete the manager and make sure all memory is cleaned up.
-  delete manager;
-  ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_);
-}
-
-TEST_F(BrowserAccessibilityManagerTest, TestMoveChildUp) {
-  // Tree 1:
-  //
-  // 1
-  //   2
-  //   3
-  //     4
-
-  ui::AXNodeData tree1_4;
-  tree1_4.id = 4;
-
-  ui::AXNodeData tree1_3;
-  tree1_3.id = 3;
-  tree1_3.child_ids.push_back(4);
-
-  ui::AXNodeData tree1_2;
-  tree1_2.id = 2;
-
-  ui::AXNodeData tree1_1;
-  tree1_1.id = 1;
-  tree1_1.role = ax::mojom::Role::kRootWebArea;
-  tree1_1.child_ids.push_back(2);
-  tree1_1.child_ids.push_back(3);
-
-  // Tree 2:
-  //
-  // 1
-  //   4    <-- moves up a level and gains child
-  //     6  <-- new
-  //   5    <-- new
-
-  ui::AXNodeData tree2_6;
-  tree2_6.id = 6;
-
-  ui::AXNodeData tree2_5;
-  tree2_5.id = 5;
-
-  ui::AXNodeData tree2_4;
-  tree2_4.id = 4;
-  tree2_4.child_ids.push_back(6);
-
-  ui::AXNodeData tree2_1;
-  tree2_1.id = 1;
-  tree2_1.child_ids.push_back(4);
-  tree2_1.child_ids.push_back(5);
-
-  // Construct a BrowserAccessibilityManager with tree1.
-  CountedBrowserAccessibility::global_obj_count_ = 0;
-  BrowserAccessibilityManager* manager = BrowserAccessibilityManager::Create(
-      MakeAXTreeUpdate(tree1_1, tree1_2, tree1_3, tree1_4),
-      test_browser_accessibility_delegate_.get(),
-      new CountedBrowserAccessibilityFactory());
-  ASSERT_EQ(4, CountedBrowserAccessibility::global_obj_count_);
-
-  // Process a notification containing the changed subtree.
-  AXEventNotificationDetails notification;
-  notification.updates.resize(1);
-  notification.updates[0].nodes.push_back(tree2_1);
-  notification.updates[0].nodes.push_back(tree2_4);
-  notification.updates[0].nodes.push_back(tree2_5);
-  notification.updates[0].nodes.push_back(tree2_6);
-  ASSERT_TRUE(manager->OnAccessibilityEvents(notification));
-
-  // There should be 4 objects now.
-  EXPECT_EQ(4, CountedBrowserAccessibility::global_obj_count_);
-
-  // Delete the manager and make sure all memory is cleaned up.
-  delete manager;
-  ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_);
-}
-
 // Temporarily disabled due to bug http://crbug.com/765490
 TEST_F(BrowserAccessibilityManagerTest, DISABLED_TestFatalError) {
   // Test that BrowserAccessibilityManager raises a fatal error
@@ -537,13 +76,10 @@
   root.child_ids.push_back(2);
   root.child_ids.push_back(2);
 
-  CountedBrowserAccessibilityFactory* factory =
-      new CountedBrowserAccessibilityFactory();
   std::unique_ptr<BrowserAccessibilityManager> manager;
   ASSERT_FALSE(test_browser_accessibility_delegate_->got_fatal_error());
   manager.reset(BrowserAccessibilityManager::Create(
-      MakeAXTreeUpdate(root), test_browser_accessibility_delegate_.get(),
-      factory));
+      MakeAXTreeUpdate(root), test_browser_accessibility_delegate_.get()));
   ASSERT_TRUE(test_browser_accessibility_delegate_->got_fatal_error());
 
   ui::AXNodeData root2;
@@ -572,14 +108,16 @@
   grandchild6.id = 6;
 
   test_browser_accessibility_delegate_->reset_got_fatal_error();
-  factory = new CountedBrowserAccessibilityFactory();
   manager.reset(BrowserAccessibilityManager::Create(
       MakeAXTreeUpdate(root2, child1, child2, grandchild4, grandchild5,
                        grandchild6),
-      test_browser_accessibility_delegate_.get(), factory));
+      test_browser_accessibility_delegate_.get()));
   ASSERT_TRUE(test_browser_accessibility_delegate_->got_fatal_error());
 }
 
+// This test depends on hypertext, which is only used on
+// Linux and Windows.
+#if defined(OS_WIN) || BUILDFLAG(USE_ATK)
 TEST_F(BrowserAccessibilityManagerTest, BoundsForRange) {
   ui::AXNodeData root;
   root.id = 1;
@@ -631,8 +169,7 @@
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, static_text, inline_text1, inline_text2),
-          test_browser_accessibility_delegate_.get(),
-          new CountedBrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   BrowserAccessibility* root_accessible = manager->GetRoot();
   ASSERT_NE(nullptr, root_accessible);
@@ -685,6 +222,7 @@
                     0, 13, ui::AXClippingBehavior::kUnclipped)
                 .ToString());
 }
+#endif  // defined(OS_WIN) || BUILDFLAG(USE_ATK)
 
 TEST_F(BrowserAccessibilityManagerTest, BoundsForRangeMultiElement) {
   ui::AXNodeData root;
@@ -731,8 +269,7 @@
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, static_text, inline_text1, static_text2,
                            inline_text2),
-          test_browser_accessibility_delegate_.get(),
-          new CountedBrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   BrowserAccessibility* root_accessible = manager->GetRoot();
   ASSERT_NE(nullptr, root_accessible);
@@ -793,6 +330,9 @@
                 .ToString());
 }
 
+// This test depends on hypertext, which is only used on
+// Linux and Windows.
+#if defined(OS_WIN) || BUILDFLAG(USE_ATK)
 TEST_F(BrowserAccessibilityManagerTest, BoundsForRangeBiDi) {
   // In this example, we assume that the string "123abc" is rendered with
   // "123" going left-to-right and "abc" going right-to-left. In other
@@ -846,8 +386,7 @@
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, static_text, inline_text1, inline_text2),
-          test_browser_accessibility_delegate_.get(),
-          new CountedBrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   BrowserAccessibility* root_accessible = manager->GetRoot();
   ASSERT_NE(nullptr, root_accessible);
@@ -893,7 +432,11 @@
                     2, 2, ui::AXClippingBehavior::kUnclipped)
                 .ToString());
 }
+#endif  // defined(OS_WIN) || BUILDFLAG(USE_ATK)
 
+// This test depends on hypertext, which is only used on
+// Linux and Windows.
+#if defined(OS_WIN) || BUILDFLAG(USE_ATK)
 TEST_F(BrowserAccessibilityManagerTest, BoundsForRangeScrolledWindow) {
   ui::AXNodeData root;
   root.id = 1;
@@ -926,8 +469,7 @@
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, static_text, inline_text),
-          test_browser_accessibility_delegate_.get(),
-          new CountedBrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   BrowserAccessibility* root_accessible = manager->GetRoot();
   ASSERT_NE(nullptr, root_accessible);
@@ -949,7 +491,11 @@
                   .ToString());
   }
 }
+#endif  // defined(OS_WIN) || BUILDFLAG(USE_ATK)
 
+// This test depends on hypertext, which is only used on
+// Linux and Windows.
+#if defined(OS_WIN) || BUILDFLAG(USE_ATK)
 TEST_F(BrowserAccessibilityManagerTest, BoundsForRangeOnParentElement) {
   ui::AXNodeData root;
   root.id = 1;
@@ -1013,8 +559,7 @@
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, div, static_text1, img, static_text2,
                            inline_text1, inline_text2),
-          test_browser_accessibility_delegate_.get(),
-          new CountedBrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
   BrowserAccessibility* root_accessible = manager->GetRoot();
   ASSERT_NE(nullptr, root_accessible);
   BrowserAccessibility* div_accessible = root_accessible->PlatformGetChild(0);
@@ -1056,6 +601,7 @@
                     0, 5, ui::AXClippingBehavior::kUnclipped)
                 .ToString());
 }
+#endif  // defined(OS_WIN) || BUILDFLAG(USE_ATK)
 
 TEST_F(BrowserAccessibilityManagerTest, TestNextPreviousInTreeOrder) {
   ui::AXNodeData root;
@@ -1081,8 +627,7 @@
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, node2, node3, node4, node5),
-          test_browser_accessibility_delegate_.get(),
-          new CountedBrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   BrowserAccessibility* root_accessible = manager->GetRoot();
   ASSERT_NE(nullptr, root_accessible);
@@ -1185,8 +730,7 @@
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, node2, node3, node4, node5),
-          test_browser_accessibility_delegate_.get(),
-          new CountedBrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   BrowserAccessibility* root_accessible = manager->GetRoot();
   ASSERT_NE(nullptr, root_accessible);
@@ -1245,6 +789,7 @@
 
   ui::AXNodeData node5;
   node5.id = 8;
+  node5.role = ax::mojom::Role::kGenericContainer;
   root.child_ids.push_back(8);
 
   ui::AXNodeData text4;
@@ -1252,12 +797,16 @@
   text4.role = ax::mojom::Role::kLineBreak;
   node5.child_ids.push_back(9);
 
+  ui::AXNodeData link;
+  link.id = 10;
+  link.role = ax::mojom::Role::kLink;
+  node5.child_ids.push_back(10);
+
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, node2, node3, node4, node5, text1, text2,
-                           text3, text4),
-          test_browser_accessibility_delegate_.get(),
-          new CountedBrowserAccessibilityFactory()));
+                           text3, text4, link),
+          test_browser_accessibility_delegate_.get()));
 
   BrowserAccessibility* root_accessible = manager->GetRoot();
   ASSERT_NE(nullptr, root_accessible);
@@ -1280,7 +829,7 @@
   ASSERT_NE(nullptr, text3_accessible);
   BrowserAccessibility* node5_accessible = root_accessible->PlatformGetChild(3);
   ASSERT_NE(nullptr, node5_accessible);
-  ASSERT_EQ(1U, node5_accessible->PlatformChildCount());
+  ASSERT_EQ(2U, node5_accessible->PlatformChildCount());
   BrowserAccessibility* text4_accessible =
       node5_accessible->PlatformGetChild(0);
   ASSERT_NE(nullptr, text4_accessible);
@@ -1313,6 +862,9 @@
   EXPECT_EQ(nullptr, manager->PreviousTextOnlyObject(root_accessible));
 }
 
+// This test depends on hypertext, which is only used on
+// Linux and Windows.
+#if defined(OS_WIN) || BUILDFLAG(USE_ATK)
 TEST_F(BrowserAccessibilityManagerTest, TestFindIndicesInCommonParent) {
   ui::AXNodeData root;
   root.id = 1;
@@ -1367,8 +919,7 @@
           MakeAXTreeUpdate(root, div, button, button_text, line_break,
                            paragraph, paragraph_text, paragraph_line1,
                            paragraph_line2),
-          test_browser_accessibility_delegate_.get(),
-          new CountedBrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   BrowserAccessibility* root_accessible = manager->GetRoot();
   ASSERT_NE(nullptr, root_accessible);
@@ -1456,7 +1007,11 @@
   EXPECT_EQ(0, child_index1);
   EXPECT_EQ(1, child_index2);
 }
+#endif  // defined(OS_WIN) || BUILDFLAG(USE_ATK)
 
+// This test depends on hypertext, which is only used on
+// Linux and Windows.
+#if defined(OS_WIN) || BUILDFLAG(USE_ATK)
 TEST_F(BrowserAccessibilityManagerTest, TestGetTextForRange) {
   ui::AXNodeData root;
   root.id = 1;
@@ -1523,8 +1078,7 @@
           MakeAXTreeUpdate(root, div, button, button_text, container,
                            container_text, line_break, paragraph,
                            paragraph_text, paragraph_line1, paragraph_line2),
-          test_browser_accessibility_delegate_.get(),
-          new CountedBrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   BrowserAccessibility* root_accessible = manager->GetRoot();
   ASSERT_NE(nullptr, root_accessible);
@@ -1640,6 +1194,7 @@
       BrowserAccessibilityManager::GetTextForRange(
           *paragraph_line2_accessible, 6, *paragraph_line1_accessible, 0));
 }
+#endif  // defined(OS_WIN) || BUILDFLAG(USE_ATK)
 
 TEST_F(BrowserAccessibilityManagerTest, DeletingFocusedNodeDoesNotCrash) {
   // Create a really simple tree with one root node and one focused child.
@@ -1656,8 +1211,7 @@
   initial_state.tree_data.focus_id = 2;
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
-          initial_state, test_browser_accessibility_delegate_.get(),
-          new CountedBrowserAccessibilityFactory()));
+          initial_state, test_browser_accessibility_delegate_.get()));
 
   EXPECT_EQ(1, manager->GetRoot()->GetId());
   ASSERT_NE(nullptr, manager->GetFocus());
@@ -1703,8 +1257,7 @@
   initial_state.tree_data.focus_id = 2;
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
-          initial_state, test_browser_accessibility_delegate_.get(),
-          new CountedBrowserAccessibilityFactory()));
+          initial_state, test_browser_accessibility_delegate_.get()));
 
   EXPECT_EQ(1, manager->GetRoot()->GetId());
   ASSERT_NE(nullptr, manager->GetFocus());
@@ -1745,8 +1298,7 @@
 
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
-          tree, test_browser_accessibility_delegate_.get(),
-          new CountedBrowserAccessibilityFactory()));
+          tree, test_browser_accessibility_delegate_.get()));
 
   CountingAXTreeObserver observer;
   manager->ax_tree()->AddObserver(&observer);
@@ -1826,13 +1378,11 @@
   // Create the two managers.
   std::unique_ptr<BrowserAccessibilityManager> parent_manager(
       BrowserAccessibilityManager::Create(
-          parent_update, test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          parent_update, test_browser_accessibility_delegate_.get()));
 
   std::unique_ptr<BrowserAccessibilityManager> child_manager(
       BrowserAccessibilityManager::Create(
-          child_update, test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          child_update, test_browser_accessibility_delegate_.get()));
 
   // Verify that they're properly connected.
   ASSERT_EQ(parent_manager.get(), child_manager->GetRootManager());
diff --git a/content/browser/accessibility/browser_accessibility_manager_win.cc b/content/browser/accessibility/browser_accessibility_manager_win.cc
index b422a0d..d6f6e86f 100644
--- a/content/browser/accessibility/browser_accessibility_manager_win.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_win.cc
@@ -30,9 +30,8 @@
 // static
 BrowserAccessibilityManager* BrowserAccessibilityManager::Create(
     const ui::AXTreeUpdate& initial_tree,
-    BrowserAccessibilityDelegate* delegate,
-    BrowserAccessibilityFactory* factory) {
-  return new BrowserAccessibilityManagerWin(initial_tree, delegate, factory);
+    BrowserAccessibilityDelegate* delegate) {
+  return new BrowserAccessibilityManagerWin(initial_tree, delegate);
 }
 
 BrowserAccessibilityManagerWin*
@@ -42,10 +41,8 @@
 
 BrowserAccessibilityManagerWin::BrowserAccessibilityManagerWin(
     const ui::AXTreeUpdate& initial_tree,
-    BrowserAccessibilityDelegate* delegate,
-    BrowserAccessibilityFactory* factory)
-    : BrowserAccessibilityManager(delegate, factory),
-      load_complete_pending_(false) {
+    BrowserAccessibilityDelegate* delegate)
+    : BrowserAccessibilityManager(delegate), load_complete_pending_(false) {
   ui::win::CreateATLModuleIfNeeded();
   Initialize(initial_tree);
 }
diff --git a/content/browser/accessibility/browser_accessibility_manager_win.h b/content/browser/accessibility/browser_accessibility_manager_win.h
index c67cdb9..49e2e10 100644
--- a/content/browser/accessibility/browser_accessibility_manager_win.h
+++ b/content/browser/accessibility/browser_accessibility_manager_win.h
@@ -31,10 +31,8 @@
 class CONTENT_EXPORT BrowserAccessibilityManagerWin
     : public BrowserAccessibilityManager {
  public:
-  BrowserAccessibilityManagerWin(
-      const ui::AXTreeUpdate& initial_tree,
-      BrowserAccessibilityDelegate* delegate,
-      BrowserAccessibilityFactory* factory = new BrowserAccessibilityFactory());
+  BrowserAccessibilityManagerWin(const ui::AXTreeUpdate& initial_tree,
+                                 BrowserAccessibilityDelegate* delegate);
 
   ~BrowserAccessibilityManagerWin() override;
 
diff --git a/content/browser/accessibility/browser_accessibility_manager_win_unittest.cc b/content/browser/accessibility/browser_accessibility_manager_win_unittest.cc
index 9d53a8be..d3d1ed4 100644
--- a/content/browser/accessibility/browser_accessibility_manager_win_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_win_unittest.cc
@@ -68,8 +68,7 @@
 
   std::unique_ptr<BrowserAccessibilityManager> root_manager(
       BrowserAccessibilityManager::Create(
-          MakeAXTreeUpdate(root), test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          MakeAXTreeUpdate(root), test_browser_accessibility_delegate_.get()));
 
   TestFragmentRootDelegate test_fragment_root_delegate(root_manager.get());
 
@@ -94,8 +93,7 @@
 
   std::unique_ptr<BrowserAccessibilityManager> iframe_manager(
       BrowserAccessibilityManager::Create(MakeAXTreeUpdate(root),
-                                          iframe_delegate.get(),
-                                          new BrowserAccessibilityFactory()));
+                                          iframe_delegate.get()));
 
   // The new frame is not a root frame, so the fragment root's lone child should
   // still be the same as before.
@@ -129,8 +127,7 @@
 
   std::unique_ptr<BrowserAccessibilityManager> parent_manager(
       BrowserAccessibilityManager::Create(
-          parent_tree_update, test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          parent_tree_update, test_browser_accessibility_delegate_.get()));
 
   TestFragmentRootDelegate test_fragment_root_delegate(parent_manager.get());
 
@@ -153,8 +150,7 @@
   child_tree_delegate->accelerated_widget_ = gfx::kMockAcceleratedWidget;
   std::unique_ptr<BrowserAccessibilityManager> child_manager(
       BrowserAccessibilityManager::Create(child_tree_update,
-                                          child_tree_delegate.get(),
-                                          new BrowserAccessibilityFactory()));
+                                          child_tree_delegate.get()));
 
   // The fragment root's lone child should still be the same as before.
   EXPECT_EQ(fragment_root->GetChildCount(), 1);
diff --git a/content/browser/accessibility/browser_accessibility_unittest.cc b/content/browser/accessibility/browser_accessibility_unittest.cc
index 163a967c..5b00a3b3 100644
--- a/content/browser/accessibility/browser_accessibility_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_unittest.cc
@@ -57,8 +57,7 @@
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, para1, text1),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   BrowserAccessibility* root_obj = manager->GetRoot();
   EXPECT_FALSE(root_obj->PlatformIsLeaf());
@@ -172,13 +171,11 @@
 
   std::unique_ptr<BrowserAccessibilityManager> parent_manager(
       BrowserAccessibilityManager::Create(
-          parent_tree_update, test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          parent_tree_update, test_browser_accessibility_delegate_.get()));
 
   std::unique_ptr<BrowserAccessibilityManager> child_manager(
       BrowserAccessibilityManager::Create(
-          child_tree_update, test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          child_tree_update, test_browser_accessibility_delegate_.get()));
 
   BrowserAccessibility* root_obj = parent_manager->GetRoot();
   // Test traversal
@@ -319,8 +316,7 @@
   std::unique_ptr<BrowserAccessibilityManager> browser_accessibility_manager(
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, static_text, inline_text1, inline_text2),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   BrowserAccessibility* root_accessible =
       browser_accessibility_manager->GetRoot();
@@ -435,8 +431,7 @@
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, static_text, inline_text1, static_text2,
                            inline_text2),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   BrowserAccessibility* root_accessible =
       browser_accessibility_manager->GetRoot();
@@ -562,8 +557,7 @@
   std::unique_ptr<BrowserAccessibilityManager> browser_accessibility_manager(
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, static_text, inline_text1, inline_text2),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   BrowserAccessibility* root_accessible =
       browser_accessibility_manager->GetRoot();
@@ -649,8 +643,7 @@
   std::unique_ptr<BrowserAccessibilityManager> browser_accessibility_manager(
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, static_text, inline_text),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   BrowserAccessibility* root_accessible =
       browser_accessibility_manager->GetRoot();
@@ -685,8 +678,7 @@
 
   std::unique_ptr<BrowserAccessibilityManager> browser_accessibility_manager(
       BrowserAccessibilityManager::Create(
-          MakeAXTreeUpdate(root), test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          MakeAXTreeUpdate(root), test_browser_accessibility_delegate_.get()));
   ASSERT_NE(nullptr, browser_accessibility_manager.get());
 
   BrowserAccessibility* root_accessible =
@@ -728,8 +720,7 @@
   std::unique_ptr<BrowserAccessibilityManager> browser_accessibility_manager(
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, input, static_text, inline_text),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
   ASSERT_NE(nullptr, browser_accessibility_manager.get());
 
   BrowserAccessibility* root_accessible =
@@ -807,13 +798,11 @@
 
   std::unique_ptr<BrowserAccessibilityManager> parent_manager(
       BrowserAccessibilityManager::Create(
-          parent_tree_update, test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          parent_tree_update, test_browser_accessibility_delegate_.get()));
 
   std::unique_ptr<BrowserAccessibilityManager> child_manager(
       BrowserAccessibilityManager::Create(
-          child_tree_update, test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          child_tree_update, test_browser_accessibility_delegate_.get()));
 
   // Portal node should use name from root of child tree.
   EXPECT_EQ("name", child_manager->GetRoot()->GetName());
@@ -844,8 +833,7 @@
   std::unique_ptr<BrowserAccessibilityManager> browser_accessibility_manager(
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, static_text),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
   ASSERT_NE(nullptr, browser_accessibility_manager.get());
 
   BrowserAccessibility* root_accessible =
diff --git a/content/browser/accessibility/browser_accessibility_win_unittest.cc b/content/browser/accessibility/browser_accessibility_win_unittest.cc
index f6e0719..69cac2a 100644
--- a/content/browser/accessibility/browser_accessibility_win_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_win_unittest.cc
@@ -151,8 +151,7 @@
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, button, checkbox),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   // Delete the manager and test that all 3 instances are deleted.
   manager.reset();
@@ -161,8 +160,7 @@
   // to get new references to two of the three nodes in the tree.
   manager.reset(BrowserAccessibilityManager::Create(
       MakeAXTreeUpdate(root, button, checkbox),
-      test_browser_accessibility_delegate_.get(),
-      new BrowserAccessibilityFactory()));
+      test_browser_accessibility_delegate_.get()));
   IAccessible* root_accessible =
       ToBrowserAccessibilityWin(manager->GetRoot())->GetCOM();
   IDispatch* root_iaccessible = NULL;
@@ -205,8 +203,7 @@
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, text),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   // Query for the text IAccessible and verify that it returns "old text" as its
   // value.
@@ -294,8 +291,7 @@
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, div, text3, text4),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   // Notify the BrowserAccessibilityManager that the div node and its children
   // were removed and ensure that only one BrowserAccessibility instance exists.
@@ -420,8 +416,7 @@
           MakeAXTreeUpdate(root, text_field, static_text1, inline_box1,
                            line_break1, static_text2, inline_box2, line_break2,
                            static_text3, inline_box3),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   BrowserAccessibilityWin* root_obj =
       ToBrowserAccessibilityWin(manager->GetRoot());
@@ -624,8 +619,7 @@
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, text1, text2),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   BrowserAccessibilityComWin* root_obj =
       ToBrowserAccessibilityWin(manager->GetRoot())->GetCOM();
@@ -739,8 +733,7 @@
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, text1, combo_box, text2, check_box, button,
                            button_text, link, link_text),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   BrowserAccessibilityComWin* root_obj =
       ToBrowserAccessibilityWin(manager->GetRoot())->GetCOM();
@@ -893,8 +886,7 @@
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, para1, text1, text2, text3, para2, text4,
                            text5, button, image),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   BrowserAccessibility* root_obj = manager->GetRoot();
   BrowserAccessibility* para_obj = root_obj->PlatformGetChild(0);
@@ -966,8 +958,7 @@
   std::unique_ptr<BrowserAccessibilityManager> manager(
       new BrowserAccessibilityManagerWin(
           BrowserAccessibilityManagerWin::GetEmptyDocument(),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   // Verify the root is as we expect by default.
   BrowserAccessibility* root = manager->GetRoot();
@@ -1047,8 +1038,7 @@
   std::unique_ptr<BrowserAccessibilityManagerWin> manager(
       new BrowserAccessibilityManagerWin(
           BrowserAccessibilityManagerWin::GetEmptyDocument(),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   // Verify the root is as we expect by default.
   BrowserAccessibility* root = manager->GetRoot();
@@ -1093,8 +1083,7 @@
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, pseudo_before, checkbox),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   ASSERT_NE(nullptr, manager->GetRoot());
   BrowserAccessibilityWin* root_accessible =
@@ -1206,8 +1195,7 @@
           MakeAXTreeUpdate(root, combo_box, combo_box_text, search_box,
                            search_box_text, new_line, text_field, link,
                            link_text, slider, slider_text),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   ASSERT_NE(nullptr, manager->GetRoot());
   BrowserAccessibilityWin* root_accessible =
@@ -1371,8 +1359,7 @@
           MakeAXTreeUpdate(root, textarea, textarea_div, textarea_text,
                            textarea_line1, textarea_line2, text_field,
                            text_field_div, text_field_text, text_field_line),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   ASSERT_NE(nullptr, manager->GetRoot());
   BrowserAccessibilityWin* root_accessible =
@@ -1474,8 +1461,7 @@
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root_data, menu_data, button_1_data, button_2_data,
                            static_text_data),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   ASSERT_NE(nullptr, manager->GetRoot());
   BrowserAccessibilityWin* root_accessible =
@@ -1608,8 +1594,7 @@
 
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
-          update, test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          update, test_browser_accessibility_delegate_.get()));
 
   ASSERT_NE(nullptr, manager->GetRoot());
   BrowserAccessibilityWin* root_accessible =
@@ -1879,8 +1864,7 @@
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, combo_box, text_field),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   ASSERT_NE(nullptr, manager->GetRoot());
   BrowserAccessibilityWin* root_accessible =
@@ -1995,8 +1979,7 @@
 
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
-          update, test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          update, test_browser_accessibility_delegate_.get()));
 
   ASSERT_NE(nullptr, manager->GetRoot());
   BrowserAccessibilityWin* root_accessible =
@@ -2118,8 +2101,7 @@
 
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
-          update, test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          update, test_browser_accessibility_delegate_.get()));
 
   ASSERT_NE(nullptr, manager->GetRoot());
   BrowserAccessibilityWin* root_accessible =
@@ -2254,8 +2236,7 @@
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, div, link, text),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   ASSERT_NE(nullptr, manager->GetRoot());
   BrowserAccessibilityWin* root_accessible =
@@ -2455,8 +2436,7 @@
 
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
-          update, test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          update, test_browser_accessibility_delegate_.get()));
 
   ASSERT_NE(nullptr, manager->GetRoot());
   BrowserAccessibilityWin* ax_root =
@@ -2687,8 +2667,7 @@
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, combo_box, combo_box_div, static_text1,
                            static_text2),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   ASSERT_NE(nullptr, manager->GetRoot());
   BrowserAccessibilityWin* ax_root =
@@ -2787,8 +2766,7 @@
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, combo_box, combo_box_div, static_text1,
                            static_text2),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   ASSERT_NE(nullptr, manager->GetRoot());
   BrowserAccessibilityWin* ax_root =
@@ -2893,8 +2871,7 @@
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, child1, child2, child2_child1, child2_child2),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   BrowserAccessibility* root_accessible = manager->GetRoot();
   ASSERT_NE(nullptr, root_accessible);
@@ -2977,8 +2954,7 @@
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, child1, child2, child2_child1, child2_child2),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   BrowserAccessibility* root_accessible = manager->GetRoot();
   ASSERT_NE(nullptr, root_accessible);
@@ -3037,8 +3013,7 @@
   std::unique_ptr<BrowserAccessibilityManagerWin> manager(
       new BrowserAccessibilityManagerWin(
           MakeAXTreeUpdate(root_node, child_node),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   BrowserAccessibility* root = manager->GetRoot();
   int32_t root_unique_id = GetUniqueId(root);
@@ -3048,8 +3023,7 @@
   // Now destroy that original tree and create a new tree.
   manager.reset(new BrowserAccessibilityManagerWin(
       MakeAXTreeUpdate(root_node, child_node),
-      test_browser_accessibility_delegate_.get(),
-      new BrowserAccessibilityFactory()));
+      test_browser_accessibility_delegate_.get()));
   root = manager->GetRoot();
   int32_t root_unique_id_2 = GetUniqueId(root);
   child = root->PlatformGetChild(0);
@@ -3098,8 +3072,7 @@
   std::unique_ptr<BrowserAccessibilityManagerWin> manager(
       new BrowserAccessibilityManagerWin(
           MakeAXTreeUpdate(root_node, child_node),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   BrowserAccessibility* root = manager->GetRoot();
   BrowserAccessibility* child = root->PlatformGetChild(0);
@@ -3138,8 +3111,7 @@
   std::unique_ptr<BrowserAccessibilityManager> manager(
       BrowserAccessibilityManager::Create(
           MakeAXTreeUpdate(root, child1, child2),
-          test_browser_accessibility_delegate_.get(),
-          new BrowserAccessibilityFactory()));
+          test_browser_accessibility_delegate_.get()));
 
   BrowserAccessibilityWin* ax_root =
       ToBrowserAccessibilityWin(manager->GetRoot());
diff --git a/content/browser/accessibility/one_shot_accessibility_tree_search_unittest.cc b/content/browser/accessibility/one_shot_accessibility_tree_search_unittest.cc
index 2bed95c..c920deb 100644
--- a/content/browser/accessibility/one_shot_accessibility_tree_search_unittest.cc
+++ b/content/browser/accessibility/one_shot_accessibility_tree_search_unittest.cc
@@ -29,10 +29,8 @@
 #else
 class TestBrowserAccessibilityManager : public BrowserAccessibilityManager {
  public:
-  TestBrowserAccessibilityManager(const ui::AXTreeUpdate& initial_tree)
-      : BrowserAccessibilityManager(initial_tree,
-                                    nullptr,
-                                    new BrowserAccessibilityFactory()) {}
+  explicit TestBrowserAccessibilityManager(const ui::AXTreeUpdate& initial_tree)
+      : BrowserAccessibilityManager(initial_tree, nullptr) {}
 };
 #endif
 
diff --git a/content/browser/accessibility/web_contents_accessibility_android.cc b/content/browser/accessibility/web_contents_accessibility_android.cc
index cf0a02b9..4633b8e 100644
--- a/content/browser/accessibility/web_contents_accessibility_android.cc
+++ b/content/browser/accessibility/web_contents_accessibility_android.cc
@@ -295,7 +295,7 @@
 
 void DeleteAutofillPopupProxy() {
   if (g_autofill_popup_proxy_node) {
-    g_autofill_popup_proxy_node->Destroy();
+    delete g_autofill_popup_proxy_node;
     delete g_autofill_popup_proxy_node_ax_node;
     g_autofill_popup_proxy_node = nullptr;
   }
diff --git a/content/browser/back_forward_cache_browsertest.cc b/content/browser/back_forward_cache_browsertest.cc
index dd8b9871..eba4665 100644
--- a/content/browser/back_forward_cache_browsertest.cc
+++ b/content/browser/back_forward_cache_browsertest.cc
@@ -62,8 +62,10 @@
 #include "services/device/public/cpp/test/fake_sensor_and_provider.h"
 #include "services/device/public/cpp/test/scoped_geolocation_overrider.h"
 #include "services/device/public/mojom/vibration_manager.mojom.h"
+#include "services/service_manager/public/cpp/interface_provider.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h"
+#include "third_party/blink/public/mojom/app_banner/app_banner.mojom.h"
 
 using testing::_;
 using testing::Each;
@@ -1987,6 +1989,91 @@
       FROM_HERE);
 }
 
+class MockAppBannerService : public blink::mojom::AppBannerService {
+ public:
+  MockAppBannerService() = default;
+  ~MockAppBannerService() override = default;
+
+  void Bind(mojo::ScopedMessagePipeHandle handle) {
+    receiver_.Bind(mojo::PendingReceiver<blink::mojom::AppBannerService>(
+        std::move(handle)));
+  }
+
+  mojo::Remote<blink::mojom::AppBannerController>& controller() {
+    return controller_;
+  }
+
+  void OnBannerPromptRequested(bool) {}
+
+  void SendBannerPromptRequest() {
+    blink::mojom::AppBannerController* controller_ptr = controller_.get();
+    base::OnceCallback<void(bool)> callback = base::BindOnce(
+        &MockAppBannerService::OnBannerPromptRequested, base::Unretained(this));
+    controller_ptr->BannerPromptRequest(
+        receiver_.BindNewPipeAndPassRemote(),
+        event_.BindNewPipeAndPassReceiver(), {"web"},
+        base::BindOnce(&MockAppBannerService::OnBannerPromptReply,
+                       base::Unretained(this), std::move(callback)));
+  }
+
+  void OnBannerPromptReply(base::OnceCallback<void(bool)> callback,
+                           blink::mojom::AppBannerPromptReply reply) {
+    std::move(callback).Run(reply ==
+                            blink::mojom::AppBannerPromptReply::CANCEL);
+  }
+
+  // blink::mojom::AppBannerService:
+  void DisplayAppBanner() override {}
+
+ private:
+  mojo::Receiver<blink::mojom::AppBannerService> receiver_{this};
+  mojo::Remote<blink::mojom::AppBannerEvent> event_;
+  mojo::Remote<blink::mojom::AppBannerController> controller_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockAppBannerService);
+};
+
+class BackForwardCacheBrowserTestWithAppBanner
+    : public BackForwardCacheBrowserTest {
+ protected:
+  void SetUpOnMainThread() override {
+    web_contents()->GetMainFrame()->GetRemoteInterfaces()->GetInterface(
+        mock_app_banner_service_.controller().BindNewPipeAndPassReceiver());
+    BackForwardCacheBrowserTest::SetUpOnMainThread();
+  }
+
+  void SendBannerPromptRequest() {
+    mock_app_banner_service_.SendBannerPromptRequest();
+  }
+
+ private:
+  MockAppBannerService mock_app_banner_service_;
+};
+
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithAppBanner,
+                       DoesNotCacheIfAppBanner) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  // 1) Navigate to A and request a PWA app banner.
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
+  SendBannerPromptRequest();
+  RenderFrameDeletedObserver delete_observer_rfh(current_frame_host());
+
+  // 2) Navigate away. Page A requested a PWA app banner, and thus not cached.
+  shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
+  delete_observer_rfh.WaitUntilDeleted();
+
+  // 3) Go back to A.
+  web_contents()->GetController().GoBack();
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+  ExpectNotRestored(
+      {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
+      FROM_HERE);
+  ExpectBlocklistedFeature(
+      blink::scheduler::WebSchedulerTrackedFeature::kAppBanner, FROM_HERE);
+}
+
 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
                        DoesNotCacheIfPageUnreachable) {
   ASSERT_TRUE(embedded_test_server()->Start());
diff --git a/content/browser/devtools/devtools_instrumentation.cc b/content/browser/devtools/devtools_instrumentation.cc
index 91da6cb..8ca9cfe 100644
--- a/content/browser/devtools/devtools_instrumentation.cc
+++ b/content/browser/devtools/devtools_instrumentation.cc
@@ -611,7 +611,7 @@
 }
 
 namespace {
-blink::mojom::SameSiteCookieIssueDetailsPtr BuildSameSiteCookieIssueDetails(
+std::vector<blink::mojom::SameSiteCookieExclusionReason> BuildExclusionReasons(
     net::CanonicalCookie::CookieInclusionStatus status) {
   std::vector<blink::mojom::SameSiteCookieExclusionReason> exclusion_reasons;
   if (status.HasExclusionReason(
@@ -625,7 +625,11 @@
     exclusion_reasons.push_back(blink::mojom::SameSiteCookieExclusionReason::
                                     ExcludeSameSiteNoneInsecure);
   }
+  return exclusion_reasons;
+}
 
+std::vector<blink::mojom::SameSiteCookieWarningReason> BuildWarningReasons(
+    net::CanonicalCookie::CookieInclusionStatus status) {
   std::vector<blink::mojom::SameSiteCookieWarningReason> warning_reasons;
   if (status.HasWarningReason(
           net::CanonicalCookie::CookieInclusionStatus::
@@ -679,28 +683,43 @@
     warning_reasons.push_back(blink::mojom::SameSiteCookieWarningReason::
                                   WarnSameSiteCrossSchemeInsecureUrlStrict);
   }
-
-  return blink::mojom::SameSiteCookieIssueDetails::New(
-      std::move(exclusion_reasons), std::move(warning_reasons));
+  return warning_reasons;
 }
 }  // namespace
 
-void ReportSameSiteCookieIssue(RenderFrameHostImpl* render_frame_host_impl,
-                               const net::CookieWithStatus& excluded_cookie,
-                               const GURL& url,
-                               const GURL& site_for_cookies) {
-  auto details = blink::mojom::InspectorIssueDetails::New();
-  details->sameSiteCookieIssueDetails =
-      BuildSameSiteCookieIssueDetails(excluded_cookie.status);
-  auto resources = blink::mojom::AffectedResources::New();
-  resources->cookies.push_back(blink::mojom::AffectedCookie::New(
+void ReportSameSiteCookieIssue(
+    RenderFrameHostImpl* render_frame_host_impl,
+    const net::CookieWithStatus& excluded_cookie,
+    const GURL& url,
+    const net::SiteForCookies& site_for_cookies,
+    blink::mojom::SameSiteCookieOperation operation,
+    const base::Optional<std::string>& devtools_request_id) {
+  blink::mojom::AffectedRequestPtr affected_request;
+  if (devtools_request_id) {
+    // We can report the url here, because if devtools_request_id is set, the
+    // url is the url of the request.
+    affected_request =
+        blink::mojom::AffectedRequest::New(*devtools_request_id, url.spec());
+  }
+  auto affected_cookie = blink::mojom::AffectedCookie::New(
       excluded_cookie.cookie.Name(), excluded_cookie.cookie.Path(),
-      excluded_cookie.cookie.Domain(), site_for_cookies));
+      excluded_cookie.cookie.Domain());
+  auto details = blink::mojom::InspectorIssueDetails::New();
+  base::Optional<GURL> optional_site_for_cookies_url;
+  if (!site_for_cookies.IsNull()) {
+    optional_site_for_cookies_url = site_for_cookies.RepresentativeUrl();
+  }
+  details->sameSiteCookieIssueDetails =
+      blink::mojom::SameSiteCookieIssueDetails::New(
+          std::move(affected_cookie),
+          BuildExclusionReasons(excluded_cookie.status),
+          BuildWarningReasons(excluded_cookie.status), operation,
+          optional_site_for_cookies_url, url, std::move(affected_request));
 
   render_frame_host_impl->AddInspectorIssue(
       blink::mojom::InspectorIssueInfo::New(
           blink::mojom::InspectorIssueCode::kSameSiteCookieIssue,
-          std::move(details), std::move(resources)));
+          std::move(details)));
 }
 
 }  // namespace devtools_instrumentation
diff --git a/content/browser/devtools/devtools_instrumentation.h b/content/browser/devtools/devtools_instrumentation.h
index 35726bd..8f79574 100644
--- a/content/browser/devtools/devtools_instrumentation.h
+++ b/content/browser/devtools/devtools_instrumentation.h
@@ -18,6 +18,7 @@
 #include "services/network/public/mojom/network_service.mojom.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
 #include "services/network/public/mojom/url_response_head.mojom-forward.h"
+#include "third_party/blink/public/mojom/devtools/inspector_issue.mojom-forward.h"
 
 class GURL;
 
@@ -158,10 +159,13 @@
 void PortalDetached(RenderFrameHostImpl* render_frame_host_impl);
 void PortalActivated(RenderFrameHostImpl* render_frame_host_impl);
 
-void ReportSameSiteCookieIssue(RenderFrameHostImpl* render_frame_host_impl,
-                               const net::CookieWithStatus& excluded_cookie,
-                               const GURL& url,
-                               const GURL& site_for_cookies);
+void ReportSameSiteCookieIssue(
+    RenderFrameHostImpl* render_frame_host_impl,
+    const net::CookieWithStatus& excluded_cookie,
+    const GURL& url,
+    const net::SiteForCookies& site_for_cookies,
+    blink::mojom::SameSiteCookieOperation operation,
+    const base::Optional<std::string>& devtools_request_id);
 }  // namespace devtools_instrumentation
 
 }  // namespace content
diff --git a/content/browser/frame_host/back_forward_cache_impl.cc b/content/browser/frame_host/back_forward_cache_impl.cc
index 0852e2f..9ce2816 100644
--- a/content/browser/frame_host/back_forward_cache_impl.cc
+++ b/content/browser/frame_host/back_forward_cache_impl.cc
@@ -148,7 +148,9 @@
       FeatureToBit(WebSchedulerTrackedFeature::kWebHID) |
       FeatureToBit(WebSchedulerTrackedFeature::kWakeLock) |
       FeatureToBit(WebSchedulerTrackedFeature::kWebShare) |
-      FeatureToBit(WebSchedulerTrackedFeature::kWebFileSystem);
+      FeatureToBit(WebSchedulerTrackedFeature::kWebFileSystem) |
+      FeatureToBit(WebSchedulerTrackedFeature::kAppBanner) |
+      FeatureToBit(WebSchedulerTrackedFeature::kPrinting);
 
   uint64_t result = kAlwaysDisallowedFeatures;
 
diff --git a/content/browser/frame_host/render_document_host_user_data_browsertest.cc b/content/browser/frame_host/render_document_host_user_data_browsertest.cc
index 9745046..062bdd96 100644
--- a/content/browser/frame_host/render_document_host_user_data_browsertest.cc
+++ b/content/browser/frame_host/render_document_host_user_data_browsertest.cc
@@ -59,7 +59,7 @@
 
   base::WeakPtrFactory<Data> weak_ptr_factory_{this};
 
-  RENDER_DOCUMENT_HOST_USER_USER_DATA_KEY_DECL();
+  RENDER_DOCUMENT_HOST_USER_DATA_KEY_DECL();
 };
 
 RENDER_DOCUMENT_HOST_USER_DATA_KEY_IMPL(Data)
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 55e1a04..8e11789f 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -431,6 +431,12 @@
                                  site_url.possibly_invalid_spec());
 }
 
+void LogCanCommitOriginAndUrlFailureReason(const std::string& failure_reason) {
+  static auto* failure_reason_key = base::debug::AllocateCrashKeyString(
+      "rfhi_can_commit_failure_reason", base::debug::CrashKeySize::Size64);
+  base::debug::SetCrashKeyString(failure_reason_key, failure_reason);
+}
+
 url::Origin GetOriginForURLLoaderFactoryUnchecked(
     NavigationRequest* navigation_request) {
   // Return a safe opaque origin when there is no |navigation_request| (e.g.
@@ -4864,8 +4870,10 @@
   }
 
   // Renderer-debug URLs can never be committed.
-  if (IsRendererDebugURL(url))
+  if (IsRendererDebugURL(url)) {
+    LogCanCommitOriginAndUrlFailureReason("is_renderer_debug_url");
     return CanCommitStatus::CANNOT_COMMIT_URL;
+  }
 
   // TODO(creis): We should also check for WebUI pages here.  Also, when the
   // out-of-process iframes implementation is ready, we should check for
@@ -4889,20 +4897,26 @@
           base::debug::AllocateCrashKeyString(
               "oopif_in_mhtml_page", base::debug::CrashKeySize::Size32),
           is_mhtml_document() ? "is_mhtml_doc" : "not_mhtml_doc");
+      LogCanCommitOriginAndUrlFailureReason("oopif_in_mhtml_page");
       return CanCommitStatus::CANNOT_COMMIT_URL;
     }
   }
 
   // Give the client a chance to disallow URLs from committing.
-  if (!GetContentClient()->browser()->CanCommitURL(GetProcess(), url))
+  if (!GetContentClient()->browser()->CanCommitURL(GetProcess(), url)) {
+    LogCanCommitOriginAndUrlFailureReason(
+        "content_client_disallowed_commit_url");
     return CanCommitStatus::CANNOT_COMMIT_URL;
+  }
 
   auto* policy = ChildProcessSecurityPolicyImpl::GetInstance();
   const CanCommitStatus can_commit_status = policy->CanCommitOriginAndUrl(
       GetProcess()->GetID(), GetSiteInstance()->GetIsolationContext(), origin,
       url);
-  if (can_commit_status != CanCommitStatus::CAN_COMMIT_ORIGIN_AND_URL)
+  if (can_commit_status != CanCommitStatus::CAN_COMMIT_ORIGIN_AND_URL) {
+    LogCanCommitOriginAndUrlFailureReason("cpspi_disallowed_commit");
     return can_commit_status;
+  }
 
   const auto origin_tuple_or_precursor_tuple =
       origin.GetTupleOrPrecursorTupleIfOpaque();
@@ -4912,8 +4926,11 @@
     // about:blank, data, and blob URLs.
 
     // Renderer-debug URLs can never be committed.
-    if (IsRendererDebugURL(origin_tuple_or_precursor_tuple.GetURL()))
+    if (IsRendererDebugURL(origin_tuple_or_precursor_tuple.GetURL())) {
+      LogCanCommitOriginAndUrlFailureReason(
+          "origin_or_precursor_is_renderer_debug_url");
       return CanCommitStatus::CANNOT_COMMIT_ORIGIN;
+    }
 
     // Give the client a chance to disallow origin URLs from committing.
     // TODO(acolwell): Fix this code to work with opaque origins. Currently
@@ -4921,6 +4938,8 @@
     // the commit to fail. These need to be investigated.
     if (!origin.opaque() && !GetContentClient()->browser()->CanCommitURL(
                                 GetProcess(), origin.GetURL())) {
+      LogCanCommitOriginAndUrlFailureReason(
+          "content_client_disallowed_commit_origin");
       return CanCommitStatus::CANNOT_COMMIT_ORIGIN;
     }
   }
diff --git a/content/browser/network_context_client_base_impl.cc b/content/browser/network_context_client_base_impl.cc
index a095086b..f525ff1 100644
--- a/content/browser/network_context_client_base_impl.cc
+++ b/content/browser/network_context_client_base_impl.cc
@@ -158,7 +158,8 @@
     int32_t routing_id,
     const GURL& url,
     const net::SiteForCookies& site_for_cookies,
-    const std::vector<net::CookieWithStatus>& cookie_list) {}
+    const std::vector<net::CookieWithStatus>& cookie_list,
+    const base::Optional<std::string>& devtools_request_id) {}
 
 void NetworkContextClientBase::OnCookiesRead(
     bool is_service_worker,
@@ -166,7 +167,8 @@
     int32_t routing_id,
     const GURL& url,
     const net::SiteForCookies& site_for_cookies,
-    const std::vector<net::CookieWithStatus>& cookie_list) {}
+    const std::vector<net::CookieWithStatus>& cookie_list,
+    const base::Optional<std::string>& devtools_request_id) {}
 
 #if defined(OS_ANDROID)
 void NetworkContextClientBase::OnGenerateHttpNegotiateAuthToken(
diff --git a/content/browser/speech/speech_recognizer_impl.cc b/content/browser/speech/speech_recognizer_impl.cc
index bd64fae..b03a554 100644
--- a/content/browser/speech/speech_recognizer_impl.cc
+++ b/content/browser/speech/speech_recognizer_impl.cc
@@ -224,7 +224,8 @@
   device_id_ = device_id;
 
   base::PostTask(FROM_HERE, {BrowserThread::IO},
-                 base::BindOnce(&SpeechRecognizerImpl::DispatchEvent, this,
+                 base::BindOnce(&SpeechRecognizerImpl::DispatchEvent,
+                                weak_ptr_factory_.GetWeakPtr(),
                                 FSMEventArgs(EVENT_PREPARE)));
 }
 
@@ -237,7 +238,8 @@
 
 void SpeechRecognizerImpl::StopAudioCapture() {
   base::PostTask(FROM_HERE, {BrowserThread::IO},
-                 base::BindOnce(&SpeechRecognizerImpl::DispatchEvent, this,
+                 base::BindOnce(&SpeechRecognizerImpl::DispatchEvent,
+                                weak_ptr_factory_.GetWeakPtr(),
                                 FSMEventArgs(EVENT_STOP_CAPTURE)));
 }
 
@@ -276,16 +278,16 @@
   // Convert audio from native format to fixed format used by WebSpeech.
   FSMEventArgs event_args(EVENT_AUDIO_DATA);
   event_args.audio_data = audio_converter_->Convert(data);
-  base::PostTask(
-      FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(&SpeechRecognizerImpl::DispatchEvent, this, event_args));
+  base::PostTask(FROM_HERE, {BrowserThread::IO},
+                 base::BindOnce(&SpeechRecognizerImpl::DispatchEvent,
+                                weak_ptr_factory_.GetWeakPtr(), event_args));
   // See http://crbug.com/506051 regarding why one extra convert call can
   // sometimes be required. It should be a rare case.
   if (!audio_converter_->data_was_converted()) {
     event_args.audio_data = audio_converter_->Convert(data);
-    base::PostTask(
-        FROM_HERE, {BrowserThread::IO},
-        base::BindOnce(&SpeechRecognizerImpl::DispatchEvent, this, event_args));
+    base::PostTask(FROM_HERE, {BrowserThread::IO},
+                   base::BindOnce(&SpeechRecognizerImpl::DispatchEvent,
+                                  weak_ptr_factory_.GetWeakPtr(), event_args));
   }
   // Something is seriously wrong here and we are most likely missing some
   // audio segments.
@@ -294,18 +296,18 @@
 
 void SpeechRecognizerImpl::OnCaptureError(const std::string& message) {
   FSMEventArgs event_args(EVENT_AUDIO_ERROR);
-  base::PostTask(
-      FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(&SpeechRecognizerImpl::DispatchEvent, this, event_args));
+  base::PostTask(FROM_HERE, {BrowserThread::IO},
+                 base::BindOnce(&SpeechRecognizerImpl::DispatchEvent,
+                                weak_ptr_factory_.GetWeakPtr(), event_args));
 }
 
 void SpeechRecognizerImpl::OnSpeechRecognitionEngineResults(
     const std::vector<blink::mojom::SpeechRecognitionResultPtr>& results) {
   FSMEventArgs event_args(EVENT_ENGINE_RESULT);
   event_args.engine_results = mojo::Clone(results);
-  base::PostTask(
-      FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(&SpeechRecognizerImpl::DispatchEvent, this, event_args));
+  base::PostTask(FROM_HERE, {BrowserThread::IO},
+                 base::BindOnce(&SpeechRecognizerImpl::DispatchEvent,
+                                weak_ptr_factory_.GetWeakPtr(), event_args));
 }
 
 void SpeechRecognizerImpl::OnSpeechRecognitionEngineEndOfUtterance() {
@@ -317,9 +319,9 @@
     const blink::mojom::SpeechRecognitionError& error) {
   FSMEventArgs event_args(EVENT_ENGINE_ERROR);
   event_args.engine_error = error;
-  base::PostTask(
-      FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(&SpeechRecognizerImpl::DispatchEvent, this, event_args));
+  base::PostTask(FROM_HERE, {BrowserThread::IO},
+                 base::BindOnce(&SpeechRecognizerImpl::DispatchEvent,
+                                weak_ptr_factory_.GetWeakPtr(), event_args));
 }
 
 // -----------------------  Core FSM implementation ---------------------------
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index a2c3fe53..c8224c0 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -423,11 +423,15 @@
 }
 
 // TODO(crbug.com/977040): Remove when no longer needed.
-void DeprecateSameSiteCookies(int process_id,
-                              int routing_id,
-                              const net::CookieStatusList& cookie_list,
-                              const GURL& url,
-                              const GURL& site_for_cookies) {
+
+void DeprecateSameSiteCookies(
+    int process_id,
+    int routing_id,
+    const net::CookieStatusList& cookie_list,
+    const GURL& url,
+    const net::SiteForCookies& site_for_cookies,
+    blink::mojom::SameSiteCookieOperation operation,
+    const base::Optional<std::string>& devtools_request_id) {
   // Navigation requests start in the browser, before process_id is assigned, so
   // the id is set to network::mojom::kBrowserProcessId. In these situations,
   // the routing_id is the frame tree node id, and can be used directly.
@@ -500,7 +504,8 @@
         samesite_none_insecure_cookies = true;
       }
       devtools_instrumentation::ReportSameSiteCookieIssue(
-          root_frame_host, excluded_cookie, url, site_for_cookies);
+          root_frame_host, excluded_cookie, url, site_for_cookies, operation,
+          devtools_request_id);
     }
     if (emit_messages) {
       root_frame_host->AddSameSiteCookieDeprecationMessage(
@@ -583,12 +588,14 @@
 void ReportCookiesChangedOnUI(
     std::vector<GlobalFrameRoutingId> destinations,
     const GURL& url,
-    const GURL& site_for_cookies,
-    const std::vector<net::CookieWithStatus>& cookie_list) {
+    const net::SiteForCookies& site_for_cookies,
+    const std::vector<net::CookieWithStatus>& cookie_list,
+    const base::Optional<std::string>& devtools_request_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   for (const GlobalFrameRoutingId& id : destinations) {
-    DeprecateSameSiteCookies(id.child_id, id.frame_routing_id, cookie_list, url,
-                             site_for_cookies);
+    DeprecateSameSiteCookies(
+        id.child_id, id.frame_routing_id, cookie_list, url, site_for_cookies,
+        blink::mojom::SameSiteCookieOperation::SetCookie, devtools_request_id);
   }
 
   for (const auto& cookie_and_status : cookie_list) {
@@ -600,7 +607,7 @@
             GetWebContentsForStoragePartition(id.child_id, id.frame_routing_id);
         if (!web_contents)
           continue;
-        web_contents->OnCookieChange(url, site_for_cookies,
+        web_contents->OnCookieChange(url, site_for_cookies.RepresentativeUrl(),
                                      cookie_and_status.cookie,
                                      /* blocked_by_policy =*/true);
       }
@@ -610,7 +617,7 @@
             GetWebContentsForStoragePartition(id.child_id, id.frame_routing_id);
         if (!web_contents)
           continue;
-        web_contents->OnCookieChange(url, site_for_cookies,
+        web_contents->OnCookieChange(url, site_for_cookies.RepresentativeUrl(),
                                      cookie_and_status.cookie,
                                      /* blocked_by_policy =*/false);
 
@@ -637,13 +644,15 @@
 void ReportCookiesReadOnUI(
     std::vector<GlobalFrameRoutingId> destinations,
     const GURL& url,
-    const GURL& site_for_cookies,
-    const std::vector<net::CookieWithStatus>& cookie_list) {
+    const net::SiteForCookies& site_for_cookies,
+    const std::vector<net::CookieWithStatus>& cookie_list,
+    const base::Optional<std::string>& devtools_request_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   for (const GlobalFrameRoutingId& id : destinations) {
-    DeprecateSameSiteCookies(id.child_id, id.frame_routing_id, cookie_list, url,
-                             site_for_cookies);
+    DeprecateSameSiteCookies(
+        id.child_id, id.frame_routing_id, cookie_list, url, site_for_cookies,
+        blink::mojom::SameSiteCookieOperation::ReadCookie, devtools_request_id);
   }
 
   net::CookieList accepted, blocked;
@@ -665,7 +674,8 @@
           GetWebContentsForStoragePartition(id.child_id, id.frame_routing_id);
       if (!web_contents)
         continue;
-      web_contents->OnCookiesRead(url, site_for_cookies, accepted,
+      web_contents->OnCookiesRead(url, site_for_cookies.RepresentativeUrl(),
+                                  accepted,
                                   /* blocked_by_policy =*/false);
 
       // TODO(https://crbug.com/1046456): Remove after deprecated.
@@ -693,7 +703,8 @@
           GetWebContentsForStoragePartition(id.child_id, id.frame_routing_id);
       if (!web_contents)
         continue;
-      web_contents->OnCookiesRead(url, site_for_cookies, blocked,
+      web_contents->OnCookiesRead(url, site_for_cookies.RepresentativeUrl(),
+                                  blocked,
                                   /* blocked_by_policy =*/true);
     }
   }
@@ -702,8 +713,9 @@
 void OnServiceWorkerCookiesReadOnCoreThread(
     scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
     const GURL& url,
-    const GURL& site_for_cookies,
-    const std::vector<net::CookieWithStatus>& cookie_list) {
+    const net::SiteForCookies& site_for_cookies,
+    const std::vector<net::CookieWithStatus>& cookie_list,
+    const base::Optional<std::string>& devtools_request_id) {
   DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
   // Notify all the frames associated with this service worker of its cookie
   // activity.
@@ -713,15 +725,16 @@
     RunOrPostTaskOnThread(
         FROM_HERE, BrowserThread::UI,
         base::BindOnce(ReportCookiesReadOnUI, *frame_routing_ids, url,
-                       site_for_cookies, cookie_list));
+                       site_for_cookies, cookie_list, devtools_request_id));
   }
 }
 
 void OnServiceWorkerCookiesChangedOnCoreThread(
     scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
     const GURL& url,
-    const GURL& site_for_cookies,
-    const std::vector<net::CookieWithStatus>& cookie_list) {
+    const net::SiteForCookies& site_for_cookies,
+    const std::vector<net::CookieWithStatus>& cookie_list,
+    const base::Optional<std::string>& devtools_request_id) {
   DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
   // Notify all the frames associated with this service worker of its cookie
   // activity.
@@ -731,7 +744,7 @@
     RunOrPostTaskOnThread(
         FROM_HERE, BrowserThread::UI,
         base::BindOnce(ReportCookiesChangedOnUI, *frame_routing_ids, url,
-                       site_for_cookies, cookie_list));
+                       site_for_cookies, cookie_list, devtools_request_id));
   }
 }
 
@@ -2039,20 +2052,21 @@
     int32_t routing_id,
     const GURL& url,
     const net::SiteForCookies& site_for_cookies,
-    const std::vector<net::CookieWithStatus>& cookie_list) {
+    const std::vector<net::CookieWithStatus>& cookie_list,
+    const base::Optional<std::string>& devtools_request_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(initialized_);
   if (is_service_worker) {
     RunOrPostTaskOnThread(
         FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
-        base::BindOnce(
-            &OnServiceWorkerCookiesChangedOnCoreThread, service_worker_context_,
-            url, site_for_cookies.RepresentativeUrl(), std::move(cookie_list)));
+        base::BindOnce(&OnServiceWorkerCookiesChangedOnCoreThread,
+                       service_worker_context_, url, site_for_cookies,
+                       cookie_list, devtools_request_id));
   } else {
     std::vector<GlobalFrameRoutingId> destination;
     destination.emplace_back(process_id, routing_id);
-    ReportCookiesChangedOnUI(destination, url,
-                             site_for_cookies.RepresentativeUrl(), cookie_list);
+    ReportCookiesChangedOnUI(destination, url, site_for_cookies, cookie_list,
+                             devtools_request_id);
   }
 }
 
@@ -2062,20 +2076,21 @@
     int32_t routing_id,
     const GURL& url,
     const net::SiteForCookies& site_for_cookies,
-    const std::vector<net::CookieWithStatus>& cookie_list) {
+    const std::vector<net::CookieWithStatus>& cookie_list,
+    const base::Optional<std::string>& devtools_request_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(initialized_);
   if (is_service_worker) {
     RunOrPostTaskOnThread(
         FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
-        base::BindOnce(
-            &OnServiceWorkerCookiesReadOnCoreThread, service_worker_context_,
-            url, site_for_cookies.RepresentativeUrl(), std::move(cookie_list)));
+        base::BindOnce(&OnServiceWorkerCookiesReadOnCoreThread,
+                       service_worker_context_, url, site_for_cookies,
+                       std::move(cookie_list), devtools_request_id));
   } else {
     std::vector<GlobalFrameRoutingId> destination;
     destination.emplace_back(process_id, routing_id);
-    ReportCookiesReadOnUI(destination, url,
-                          site_for_cookies.RepresentativeUrl(), cookie_list);
+    ReportCookiesReadOnUI(destination, url, site_for_cookies, cookie_list,
+                          devtools_request_id);
   }
 }
 
diff --git a/content/browser/storage_partition_impl.h b/content/browser/storage_partition_impl.h
index fb0f0737..eedad24 100644
--- a/content/browser/storage_partition_impl.h
+++ b/content/browser/storage_partition_impl.h
@@ -261,14 +261,16 @@
       int32_t routing_id,
       const GURL& url,
       const net::SiteForCookies& site_for_cookies,
-      const std::vector<net::CookieWithStatus>& cookie_list) override;
+      const std::vector<net::CookieWithStatus>& cookie_list,
+      const base::Optional<std::string>& devtools_request_id) override;
   void OnCookiesRead(
       bool is_service_worker,
       int32_t process_id,
       int32_t routing_id,
       const GURL& url,
       const net::SiteForCookies& site_for_cookies,
-      const std::vector<net::CookieWithStatus>& cookie_list) override;
+      const std::vector<net::CookieWithStatus>& cookie_list,
+      const base::Optional<std::string>& devtools_request_id) override;
 #if defined(OS_ANDROID)
   void OnGenerateHttpNegotiateAuthToken(
       const std::string& server_auth_token,
diff --git a/content/public/browser/network_context_client_base.h b/content/public/browser/network_context_client_base.h
index 0f7fa095..99490032 100644
--- a/content/public/browser/network_context_client_base.h
+++ b/content/public/browser/network_context_client_base.h
@@ -70,14 +70,16 @@
       int32_t routing_id,
       const GURL& url,
       const net::SiteForCookies& site_for_cookies,
-      const std::vector<net::CookieWithStatus>& cookie_list) override;
+      const std::vector<net::CookieWithStatus>& cookie_list,
+      const base::Optional<std::string>& devtools_request_id) override;
   void OnCookiesRead(
       bool is_service_worker,
       int32_t process_id,
       int32_t routing_id,
       const GURL& url,
       const net::SiteForCookies& site_for_cookies,
-      const std::vector<net::CookieWithStatus>& cookie_list) override;
+      const std::vector<net::CookieWithStatus>& cookie_list,
+      const base::Optional<std::string>& devtools_request_id) override;
 #if defined(OS_ANDROID)
   void OnGenerateHttpNegotiateAuthToken(
       const std::string& server_auth_token,
diff --git a/content/public/browser/render_document_host_user_data.h b/content/public/browser/render_document_host_user_data.h
index 87600154..f55f24f6 100644
--- a/content/public/browser/render_document_host_user_data.h
+++ b/content/public/browser/render_document_host_user_data.h
@@ -90,7 +90,7 @@
 // This macro declares a static variable inside the class that inherits from
 // RenderDocumentHostUserData. The address of this static variable is used as
 // the key to store/retrieve an instance of the class on/from a WebState.
-#define RENDER_DOCUMENT_HOST_USER_USER_DATA_KEY_DECL() \
+#define RENDER_DOCUMENT_HOST_USER_DATA_KEY_DECL() \
   static constexpr int kUserDataKey = 0
 
 // This macro instantiates the static variable declared by the previous macro.
diff --git a/content/public/common/BUILD.gn b/content/public/common/BUILD.gn
index e420139..aebd67f5 100644
--- a/content/public/common/BUILD.gn
+++ b/content/public/common/BUILD.gn
@@ -99,9 +99,6 @@
     "cdm_info.h",
     "child_process_host.h",
     "child_process_host_delegate.h",
-    "common_param_traits.cc",
-    "common_param_traits.h",
-    "common_param_traits_macros.h",
     "common_sandbox_support_linux.h",
     "console_message_level.h",
     "content_client.cc",
@@ -117,8 +114,6 @@
     "content_switch_dependent_feature_overrides.h",
     "content_switches.cc",
     "content_switches.h",
-    "drop_data.cc",
-    "drop_data.h",
     "font_cache_dispatcher_win.h",
     "frame_navigate_params.cc",
     "frame_navigate_params.h",
@@ -185,8 +180,6 @@
     "user_agent.h",
     "web_preferences.cc",
     "web_preferences.h",
-    "webplugininfo.cc",
-    "webplugininfo.h",
     "webplugininfo_param_traits.h",
     "widget_type.h",
   ]
@@ -199,6 +192,7 @@
   public_configs = [ "//v8:external_startup_data" ]
 
   public_deps = [
+    ":common_traits_types",
     ":interfaces",
     ":renderer_type",
     ":service_names",
@@ -220,6 +214,7 @@
     "//url/ipc:url_ipc",
   ]
   deps = [
+    ":common_traits_sources",
     ":content_descriptor_keys",
     "//build:branding_buildflags",
 
@@ -272,6 +267,7 @@
   # //content/common needs to include public headers.
   allow_circular_includes_from = [
     ":interfaces",
+    ":common_traits_sources",
     "//content/common",
     "//content/common:mojo_bindings",
   ]
@@ -284,6 +280,66 @@
   }
 }
 
+source_set("common_traits_types") {
+  visibility = [
+    ":common_sources",
+    ":common_traits_sources",
+  ]
+
+  sources = [
+    "drop_data.cc",
+    "drop_data.h",
+    "webplugininfo.cc",
+    "webplugininfo.h",
+  ]
+
+  configs += [
+    "//build/config:precompiled_headers",
+    "//content:content_implementation",
+  ]
+
+  deps = [
+    "//build:branding_buildflags",
+    "//content:export",
+    "//third_party/blink/public:blink_headers",
+    "//ui/base",
+    "//url",
+  ]
+}
+
+source_set("common_traits_sources") {
+  visibility = [
+    ":common_sources",
+    ":interfaces",
+  ]
+
+  sources = [
+    "common_param_traits.cc",
+    "common_param_traits.h",
+    "common_param_traits_macros.h",
+    "webplugininfo_param_traits.h",
+  ]
+
+  configs += [
+    "//build/config:precompiled_headers",
+    "//content:content_implementation",
+  ]
+
+  deps = [
+    "//build:branding_buildflags",
+    "//content:export",
+    "//third_party/blink/public:blink_headers",
+    "//third_party/blink/public/common",
+    "//ui/accessibility",
+    "//ui/base",
+    "//ui/gfx/ipc/geometry",
+    "//ui/gfx/ipc/skia",
+    "//ui/surface",
+  ]
+
+  public_deps = [ ":common_traits_types" ]
+}
+
 mojom("interfaces") {
   # We don't want Blink variants of these bindings to be generated.
   disable_variants = true
diff --git a/content/public/common/drop_data.typemap b/content/public/common/drop_data.typemap
index eaba6f9..96506c00 100644
--- a/content/public/common/drop_data.typemap
+++ b/content/public/common/drop_data.typemap
@@ -5,4 +5,5 @@
 mojom = "//content/public/common/drop_data.mojom"
 public_headers = [ "//content/public/common/drop_data.h" ]
 traits_headers = [ "//content/public/common/common_param_traits_macros.h" ]
+public_deps = [ "//content/public/common:common_traits_sources" ]
 type_mappings = [ "content.mojom.DropData=::content::DropData" ]
diff --git a/content/test/data/accessibility/event/css-flex-text-update-expected-auralinux.txt b/content/test/data/accessibility/event/css-flex-text-update-expected-auralinux.txt
index c68cfe9..483d5bb 100644
--- a/content/test/data/accessibility/event/css-flex-text-update-expected-auralinux.txt
+++ b/content/test/data/accessibility/event/css-flex-text-update-expected-auralinux.txt
@@ -1,3 +1,3 @@
-CHILDREN-CHANGED index:0 CHILD:(role=ROLE_STATIC) role=ROLE_STATIC ENABLED,SENSITIVE,SHOWING,VISIBLE
+CHILDREN-CHANGED index:-1 CHILD:(role=ROLE_STATIC) role=ROLE_STATIC ENABLED,SENSITIVE,SHOWING,VISIBLE
 NAME-CHANGED:new role=ROLE_STATIC name='new' ENABLED,SENSITIVE,SHOWING,VISIBLE
 STATE-CHANGE:DEFUNCT:TRUE role=ROLE_INVALID name='(null)' DEFUNCT
diff --git a/content/test/data/accessibility/event/text-changed-expected-auralinux.txt b/content/test/data/accessibility/event/text-changed-expected-auralinux.txt
index b1573d5a..0fe6700c9 100644
--- a/content/test/data/accessibility/event/text-changed-expected-auralinux.txt
+++ b/content/test/data/accessibility/event/text-changed-expected-auralinux.txt
@@ -1,7 +1,7 @@
+CHILDREN-CHANGED index:-1 CHILD:(role=ROLE_STATIC) role=ROLE_STATIC ENABLED,SENSITIVE,SHOWING,VISIBLE
+CHILDREN-CHANGED index:-1 CHILD:(role=ROLE_STATIC) role=ROLE_STATIC ENABLED,SENSITIVE,SHOWING,VISIBLE
 CHILDREN-CHANGED index:0 CHILD:(role=ROLE_STATIC) role=ROLE_PARAGRAPH ENABLED,SENSITIVE,SHOWING,VISIBLE
 CHILDREN-CHANGED index:0 CHILD:(role=ROLE_STATIC) role=ROLE_PARAGRAPH ENABLED,SENSITIVE,SHOWING,VISIBLE
-CHILDREN-CHANGED index:0 CHILD:(role=ROLE_STATIC) role=ROLE_STATIC ENABLED,SENSITIVE,SHOWING,VISIBLE
-CHILDREN-CHANGED index:0 CHILD:(role=ROLE_STATIC) role=ROLE_STATIC ENABLED,SENSITIVE,SHOWING,VISIBLE
 NAME-CHANGED:Modified Div role=ROLE_STATIC name='Modified Div' ENABLED,SENSITIVE,SHOWING,VISIBLE
 NAME-CHANGED:Modified Heading role=ROLE_STATIC name='Modified Heading' ENABLED,SENSITIVE,SHOWING,VISIBLE
 STATE-CHANGE:DEFUNCT:TRUE role=ROLE_INVALID name='(null)' DEFUNCT
diff --git a/gpu/command_buffer/service/context_group.cc b/gpu/command_buffer/service/context_group.cc
index 83759c17..51452b9 100644
--- a/gpu/command_buffer/service/context_group.cc
+++ b/gpu/command_buffer/service/context_group.cc
@@ -626,7 +626,7 @@
   }
 
   if (passthrough_discardable_manager_) {
-    passthrough_discardable_manager_->DeleteContextGroup(this);
+    passthrough_discardable_manager_->DeleteContextGroup(this, have_context);
   }
 
   if (passthrough_resources_) {
diff --git a/gpu/command_buffer/service/passthrough_discardable_manager.cc b/gpu/command_buffer/service/passthrough_discardable_manager.cc
index 82d433d3..d96fdc0 100644
--- a/gpu/command_buffer/service/passthrough_discardable_manager.cc
+++ b/gpu/command_buffer/service/passthrough_discardable_manager.cc
@@ -108,12 +108,27 @@
 }
 
 void PassthroughDiscardableManager::DeleteContextGroup(
-    const gles2::ContextGroup* context_group) {
+    const gles2::ContextGroup* context_group,
+    bool has_context) {
+  DCHECK(context_group);
+
+  DeleteTextures(context_group, has_context);
+}
+
+void PassthroughDiscardableManager::OnContextLost() {
+  DeleteTextures(nullptr, false);
+}
+
+void PassthroughDiscardableManager::DeleteTextures(
+    const gles2::ContextGroup* context_group,
+    bool has_context) {
   auto iter = cache_.begin();
   while (iter != cache_.end()) {
-    if (iter->first.second == context_group) {
+    if (iter->first.second == context_group || !context_group) {
       iter->second.handle.ForceDelete();
       total_size_ -= iter->second.size;
+      if (!has_context && iter->second.unlocked_texture)
+        iter->second.unlocked_texture->MarkContextLost();
       iter = cache_.Erase(iter);
     } else {
       iter++;
diff --git a/gpu/command_buffer/service/passthrough_discardable_manager.h b/gpu/command_buffer/service/passthrough_discardable_manager.h
index c8a566a1..c69055af 100644
--- a/gpu/command_buffer/service/passthrough_discardable_manager.h
+++ b/gpu/command_buffer/service/passthrough_discardable_manager.h
@@ -33,8 +33,12 @@
                    const gles2::ContextGroup* context_group);
 
   // Called when a context group is deleted, clean up all textures from this
-  // group
-  void DeleteContextGroup(const gles2::ContextGroup* context_group);
+  // group.
+  void DeleteContextGroup(const gles2::ContextGroup* context_group,
+                          bool has_context);
+
+  // Called when all contexts with cached textures in this manager are lost.
+  void OnContextLost();
 
   // Called when a texture is deleted, to clean up state.
   void DeleteTexture(uint32_t client_id,
@@ -80,6 +84,11 @@
     size_t size = 0;
   };
 
+  // Delete textures belonging to |context_group|. If |context_group| is null
+  // then all textures are deleted.
+  void DeleteTextures(const gles2::ContextGroup* context_group,
+                      bool has_context);
+
   using DiscardableCache =
       base::MRUCache<DiscardableCacheKey, DiscardableCacheValue>;
   DiscardableCache cache_;
diff --git a/gpu/command_buffer/service/service_discardable_manager.cc b/gpu/command_buffer/service/service_discardable_manager.cc
index 94bae955..5c58686 100644
--- a/gpu/command_buffer/service/service_discardable_manager.cc
+++ b/gpu/command_buffer/service/service_discardable_manager.cc
@@ -228,6 +228,18 @@
   entries_.Erase(found);
 }
 
+void ServiceDiscardableManager::OnContextLost() {
+  auto iter = entries_.begin();
+  while (iter != entries_.end()) {
+    iter->second.handle.ForceDelete();
+    if (iter->second.unlocked_texture_ref)
+      iter->second.unlocked_texture_ref->ForceContextLost();
+
+    total_size_ -= iter->second.size;
+    iter = entries_.Erase(iter);
+  }
+}
+
 void ServiceDiscardableManager::OnTextureSizeChanged(
     uint32_t texture_id,
     gles2::TextureManager* texture_manager,
diff --git a/gpu/command_buffer/service/service_discardable_manager.h b/gpu/command_buffer/service/service_discardable_manager.h
index 522b4a16..6d273a0 100644
--- a/gpu/command_buffer/service/service_discardable_manager.h
+++ b/gpu/command_buffer/service/service_discardable_manager.h
@@ -67,6 +67,9 @@
                             gles2::TextureManager* texture_manager,
                             size_t new_size);
 
+  // Called when all contexts with cached textures in this manager are lost.
+  void OnContextLost();
+
   // Test only functions:
   size_t NumCacheEntriesForTesting() const { return entries_.size(); }
   bool IsEntryLockedForTesting(uint32_t texture_id,
diff --git a/gpu/ipc/service/gpu_channel_manager.cc b/gpu/ipc/service/gpu_channel_manager.cc
index 3d81f6e..de356776 100644
--- a/gpu/ipc/service/gpu_channel_manager.cc
+++ b/gpu/ipc/service/gpu_channel_manager.cc
@@ -434,6 +434,8 @@
 void GpuChannelManager::LoseAllContexts() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
+  discardable_manager_.OnContextLost();
+  passthrough_discardable_manager_.OnContextLost();
   share_group_ = base::MakeRefCounted<gl::GLShareGroup>();
   for (auto& kv : gpu_channels_) {
     kv.second->MarkAllContextsLost();
@@ -609,10 +611,15 @@
 
   if (program_cache_)
     program_cache_->HandleMemoryPressure(memory_pressure_level);
-  discardable_manager_.HandleMemoryPressure(memory_pressure_level);
-  passthrough_discardable_manager_.HandleMemoryPressure(memory_pressure_level);
-  if (shared_context_state_)
+
+  // These caches require a current context for cleanup.
+  if (shared_context_state_ &&
+      shared_context_state_->MakeCurrent(nullptr, true /* needs_gl */)) {
+    discardable_manager_.HandleMemoryPressure(memory_pressure_level);
+    passthrough_discardable_manager_.HandleMemoryPressure(
+        memory_pressure_level);
     shared_context_state_->PurgeMemory(memory_pressure_level);
+  }
   if (gr_shader_cache_)
     gr_shader_cache_->PurgeMemory(memory_pressure_level);
 #if defined(OS_WIN)
diff --git a/ios/chrome/browser/pref_names.cc b/ios/chrome/browser/pref_names.cc
index 1994fe9c..af0cd7f7 100644
--- a/ios/chrome/browser/pref_names.cc
+++ b/ios/chrome/browser/pref_names.cc
@@ -96,9 +96,6 @@
 const char kMetricsReportingWifiOnly[] =
     "ios.user_experience_metrics.wifi_only";
 
-// Which page should be visible on the new tab page v4
-const char kNtpShownPage[] = "ntp.shown_page";
-
 // Boolean controlling whether history saving is disabled.
 const char kSavingBrowserHistoryDisabled[] = "history.saving_disabled";
 
diff --git a/ios/chrome/browser/pref_names.h b/ios/chrome/browser/pref_names.h
index eacae2b5..b01868ef 100644
--- a/ios/chrome/browser/pref_names.h
+++ b/ios/chrome/browser/pref_names.h
@@ -29,7 +29,6 @@
 extern const char kIosSettingsSigninPromoDisplayedCount[];
 extern const char kLastSessionExitedCleanly[];
 extern const char kMetricsReportingWifiOnly[];
-extern const char kNtpShownPage[];
 extern const char kSavingBrowserHistoryDisabled[];
 extern const char kSearchSuggestEnabled[];
 
diff --git a/ios/chrome/browser/prefs/browser_prefs.mm b/ios/chrome/browser/prefs/browser_prefs.mm
index 5807c99..182d375 100644
--- a/ios/chrome/browser/prefs/browser_prefs.mm
+++ b/ios/chrome/browser/prefs/browser_prefs.mm
@@ -72,7 +72,6 @@
 #endif
 
 namespace {
-const char kReverseAutologinEnabled[] = "reverse_autologin.enabled";
 const char kLastKnownGoogleURL[] = "browser.last_known_google_url";
 const char kLastPromptedGoogleURL[] = "browser.last_prompted_google_url";
 
@@ -197,7 +196,6 @@
       prefs::kSearchSuggestEnabled, true,
       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
   registry->RegisterBooleanPref(prefs::kSavingBrowserHistoryDisabled, false);
-  registry->RegisterIntegerPref(prefs::kNtpShownPage, 1 << 10);
 
   // This comes from components/bookmarks/core/browser/bookmark_model.h
   // Defaults to 3, which is the id of bookmarkModel_->mobile_node()
@@ -206,7 +204,6 @@
   // Register prefs used by Clear Browsing Data UI.
   browsing_data::prefs::RegisterBrowserUserPrefs(registry);
 
-  registry->RegisterBooleanPref(kReverseAutologinEnabled, true);
   registry->RegisterStringPref(kLastKnownGoogleURL, std::string());
   registry->RegisterStringPref(kLastPromptedGoogleURL, std::string());
   registry->RegisterStringPref(kGoogleServicesUsername, std::string());
@@ -236,15 +233,9 @@
 
 // This method should be periodically pruned of year+ old migrations.
 void MigrateObsoleteBrowserStatePrefs(PrefService* prefs) {
-  // Added 01/2018.
-  prefs->ClearPref(::prefs::kNtpShownPage);
-
-  // Added 8/2018.
+  // Check MigrateDeprecatedAutofillPrefs() to see if this is safe to remove.
   autofill::prefs::MigrateDeprecatedAutofillPrefs(prefs);
 
-  // Added 10/2018.
-  prefs->ClearPref(kReverseAutologinEnabled);
-
   // Added 07/2019.
   syncer::MigrateSyncSuppressedPref(prefs);
   syncer::ClearObsoleteMemoryPressurePrefs(prefs);
diff --git a/ios/chrome/browser/tabs/tab_model.mm b/ios/chrome/browser/tabs/tab_model.mm
index 3cb54cf9..3a29fff 100644
--- a/ios/chrome/browser/tabs/tab_model.mm
+++ b/ios/chrome/browser/tabs/tab_model.mm
@@ -133,9 +133,10 @@
 
   web::NavigationItem* pending_item = navigation_manager->GetPendingItem();
   if (pending_item) {
+    UIView* webView = navigation->GetWebState()->GetView();
     if (IsTransitionBetweenDesktopAndMobileUserAgent(
-            pending_item->GetUserAgentType(),
-            last_committed_item->GetUserAgentType())) {
+            pending_item->GetUserAgentType(webView),
+            last_committed_item->GetUserAgentType(webView))) {
       // Switching between Desktop and Mobile user agent.
       return NO;
     }
diff --git a/ios/chrome/browser/ui/activity_services/share_to_data_builder.mm b/ios/chrome/browser/ui/activity_services/share_to_data_builder.mm
index d3cb96bd..60e54141 100644
--- a/ios/chrome/browser/ui/activity_services/share_to_data_builder.mm
+++ b/ios/chrome/browser/ui/activity_services/share_to_data_builder.mm
@@ -57,7 +57,7 @@
       web_state->GetNavigationManager()->GetVisibleItem();
   web::UserAgentType userAgent = web::UserAgentType::NONE;
   if (visibleItem)
-    userAgent = visibleItem->GetUserAgentType();
+    userAgent = visibleItem->GetUserAgentType(web_state->GetView());
 
   FindTabHelper* helper = FindTabHelper::FromWebState(web_state);
   BOOL is_page_searchable =
diff --git a/ios/chrome/browser/ui/app_launcher/BUILD.gn b/ios/chrome/browser/ui/app_launcher/BUILD.gn
index 52eae05..a94a988 100644
--- a/ios/chrome/browser/ui/app_launcher/BUILD.gn
+++ b/ios/chrome/browser/ui/app_launcher/BUILD.gn
@@ -18,12 +18,16 @@
     "//ios/chrome/app/strings:ios_strings_grit",
     "//ios/chrome/browser",
     "//ios/chrome/browser/app_launcher",
+    "//ios/chrome/browser/main:public",
     "//ios/chrome/browser/overlays",
     "//ios/chrome/browser/overlays/public/web_content_area",
     "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
     "//ios/chrome/browser/ui/dialogs:feature_flags",
+    "//ios/chrome/browser/web_state_list",
     "//ios/public/provider/chrome/browser",
     "//ios/public/provider/chrome/browser/mailto",
+    "//ios/web/public",
+    "//ios/web/public/navigation",
     "//net",
     "//ui/base",
     "//url",
diff --git a/ios/chrome/browser/ui/app_launcher/app_launcher_coordinator.mm b/ios/chrome/browser/ui/app_launcher/app_launcher_coordinator.mm
index 26181fc..0b6f446 100644
--- a/ios/chrome/browser/ui/app_launcher/app_launcher_coordinator.mm
+++ b/ios/chrome/browser/ui/app_launcher/app_launcher_coordinator.mm
@@ -11,6 +11,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/app_launcher/app_launcher_tab_helper.h"
+#import "ios/chrome/browser/main/browser.h"
 #include "ios/chrome/browser/overlays/public/overlay_callback_manager.h"
 #import "ios/chrome/browser/overlays/public/overlay_request.h"
 #import "ios/chrome/browser/overlays/public/overlay_request_queue.h"
@@ -19,9 +20,13 @@
 #include "ios/chrome/browser/procedural_block_types.h"
 #import "ios/chrome/browser/ui/app_launcher/app_launcher_util.h"
 #import "ios/chrome/browser/ui/dialogs/dialog_features.h"
+#import "ios/chrome/browser/web_state_list/web_state_list.h"
+#import "ios/chrome/browser/web_state_list/web_state_opener.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #include "ios/public/provider/chrome/browser/mailto/mailto_handler_provider.h"
+#import "ios/web/public/navigation/navigation_manager.h"
+#import "ios/web/public/web_state.h"
 #import "net/base/mac/url_conversions.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "url/gurl.h"
@@ -115,12 +120,11 @@
   if (base::FeatureList::IsEnabled(dialogs::kNonModalDialogs)) {
     std::unique_ptr<OverlayRequest> request =
         OverlayRequest::CreateWithConfig<AppLauncherAlertOverlayRequestConfig>(
-            /* is_repeated_request= */ false);
+            /*is_repeated_request=*/false);
     request->GetCallbackManager()->AddCompletionCallback(
         base::BindOnce(&AppLauncherOverlayCallback, completion));
-    OverlayRequestQueue::FromWebState(webState,
-                                      OverlayModality::kWebContentArea)
-        ->AddRequest(std::move(request));
+    [self overlayRequestQueueForWebState:webState]->AddRequest(
+        std::move(request));
   } else {
     [self showAlertWithMessage:prompt
              acceptActionTitle:openLabel
@@ -129,6 +133,26 @@
   }
 }
 
+// Returns the OverlayRequestQueue to use when displaying the app launcher
+// dialog when requested by |webState|.
+- (OverlayRequestQueue*)overlayRequestQueueForWebState:
+    (web::WebState*)webState {
+  web::WebState* queueWebState = webState;
+  // If an app launch navigation is occurring in a new tab, the tab will be
+  // closed immediately after the navigation fails, cancelling the app launcher
+  // dialog before it gets a chance to be shown.  When this occurs, use the
+  // OverlayRequestQueue for the tab's opener instead.
+  if (!webState->GetNavigationManager()->GetItemCount() &&
+      webState->HasOpener()) {
+    WebStateList* webStateList = self.browser->GetWebStateList();
+    int index = webStateList->GetIndexOfWebState(webState);
+    queueWebState =
+        webStateList->GetOpenerOfWebStateAt(index).opener ?: queueWebState;
+  }
+  return OverlayRequestQueue::FromWebState(queueWebState,
+                                           OverlayModality::kWebContentArea);
+}
+
 #pragma mark - AppLauncherTabHelperDelegate
 
 - (BOOL)appLauncherTabHelper:(AppLauncherTabHelper*)tabHelper
diff --git a/ios/chrome/browser/ui/app_launcher/app_launcher_coordinator_unittest.mm b/ios/chrome/browser/ui/app_launcher/app_launcher_coordinator_unittest.mm
index 967141f..38f9939 100644
--- a/ios/chrome/browser/ui/app_launcher/app_launcher_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/app_launcher/app_launcher_coordinator_unittest.mm
@@ -16,6 +16,7 @@
 #import "ios/chrome/browser/ui/dialogs/dialog_features.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/chrome/test/scoped_key_window.h"
+#import "ios/web/public/test/fakes/test_navigation_manager.h"
 #import "ios/web/public/test/fakes/test_web_state.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
@@ -41,6 +42,11 @@
     application_ = OCMClassMock([UIApplication class]);
     OCMStub([application_ sharedApplication]).andReturn(application_);
     AppLauncherTabHelper::CreateForWebState(&web_state_, nil, nil);
+    std::unique_ptr<web::TestNavigationManager> navigation_manager =
+        std::make_unique<web::TestNavigationManager>();
+    navigation_manager->AddItem(GURL("http://www.chromium.org"),
+                                ui::PAGE_TRANSITION_LINK);
+    web_state_.SetNavigationManager(std::move(navigation_manager));
   }
   ~AppLauncherCoordinatorTest() override {
     [application_ stopMocking];
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 60425c39..85f8d625 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -889,7 +889,7 @@
   if (!visibleItem)
     return web::UserAgentType::NONE;
 
-  return visibleItem->GetUserAgentType();
+  return visibleItem->GetUserAgentType(self.view);
 }
 
 - (void)setVisible:(BOOL)visible {
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm
index 5ffad90..3371912 100644
--- a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm
+++ b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm
@@ -981,7 +981,7 @@
   if (!visibleItem)
     return web::UserAgentType::NONE;
 
-  return visibleItem->GetUserAgentType();
+  return visibleItem->GetUserAgentType(self.webState->GetView());
 }
 
 @end
diff --git a/ios/web/navigation/crw_js_navigation_handler.mm b/ios/web/navigation/crw_js_navigation_handler.mm
index 90e9455..b3cd4db 100644
--- a/ios/web/navigation/crw_js_navigation_handler.mm
+++ b/ios/web/navigation/crw_js_navigation_handler.mm
@@ -183,8 +183,7 @@
         self.navigationManagerImpl->GetItemAtIndex(currentIndex - 1);
     web::UserAgentType userAgent = previousItem->GetUserAgentForInheritance();
     if (userAgent != web::UserAgentType::NONE) {
-      navItem->SetUserAgentType(userAgent,
-                                /*update_inherited_user_agent =*/true);
+      navItem->SetUserAgentType(userAgent);
     }
   }
   // If the user interacted with the page, categorize it as a link navigation.
diff --git a/ios/web/navigation/crw_wk_navigation_handler.mm b/ios/web/navigation/crw_wk_navigation_handler.mm
index 710f56c..2671616 100644
--- a/ios/web/navigation/crw_wk_navigation_handler.mm
+++ b/ios/web/navigation/crw_wk_navigation_handler.mm
@@ -158,7 +158,7 @@
   // code path leaving it uninitialized.
   web::UserAgentType userAgentType;
   if (item) {
-    userAgentType = item->GetUserAgentType();
+    userAgentType = item->GetUserAgentType(webView);
   } else {
     // Probably a renderer-initiated navigation. Use the UserAgent of the
     // previous navigation.
diff --git a/ios/web/navigation/navigation_item_impl.h b/ios/web/navigation/navigation_item_impl.h
index cdb9f12..07a872c 100644
--- a/ios/web/navigation/navigation_item_impl.h
+++ b/ios/web/navigation/navigation_item_impl.h
@@ -56,9 +56,9 @@
   SSLStatus& GetSSL() override;
   void SetTimestamp(base::Time timestamp) override;
   base::Time GetTimestamp() const override;
-  void SetUserAgentType(UserAgentType type,
-                        bool update_inherited_user_agent) override;
-  UserAgentType GetUserAgentType() const override;
+  void SetUserAgentType(UserAgentType type) override;
+  UserAgentType GetUserAgentType(
+      id<UITraitEnvironment> web_view) const override;
   UserAgentType GetUserAgentForInheritance() const override;
   bool HasPostData() const override;
   NSDictionary* GetHttpRequestHeaders() const override;
diff --git a/ios/web/navigation/navigation_item_impl.mm b/ios/web/navigation/navigation_item_impl.mm
index c4aa87d..e43096e 100644
--- a/ios/web/navigation/navigation_item_impl.mm
+++ b/ios/web/navigation/navigation_item_impl.mm
@@ -109,14 +109,13 @@
   cached_display_title_.clear();
   error_retry_state_machine_.SetURL(url);
   if (!wk_navigation_util::URLNeedsUserAgentType(url)) {
-    SetUserAgentType(UserAgentType::NONE,
-                     /*update_inherited_user_agent =*/true);
-  } else if (GetUserAgentType() == web::UserAgentType::NONE) {
+    SetUserAgentType(UserAgentType::NONE);
+  } else if (GetUserAgentForInheritance() == web::UserAgentType::NONE) {
     UserAgentType type =
         base::FeatureList::IsEnabled(features::kUseDefaultUserAgentInWebClient)
             ? UserAgentType::AUTOMATIC
             : UserAgentType::MOBILE;
-    SetUserAgentType(type, /*update_inherited_user_agent =*/true);
+    SetUserAgentType(type);
   }
 }
 
@@ -210,11 +209,8 @@
   return timestamp_;
 }
 
-void NavigationItemImpl::SetUserAgentType(UserAgentType type,
-                                          bool update_inherited_user_agent) {
+void NavigationItemImpl::SetUserAgentType(UserAgentType type) {
   user_agent_type_ = type;
-  if (update_inherited_user_agent)
-    user_agent_type_inheritance_ = type;
   DCHECK_EQ(!wk_navigation_util::URLNeedsUserAgentType(GetURL()),
             user_agent_type_ == UserAgentType::NONE);
 }
@@ -227,12 +223,20 @@
   return is_untrusted_;
 }
 
-UserAgentType NavigationItemImpl::GetUserAgentType() const {
+UserAgentType NavigationItemImpl::GetUserAgentType(
+    id<UITraitEnvironment> web_view) const {
+  if (user_agent_type_ == UserAgentType::AUTOMATIC) {
+    DCHECK(base::FeatureList::IsEnabled(
+        features::kUseDefaultUserAgentInWebClient));
+    // TODO: Find a way to get the WebView. Passed as parameter?
+    UIView* web_view = nil;
+    return GetWebClient()->GetDefaultUserAgent(web_view, url_);
+  }
   return user_agent_type_;
 }
 
 UserAgentType NavigationItemImpl::GetUserAgentForInheritance() const {
-  return user_agent_type_inheritance_;
+  return user_agent_type_;
 }
 
 bool NavigationItemImpl::HasPostData() const {
@@ -341,10 +345,8 @@
 void NavigationItemImpl::RestoreStateFromItem(NavigationItem* other) {
   // Only restore the UserAgent type and the page display state. The other
   // headers might not make sense after creating a new navigation to the page.
-  bool inherited_user_agent =
-      other->GetUserAgentType() == other->GetUserAgentForInheritance();
-  if (other->GetUserAgentType() != UserAgentType::NONE) {
-    SetUserAgentType(other->GetUserAgentType(), inherited_user_agent);
+  if (other->GetUserAgentForInheritance() != UserAgentType::NONE) {
+    SetUserAgentType(other->GetUserAgentForInheritance());
   }
   SetPageDisplayState(other->GetPageDisplayState());
 }
@@ -379,7 +381,7 @@
       stringWithFormat:
           @"url:%s virtual_url_:%s originalurl:%s referrer: %s title:%s "
           @"transition:%d "
-           "displayState:%@ userAgentType:%s userAgentForInheritance:%s "
+           "displayState:%@ userAgent:%s "
            "is_create_from_push_state: %@ "
            "has_state_been_replaced: %@ is_created_from_hash_change: %@ "
            "navigation_initiation_type: %d",
@@ -388,7 +390,6 @@
           base::UTF16ToUTF8(title_).c_str(), transition_type_,
           page_display_state_.GetDescription(),
           GetUserAgentTypeDescription(user_agent_type_).c_str(),
-          GetUserAgentTypeDescription(user_agent_type_inheritance_).c_str(),
           is_created_from_push_state_ ? @"true" : @"false",
           has_state_been_replaced_ ? @"true" : @"false",
           is_created_from_hash_change_ ? @"true" : @"false",
diff --git a/ios/web/navigation/navigation_item_impl_unittest.mm b/ios/web/navigation/navigation_item_impl_unittest.mm
index 72870b7..e09fbb4c 100644
--- a/ios/web/navigation/navigation_item_impl_unittest.mm
+++ b/ios/web/navigation/navigation_item_impl_unittest.mm
@@ -58,7 +58,7 @@
   EXPECT_TRUE([description containsString:@"originalurl:http://init.test/"]);
   EXPECT_TRUE([description containsString:@"title:Title"]);
   EXPECT_TRUE([description containsString:@"transition:2"]);
-  EXPECT_TRUE([description containsString:@"userAgentType:MOBILE"]);
+  EXPECT_TRUE([description containsString:@"userAgent:MOBILE"]);
   EXPECT_TRUE([description containsString:@"is_create_from_push_state: false"]);
   EXPECT_TRUE([description containsString:@"has_state_been_replaced: false"]);
   EXPECT_TRUE(
@@ -189,31 +189,24 @@
 
 // Tests that SetURL correctly updates user agent type.
 TEST_F(NavigationItemTest, UpdateUserAgentType) {
-  ASSERT_EQ(UserAgentType::MOBILE, item_->GetUserAgentType());
+  ASSERT_EQ(UserAgentType::MOBILE, item_->GetUserAgentType(nil));
 
   // about:blank resets User Agent to NONE.
   GURL no_user_agent_url(url::kAboutBlankURL);
   ASSERT_FALSE(wk_navigation_util::URLNeedsUserAgentType(no_user_agent_url));
   item_->SetURL(no_user_agent_url);
-  EXPECT_EQ(UserAgentType::NONE, item_->GetUserAgentType());
+  EXPECT_EQ(UserAgentType::NONE, item_->GetUserAgentType(nil));
 
   // Regular HTTP URL resets User Agent to MOBILE.
   GURL user_agent_url(kItemURLString);
   ASSERT_TRUE(wk_navigation_util::URLNeedsUserAgentType(user_agent_url));
   item_->SetURL(user_agent_url);
-  EXPECT_EQ(UserAgentType::MOBILE, item_->GetUserAgentType());
+  EXPECT_EQ(UserAgentType::MOBILE, item_->GetUserAgentType(nil));
 
   // Regular HTTP URL does not reset DESKTOP User Agent to MOBILE.
-  item_->SetUserAgentType(UserAgentType::DESKTOP,
-                          /*update_inherited_user_agent =*/true);
+  item_->SetUserAgentType(UserAgentType::DESKTOP);
   item_->SetURL(user_agent_url);
-  EXPECT_EQ(UserAgentType::DESKTOP, item_->GetUserAgentType());
-  EXPECT_EQ(UserAgentType::DESKTOP, item_->GetUserAgentForInheritance());
-
-  // Reset the UserAgentType to Mobile, without updating the inheritance.
-  item_->SetUserAgentType(UserAgentType::MOBILE,
-                          /*update_inherited_user_agent =*/false);
-  EXPECT_EQ(UserAgentType::MOBILE, item_->GetUserAgentType());
+  EXPECT_EQ(UserAgentType::DESKTOP, item_->GetUserAgentType(nil));
   EXPECT_EQ(UserAgentType::DESKTOP, item_->GetUserAgentForInheritance());
 }
 
diff --git a/ios/web/navigation/navigation_item_storage_builder.mm b/ios/web/navigation/navigation_item_storage_builder.mm
index a7b0dbb..c9cf2bf 100644
--- a/ios/web/navigation/navigation_item_storage_builder.mm
+++ b/ios/web/navigation/navigation_item_storage_builder.mm
@@ -24,7 +24,7 @@
   storage.displayState = navigation_item->GetPageDisplayState();
   storage.shouldSkipRepostFormConfirmation =
       navigation_item->ShouldSkipRepostFormConfirmation();
-  storage.userAgentType = navigation_item->GetUserAgentType();
+  storage.userAgentType = navigation_item->GetUserAgentForInheritance();
   storage.POSTData = navigation_item->GetPostData();
   storage.HTTPRequestHeaders = navigation_item->GetHttpRequestHeaders();
   return storage;
diff --git a/ios/web/navigation/navigation_manager_impl.h b/ios/web/navigation/navigation_manager_impl.h
index 26633e05..e894e156 100644
--- a/ios/web/navigation/navigation_manager_impl.h
+++ b/ios/web/navigation/navigation_manager_impl.h
@@ -223,10 +223,9 @@
 
   // Applies the user agent override to |pending_item|, or inherits the user
   // agent of |inherit_from| if |user_agent_override_option| is INHERIT.
-  static void UpdatePendingItemUserAgentType(
-      UserAgentOverrideOption override_option,
-      const NavigationItem* inherit_from,
-      NavigationItem* pending_item);
+  void UpdatePendingItemUserAgentType(UserAgentOverrideOption override_option,
+                                      const NavigationItem* inherit_from,
+                                      NavigationItem* pending_item);
 
   // Must be called by subclasses before restoring |item_count| navigation
   // items.
diff --git a/ios/web/navigation/navigation_manager_impl.mm b/ios/web/navigation/navigation_manager_impl.mm
index 2e30ee7..c2b52927 100644
--- a/ios/web/navigation/navigation_manager_impl.mm
+++ b/ios/web/navigation/navigation_manager_impl.mm
@@ -11,6 +11,7 @@
 #import "ios/web/navigation/navigation_manager_delegate.h"
 #import "ios/web/navigation/wk_navigation_util.h"
 #import "ios/web/public/web_client.h"
+#import "ios/web/public/web_state.h"
 #include "ui/base/page_transition_types.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -72,7 +73,6 @@
   return nullptr;
 }
 
-/* static */
 void NavigationManagerImpl::UpdatePendingItemUserAgentType(
     UserAgentOverrideOption user_agent_override_option,
     const NavigationItem* inherit_from_item,
@@ -82,35 +82,32 @@
   // |user_agent_override_option| must be INHERIT if |pending_item|'s
   // UserAgentType is NONE, as requesting a desktop or mobile user agent should
   // be disabled for app-specific URLs.
-  DCHECK(pending_item->GetUserAgentType() != UserAgentType::NONE ||
+  DCHECK(pending_item->GetUserAgentForInheritance() != UserAgentType::NONE ||
          user_agent_override_option == UserAgentOverrideOption::INHERIT);
 
   // Newly created pending items are created with UserAgentType::NONE for native
-  // pages or UserAgentType::MOBILE for non-native pages.  If the pending item's
-  // URL is non-native, check which user agent type it should be created with
-  // based on |user_agent_override_option|.
-  DCHECK_NE(UserAgentType::DESKTOP, pending_item->GetUserAgentType());
-  if (pending_item->GetUserAgentType() == UserAgentType::NONE)
+  // pages or UserAgentType::MOBILE or UserAgentType::DESKTOP for non-native
+  // pages.  If the pending item's URL is non-native, check which user agent
+  // type it should be created with based on |user_agent_override_option|.
+  if (pending_item->GetUserAgentForInheritance() == UserAgentType::NONE)
     return;
 
   switch (user_agent_override_option) {
     case UserAgentOverrideOption::DESKTOP:
-      pending_item->SetUserAgentType(UserAgentType::DESKTOP,
-                                     /*update_inherited_user_agent =*/true);
+      pending_item->SetUserAgentType(UserAgentType::DESKTOP);
       break;
     case UserAgentOverrideOption::MOBILE:
-      pending_item->SetUserAgentType(UserAgentType::MOBILE,
-                                     /*update_inherited_user_agent =*/true);
+      pending_item->SetUserAgentType(UserAgentType::MOBILE);
       break;
     case UserAgentOverrideOption::INHERIT: {
       // Propagate the last committed non-native item's UserAgentType if there
       // is one, otherwise keep the default value, which is mobile.
       DCHECK(!inherit_from_item ||
-             inherit_from_item->GetUserAgentType() != UserAgentType::NONE);
+             inherit_from_item->GetUserAgentForInheritance() !=
+                 UserAgentType::NONE);
       if (inherit_from_item) {
         pending_item->SetUserAgentType(
-            inherit_from_item->GetUserAgentForInheritance(),
-            /*update_inherited_user_agent =*/true);
+            inherit_from_item->GetUserAgentForInheritance());
       }
       break;
     }
@@ -502,7 +499,7 @@
        index >= 0; index--) {
     NavigationItem* item = GetItemAtIndex(index);
     if (wk_navigation_util::URLNeedsUserAgentType(item->GetURL())) {
-      DCHECK_NE(item->GetUserAgentType(), UserAgentType::NONE);
+      DCHECK_NE(item->GetUserAgentForInheritance(), UserAgentType::NONE);
       return item;
     }
   }
diff --git a/ios/web/navigation/navigation_manager_impl_unittest.mm b/ios/web/navigation/navigation_manager_impl_unittest.mm
index ba81875..9da4da0a 100644
--- a/ios/web/navigation/navigation_manager_impl_unittest.mm
+++ b/ios/web/navigation/navigation_manager_impl_unittest.mm
@@ -107,7 +107,6 @@
 struct ItemInfoToBeRestored {
   GURL url;
   UserAgentType user_agent;
-  bool user_agent_inherited;
   PageDisplayState display_state;
 };
 
@@ -650,7 +649,10 @@
       navigation_manager()->GetPendingItem()->GetTransitionType(),
       ui::PAGE_TRANSITION_TYPED));
   EXPECT_EQ(web::UserAgentType::MOBILE,
-            navigation_manager()->GetPendingItem()->GetUserAgentType());
+            navigation_manager()->GetPendingItem()->GetUserAgentType(nil));
+  EXPECT_EQ(
+      web::UserAgentType::MOBILE,
+      navigation_manager()->GetPendingItem()->GetUserAgentForInheritance());
   EXPECT_EQ(0, navigation_manager()->GetItemCount());
 
   navigation_manager()->AddPendingItem(
@@ -678,7 +680,10 @@
       navigation_manager()->GetPendingItem()->GetTransitionType(),
       ui::PAGE_TRANSITION_TYPED));
   EXPECT_EQ(web::UserAgentType::DESKTOP,
-            navigation_manager()->GetPendingItem()->GetUserAgentType());
+            navigation_manager()->GetPendingItem()->GetUserAgentType(nil));
+  EXPECT_EQ(
+      web::UserAgentType::DESKTOP,
+      navigation_manager()->GetPendingItem()->GetUserAgentForInheritance());
   EXPECT_EQ(0, navigation_manager()->GetItemCount());
 
   navigation_manager()->AddPendingItem(
@@ -832,8 +837,12 @@
   EXPECT_TRUE(ui::PageTransitionCoreTypeIs(
       navigation_manager()->GetLastCommittedItem()->GetTransitionType(),
       ui::PAGE_TRANSITION_TYPED));
-  EXPECT_EQ(web::UserAgentType::MOBILE,
-            navigation_manager()->GetLastCommittedItem()->GetUserAgentType());
+  EXPECT_EQ(
+      web::UserAgentType::MOBILE,
+      navigation_manager()->GetLastCommittedItem()->GetUserAgentType(nil));
+  EXPECT_EQ(web::UserAgentType::MOBILE, navigation_manager()
+                                            ->GetLastCommittedItem()
+                                            ->GetUserAgentForInheritance());
   EXPECT_EQ(1, navigation_manager()->GetItemCount());
 
   navigation_manager()->AddPendingItem(
@@ -864,8 +873,12 @@
   EXPECT_TRUE(ui::PageTransitionCoreTypeIs(
       navigation_manager()->GetLastCommittedItem()->GetTransitionType(),
       ui::PAGE_TRANSITION_TYPED));
-  EXPECT_EQ(web::UserAgentType::DESKTOP,
-            navigation_manager()->GetLastCommittedItem()->GetUserAgentType());
+  EXPECT_EQ(
+      web::UserAgentType::DESKTOP,
+      navigation_manager()->GetLastCommittedItem()->GetUserAgentType(nil));
+  EXPECT_EQ(web::UserAgentType::DESKTOP, navigation_manager()
+                                             ->GetLastCommittedItem()
+                                             ->GetUserAgentForInheritance());
   EXPECT_EQ(1, navigation_manager()->GetItemCount());
 
   navigation_manager()->AddPendingItem(
@@ -892,7 +905,9 @@
 
   NavigationItem* last_committed_item =
       navigation_manager()->GetLastCommittedItem();
-  EXPECT_EQ(UserAgentType::MOBILE, last_committed_item->GetUserAgentType());
+  EXPECT_EQ(UserAgentType::MOBILE, last_committed_item->GetUserAgentType(nil));
+  EXPECT_EQ(UserAgentType::MOBILE,
+            last_committed_item->GetUserAgentForInheritance());
   EXPECT_EQ(1, navigation_manager()->GetItemCount());
 
   navigation_manager()->AddPendingItem(
@@ -901,7 +916,10 @@
       web::NavigationManager::UserAgentOverrideOption::DESKTOP);
   ASSERT_TRUE(navigation_manager()->GetPendingItem());
   EXPECT_EQ(UserAgentType::DESKTOP,
-            navigation_manager()->GetPendingItem()->GetUserAgentType());
+            navigation_manager()->GetPendingItem()->GetUserAgentType(nil));
+  EXPECT_EQ(
+      UserAgentType::DESKTOP,
+      navigation_manager()->GetPendingItem()->GetUserAgentForInheritance());
   EXPECT_EQ(1, navigation_manager()->GetItemCount());
 }
 
@@ -918,9 +936,10 @@
 
   NavigationItem* last_committed_item =
       navigation_manager()->GetLastCommittedItem();
-  last_committed_item->SetUserAgentType(UserAgentType::DESKTOP,
-                                        /*update_inherited_user_agent =*/true);
-  EXPECT_EQ(UserAgentType::DESKTOP, last_committed_item->GetUserAgentType());
+  last_committed_item->SetUserAgentType(UserAgentType::DESKTOP);
+  EXPECT_EQ(UserAgentType::DESKTOP, last_committed_item->GetUserAgentType(nil));
+  EXPECT_EQ(UserAgentType::DESKTOP,
+            last_committed_item->GetUserAgentForInheritance());
 
   navigation_manager()->AddPendingItem(
       GURL("http://www.2.com"), Referrer(), ui::PAGE_TRANSITION_TYPED,
@@ -928,7 +947,10 @@
       web::NavigationManager::UserAgentOverrideOption::MOBILE);
   ASSERT_TRUE(navigation_manager()->GetPendingItem());
   EXPECT_EQ(UserAgentType::MOBILE,
-            navigation_manager()->GetPendingItem()->GetUserAgentType());
+            navigation_manager()->GetPendingItem()->GetUserAgentType(nil));
+  EXPECT_EQ(
+      UserAgentType::MOBILE,
+      navigation_manager()->GetPendingItem()->GetUserAgentForInheritance());
 }
 
 // Tests that the UserAgentType of an INHERIT item is propagated to subsequent
@@ -943,8 +965,9 @@
   navigation_manager()->CommitPendingItem();
 
   ASSERT_TRUE(navigation_manager()->GetLastCommittedItem());
-  EXPECT_EQ(web::UserAgentType::MOBILE,
-            navigation_manager()->GetLastCommittedItem()->GetUserAgentType());
+  EXPECT_EQ(web::UserAgentType::MOBILE, navigation_manager()
+                                            ->GetLastCommittedItem()
+                                            ->GetUserAgentForInheritance());
 
   navigation_manager()->AddPendingItem(
       GURL("http://www.2.com"), Referrer(), ui::PAGE_TRANSITION_TYPED,
@@ -957,8 +980,9 @@
   navigation_manager()->CommitPendingItem();
 
   ASSERT_TRUE(navigation_manager()->GetLastCommittedItem());
-  EXPECT_EQ(web::UserAgentType::MOBILE,
-            navigation_manager()->GetLastCommittedItem()->GetUserAgentType());
+  EXPECT_EQ(web::UserAgentType::MOBILE, navigation_manager()
+                                            ->GetLastCommittedItem()
+                                            ->GetUserAgentForInheritance());
 }
 
 // Tests that the UserAgentType of a MOBILE item is propagated to subsequent
@@ -973,8 +997,12 @@
   navigation_manager()->CommitPendingItem();
 
   ASSERT_TRUE(navigation_manager()->GetLastCommittedItem());
-  EXPECT_EQ(web::UserAgentType::MOBILE,
-            navigation_manager()->GetLastCommittedItem()->GetUserAgentType());
+  EXPECT_EQ(
+      web::UserAgentType::MOBILE,
+      navigation_manager()->GetLastCommittedItem()->GetUserAgentType(nil));
+  EXPECT_EQ(web::UserAgentType::MOBILE, navigation_manager()
+                                            ->GetLastCommittedItem()
+                                            ->GetUserAgentForInheritance());
 
   navigation_manager()->AddPendingItem(
       GURL("http://www.2.com"), Referrer(), ui::PAGE_TRANSITION_TYPED,
@@ -987,8 +1015,12 @@
   navigation_manager()->CommitPendingItem();
 
   ASSERT_TRUE(navigation_manager()->GetLastCommittedItem());
-  EXPECT_EQ(web::UserAgentType::MOBILE,
-            navigation_manager()->GetLastCommittedItem()->GetUserAgentType());
+  EXPECT_EQ(
+      web::UserAgentType::MOBILE,
+      navigation_manager()->GetLastCommittedItem()->GetUserAgentType(nil));
+  EXPECT_EQ(web::UserAgentType::MOBILE, navigation_manager()
+                                            ->GetLastCommittedItem()
+                                            ->GetUserAgentForInheritance());
 }
 
 // Tests that the UserAgentType of a DESKTOP item is propagated to subsequent
@@ -1003,8 +1035,12 @@
   navigation_manager()->CommitPendingItem();
 
   ASSERT_TRUE(navigation_manager()->GetLastCommittedItem());
-  EXPECT_EQ(web::UserAgentType::DESKTOP,
-            navigation_manager()->GetLastCommittedItem()->GetUserAgentType());
+  EXPECT_EQ(
+      web::UserAgentType::DESKTOP,
+      navigation_manager()->GetLastCommittedItem()->GetUserAgentType(nil));
+  EXPECT_EQ(web::UserAgentType::DESKTOP, navigation_manager()
+                                             ->GetLastCommittedItem()
+                                             ->GetUserAgentForInheritance());
 
   navigation_manager()->AddPendingItem(
       GURL("http://www.2.com"), Referrer(), ui::PAGE_TRANSITION_TYPED,
@@ -1017,8 +1053,12 @@
   navigation_manager()->CommitPendingItem();
 
   ASSERT_TRUE(navigation_manager()->GetLastCommittedItem());
-  EXPECT_EQ(web::UserAgentType::DESKTOP,
-            navigation_manager()->GetLastCommittedItem()->GetUserAgentType());
+  EXPECT_EQ(
+      web::UserAgentType::DESKTOP,
+      navigation_manager()->GetLastCommittedItem()->GetUserAgentType(nil));
+  EXPECT_EQ(web::UserAgentType::DESKTOP, navigation_manager()
+                                             ->GetLastCommittedItem()
+                                             ->GetUserAgentForInheritance());
 }
 
 // Tests that the UserAgentType is propagated to subsequent NavigationItems if
@@ -1044,7 +1084,7 @@
   navigation_manager()->CommitPendingItem();
 
   NavigationItem* item1 = navigation_manager()->GetLastCommittedItem();
-  ASSERT_EQ(web::UserAgentType::MOBILE, item1->GetUserAgentType());
+  ASSERT_EQ(web::UserAgentType::MOBILE, item1->GetUserAgentType(nil));
 
   GURL item2_url =
       item1->GetURL().ReplaceComponents(app_specific_scheme_replacement);
@@ -1063,7 +1103,7 @@
   // Having a non-app-specific URL should not change the fact that the native
   // item should be skipped when determining user agent inheritance.
   native_item1->SetVirtualURL(GURL("http://non-app-specific-url"));
-  ASSERT_EQ(web::UserAgentType::NONE, native_item1->GetUserAgentType());
+  ASSERT_EQ(web::UserAgentType::NONE, native_item1->GetUserAgentType(nil));
   navigation_manager()->AddPendingItem(
       GURL("http://www.2.com"), Referrer(), ui::PAGE_TRANSITION_TYPED,
       web::NavigationInitiationType::BROWSER_INITIATED,
@@ -1077,13 +1117,12 @@
   NavigationItem* item2 = navigation_manager()->GetLastCommittedItem();
 
   // Verify that |item1|'s UserAgentType is propagated to |item2|.
-  EXPECT_EQ(item1->GetUserAgentType(), item2->GetUserAgentType());
+  EXPECT_EQ(item1->GetUserAgentType(nil), item2->GetUserAgentType(nil));
 
   // Update |item2|'s UA type to DESKTOP and add a third non-native navigation,
   // once again separated by a native one.
-  item2->SetUserAgentType(web::UserAgentType::DESKTOP,
-                          /*update_inherited_user_agent =*/true);
-  ASSERT_EQ(web::UserAgentType::DESKTOP, item2->GetUserAgentType());
+  item2->SetUserAgentType(web::UserAgentType::DESKTOP);
+  ASSERT_EQ(web::UserAgentType::DESKTOP, item2->GetUserAgentType(nil));
 
   GURL item3_url =
       item2->GetURL().ReplaceComponents(app_specific_scheme_replacement);
@@ -1099,7 +1138,8 @@
   navigation_manager()->CommitPendingItem();
 
   NavigationItem* native_item2 = navigation_manager()->GetLastCommittedItem();
-  ASSERT_EQ(web::UserAgentType::NONE, native_item2->GetUserAgentType());
+  ASSERT_EQ(web::UserAgentType::NONE,
+            native_item2->GetUserAgentForInheritance());
   navigation_manager()->AddPendingItem(
       GURL("http://www.3.com"), Referrer(), ui::PAGE_TRANSITION_TYPED,
       web::NavigationInitiationType::BROWSER_INITIATED,
@@ -1115,12 +1155,12 @@
   NavigationItem* item3 = navigation_manager()->GetLastCommittedItem();
 
   // Verify that |item2|'s UserAgentType is propagated to |item3|.
-  EXPECT_EQ(item2->GetUserAgentType(), item3->GetUserAgentType());
+  EXPECT_EQ(item2->GetUserAgentForInheritance(),
+            item3->GetUserAgentForInheritance());
 }
 
 // Tests that adding transient item for a pending item with mobile user agent
-// type results in a transient item with mobile user agent type when the type is
-// forcing the inheritance.
+// type results in a transient item with mobile user agent type.
 TEST_F(NavigationManagerTest, AddTransientItemForMobilePendingItem) {
   navigation_manager()->AddPendingItem(
       GURL("http://www.url.com"), Referrer(), ui::PAGE_TRANSITION_TYPED,
@@ -1128,29 +1168,20 @@
       web::NavigationManager::UserAgentOverrideOption::INHERIT);
   ASSERT_TRUE(navigation_manager()->GetPendingItem());
   navigation_manager()->GetPendingItem()->SetUserAgentType(
-      UserAgentType::MOBILE, /*update_inherited_user_agent =*/true);
+      UserAgentType::MOBILE);
 
   navigation_manager()->AddTransientItem(GURL("http://www.url.com"));
   ASSERT_TRUE(navigation_manager()->GetTransientItem());
-  EXPECT_EQ(UserAgentType::MOBILE,
-            navigation_manager()->GetTransientItem()->GetUserAgentType());
-  EXPECT_EQ(UserAgentType::MOBILE,
-            navigation_manager()->GetPendingItem()->GetUserAgentType());
-
-  // Don't update the inherited user agent.
-  navigation_manager()->GetPendingItem()->SetUserAgentType(
-      UserAgentType::DESKTOP, /*update_inherited_user_agent =*/false);
-  navigation_manager()->AddTransientItem(GURL("http://www.url2.com"));
-  ASSERT_TRUE(navigation_manager()->GetTransientItem());
-  EXPECT_EQ(UserAgentType::MOBILE,
-            navigation_manager()->GetTransientItem()->GetUserAgentType());
-  EXPECT_EQ(UserAgentType::DESKTOP,
-            navigation_manager()->GetPendingItem()->GetUserAgentType());
+  EXPECT_EQ(
+      UserAgentType::MOBILE,
+      navigation_manager()->GetTransientItem()->GetUserAgentForInheritance());
+  EXPECT_EQ(
+      UserAgentType::MOBILE,
+      navigation_manager()->GetPendingItem()->GetUserAgentForInheritance());
 }
 
 // Tests that adding transient item for a pending item with desktop user agent
-// type results in a transient item with desktop user agent type when the type
-// is forcing the inheritance.
+// type results in a transient item with desktop user agent type.
 TEST_F(NavigationManagerTest, AddTransientItemForDesktopPendingItem) {
   navigation_manager()->AddPendingItem(
       GURL("http://www.url.com"), Referrer(), ui::PAGE_TRANSITION_TYPED,
@@ -1158,24 +1189,16 @@
       web::NavigationManager::UserAgentOverrideOption::INHERIT);
   ASSERT_TRUE(navigation_manager()->GetPendingItem());
   navigation_manager()->GetPendingItem()->SetUserAgentType(
-      UserAgentType::DESKTOP, /*update_inherited_user_agent =*/true);
+      UserAgentType::DESKTOP);
 
   navigation_manager()->AddTransientItem(GURL("http://www.url.com"));
   ASSERT_TRUE(navigation_manager()->GetTransientItem());
-  EXPECT_EQ(UserAgentType::DESKTOP,
-            navigation_manager()->GetTransientItem()->GetUserAgentType());
-  EXPECT_EQ(UserAgentType::DESKTOP,
-            navigation_manager()->GetPendingItem()->GetUserAgentType());
-
-  // Don't update the inherited user agent.
-  navigation_manager()->GetPendingItem()->SetUserAgentType(
-      UserAgentType::MOBILE, /*update_inherited_user_agent =*/false);
-  navigation_manager()->AddTransientItem(GURL("http://www.url2.com"));
-  ASSERT_TRUE(navigation_manager()->GetTransientItem());
-  EXPECT_EQ(UserAgentType::DESKTOP,
-            navigation_manager()->GetTransientItem()->GetUserAgentType());
-  EXPECT_EQ(UserAgentType::MOBILE,
-            navigation_manager()->GetPendingItem()->GetUserAgentType());
+  EXPECT_EQ(
+      UserAgentType::DESKTOP,
+      navigation_manager()->GetTransientItem()->GetUserAgentForInheritance());
+  EXPECT_EQ(
+      UserAgentType::DESKTOP,
+      navigation_manager()->GetPendingItem()->GetUserAgentForInheritance());
 }
 
 // Tests that calling |Reload| with web::ReloadType::NORMAL is no-op when there
@@ -1481,7 +1504,8 @@
       navigation_manager()->GetPendingItemInCurrentOrRestoredSession();
   EXPECT_EQ(url, pending_item->GetURL());
   EXPECT_EQ(virtual_url, pending_item->GetVirtualURL());
-  EXPECT_EQ(UserAgentType::DESKTOP, pending_item->GetUserAgentType());
+  EXPECT_EQ(UserAgentType::DESKTOP, pending_item->GetUserAgentType(nil));
+  EXPECT_EQ(UserAgentType::DESKTOP, pending_item->GetUserAgentForInheritance());
 }
 
 // Tests that ReloadWithUserAgentType reloads on the last committed item before
@@ -1510,7 +1534,8 @@
   NavigationItem* pending_item =
       navigation_manager()->GetPendingItemInCurrentOrRestoredSession();
   EXPECT_EQ(url, pending_item->GetURL());
-  EXPECT_EQ(UserAgentType::DESKTOP, pending_item->GetUserAgentType());
+  EXPECT_EQ(UserAgentType::DESKTOP, pending_item->GetUserAgentType(nil));
+  EXPECT_EQ(UserAgentType::DESKTOP, pending_item->GetUserAgentForInheritance());
 }
 
 // Tests that ReloadWithUserAgentType reloads on the last committed item if
@@ -1530,7 +1555,8 @@
   NavigationItem* pending_item =
       navigation_manager()->GetPendingItemInCurrentOrRestoredSession();
   EXPECT_EQ(url, pending_item->GetURL());
-  EXPECT_EQ(UserAgentType::DESKTOP, pending_item->GetUserAgentType());
+  EXPECT_EQ(UserAgentType::DESKTOP, pending_item->GetUserAgentType(nil));
+  EXPECT_EQ(UserAgentType::DESKTOP, pending_item->GetUserAgentForInheritance());
 }
 
 // Tests that ReloadWithUserAgentType does not expose internal URLs.
@@ -1556,7 +1582,8 @@
       navigation_manager()->GetPendingItemInCurrentOrRestoredSession();
   EXPECT_EQ(url, pending_item->GetURL());
   EXPECT_EQ(virtual_url, pending_item->GetVirtualURL());
-  EXPECT_EQ(UserAgentType::DESKTOP, pending_item->GetUserAgentType());
+  EXPECT_EQ(UserAgentType::DESKTOP, pending_item->GetUserAgentType(nil));
+  EXPECT_EQ(UserAgentType::DESKTOP, pending_item->GetUserAgentForInheritance());
 }
 
 // Tests that app-specific URLs are not rewritten for renderer-initiated loads
@@ -1728,19 +1755,17 @@
 TEST_F(NavigationManagerTest, Restore) {
   ItemInfoToBeRestored restore_information[3];
   restore_information[0] = {GURL("http://www.url.com/0"), UserAgentType::MOBILE,
-                            true, PageDisplayState()};
+                            PageDisplayState()};
   restore_information[1] = {GURL("http://www.url.com/1"),
-                            UserAgentType::DESKTOP, true, PageDisplayState()};
+                            UserAgentType::AUTOMATIC, PageDisplayState()};
   restore_information[2] = {GURL("http://www.url.com/2"),
-                            UserAgentType::DESKTOP, false, PageDisplayState()};
+                            UserAgentType::DESKTOP, PageDisplayState()};
 
   std::vector<std::unique_ptr<NavigationItem>> items;
   for (size_t index = 0; index < base::size(restore_information); ++index) {
     items.push_back(NavigationItem::Create());
     items.back()->SetURL(restore_information[index].url);
-    items.back()->SetUserAgentType(
-        restore_information[index].user_agent,
-        restore_information[index].user_agent_inherited);
+    items.back()->SetUserAgentType(restore_information[index].user_agent);
     items.back()->SetPageDisplayState(restore_information[index].display_state);
   }
 
@@ -1790,20 +1815,7 @@
     NavigationItem* navigation_item = navigation_manager()->GetItemAtIndex(i);
     EXPECT_EQ(restore_information[i].url, navigation_item->GetURL());
     EXPECT_EQ(restore_information[i].user_agent,
-              navigation_item->GetUserAgentType());
-    if (restore_information[i].user_agent_inherited) {
-      EXPECT_EQ(restore_information[i].user_agent,
-                navigation_item->GetUserAgentForInheritance());
-    } else {
-      if (base::FeatureList::IsEnabled(
-              features::kUseDefaultUserAgentInWebClient)) {
-        EXPECT_EQ(UserAgentType::AUTOMATIC,
-                  navigation_item->GetUserAgentForInheritance());
-      } else {
-        EXPECT_EQ(UserAgentType::MOBILE,
-                  navigation_item->GetUserAgentForInheritance());
-      }
-    }
+              navigation_item->GetUserAgentForInheritance());
     EXPECT_EQ(restore_information[i].display_state,
               navigation_item->GetPageDisplayState());
   }
diff --git a/ios/web/navigation/wk_based_navigation_manager_impl.mm b/ios/web/navigation/wk_based_navigation_manager_impl.mm
index bc9f5e54..955313d 100644
--- a/ios/web/navigation/wk_based_navigation_manager_impl.mm
+++ b/ios/web/navigation/wk_based_navigation_manager_impl.mm
@@ -145,9 +145,8 @@
   // Item may still be null in captive portal case if chrome://newtab is the
   // only entry in back/forward history.
   if (item) {
-    DCHECK(item->GetUserAgentType() != UserAgentType::NONE);
-    transient_item_->SetUserAgentType(item->GetUserAgentForInheritance(),
-                                      /*update_inherited_user_agent =*/true);
+    DCHECK(item->GetUserAgentForInheritance() != UserAgentType::NONE);
+    transient_item_->SetUserAgentType(item->GetUserAgentForInheritance());
   }
 }
 
@@ -234,11 +233,9 @@
       SetNavigationItemInWKItem(current_wk_item, std::move(pending_item_));
     }
     if (user_agent_override_option == UserAgentOverrideOption::DESKTOP) {
-      current_item->SetUserAgentType(UserAgentType::DESKTOP,
-                                     /*update_inherited_user_agent =*/true);
+      current_item->SetUserAgentType(UserAgentType::DESKTOP);
     } else if (user_agent_override_option == UserAgentOverrideOption::MOBILE) {
-      current_item->SetUserAgentType(UserAgentType::MOBILE,
-                                     /*update_inherited_user_agent =*/true);
+      current_item->SetUserAgentType(UserAgentType::MOBILE);
     }
 
     pending_item_.reset();
@@ -891,8 +888,7 @@
     }
     if (current_committed_item) {
       last_committed_item->SetUserAgentType(
-          current_committed_item->GetUserAgentForInheritance(),
-          /*update_inherited_user_agent =*/true);
+          current_committed_item->GetUserAgentForInheritance());
     }
   }
   if (last_committed_item && GetWebState() &&
diff --git a/ios/web/navigation/wk_based_navigation_manager_impl_unittest.mm b/ios/web/navigation/wk_based_navigation_manager_impl_unittest.mm
index ec28972..1787900e 100644
--- a/ios/web/navigation/wk_based_navigation_manager_impl_unittest.mm
+++ b/ios/web/navigation/wk_based_navigation_manager_impl_unittest.mm
@@ -147,7 +147,7 @@
   EXPECT_EQ(GURL("http://www.0.com"), item->GetURL());
   EXPECT_TRUE(ui::PageTransitionCoreTypeIs(ui::PAGE_TRANSITION_LINK,
                                            item->GetTransitionType()));
-  EXPECT_EQ(UserAgentType::MOBILE, item->GetUserAgentType());
+  EXPECT_EQ(UserAgentType::MOBILE, item->GetUserAgentForInheritance());
   EXPECT_FALSE(item->GetTimestamp().is_null());
 }
 
@@ -166,7 +166,7 @@
   EXPECT_EQ(GURL("http://www.2.com"), item2->GetURL());
   EXPECT_TRUE(ui::PageTransitionCoreTypeIs(ui::PAGE_TRANSITION_LINK,
                                            item2->GetTransitionType()));
-  EXPECT_EQ(UserAgentType::MOBILE, item2->GetUserAgentType());
+  EXPECT_EQ(UserAgentType::MOBILE, item2->GetUserAgentForInheritance());
   EXPECT_EQ(GURL("http://www.1.com"), item2->GetReferrer().url);
   EXPECT_FALSE(item2->GetTimestamp().is_null());
 
@@ -175,7 +175,7 @@
   EXPECT_EQ(GURL("http://www.1.com"), item1->GetURL());
   EXPECT_TRUE(ui::PageTransitionCoreTypeIs(ui::PAGE_TRANSITION_LINK,
                                            item1->GetTransitionType()));
-  EXPECT_EQ(UserAgentType::MOBILE, item1->GetUserAgentType());
+  EXPECT_EQ(UserAgentType::MOBILE, item1->GetUserAgentForInheritance());
   EXPECT_EQ(GURL("http://www.0.com"), item1->GetReferrer().url);
   EXPECT_FALSE(item1->GetTimestamp().is_null());
 
@@ -184,7 +184,7 @@
   EXPECT_EQ(GURL("http://www.0.com"), item0->GetURL());
   EXPECT_TRUE(ui::PageTransitionCoreTypeIs(ui::PAGE_TRANSITION_LINK,
                                            item0->GetTransitionType()));
-  EXPECT_EQ(UserAgentType::MOBILE, item0->GetUserAgentType());
+  EXPECT_EQ(UserAgentType::MOBILE, item0->GetUserAgentForInheritance());
   EXPECT_FALSE(item0->GetTimestamp().is_null());
 }
 
@@ -210,12 +210,13 @@
   [mock_wk_list_ setCurrentURL:@"http://www.1.com"
                   backListURLs:@[ @"http://www.0.com" ]
                forwardListURLs:nil];
-  manager_->GetItemAtIndex(0)->SetUserAgentType(UserAgentType::DESKTOP, true);
+  manager_->GetItemAtIndex(0)->SetUserAgentType(UserAgentType::DESKTOP);
 
   NavigationItem* item = manager_->GetLastCommittedItem();
   ASSERT_NE(item, nullptr);
   EXPECT_EQ("http://www.1.com/", item->GetURL().spec());
-  EXPECT_EQ(UserAgentType::DESKTOP, item->GetUserAgentType());
+  EXPECT_EQ(UserAgentType::DESKTOP, item->GetUserAgentType(nil));
+  EXPECT_EQ(UserAgentType::DESKTOP, item->GetUserAgentForInheritance());
 }
 
 // Tests that GetLastCommittedItem() creates a default NavigationItem when the
@@ -260,7 +261,8 @@
   EXPECT_EQ(GURL("http://www.0.com"), item->GetURL());
   EXPECT_TRUE(ui::PageTransitionCoreTypeIs(ui::PAGE_TRANSITION_TYPED,
                                            item->GetTransitionType()));
-  EXPECT_EQ(UserAgentType::DESKTOP, item->GetUserAgentType());
+  EXPECT_EQ(UserAgentType::DESKTOP, item->GetUserAgentType(nil));
+  EXPECT_EQ(UserAgentType::DESKTOP, item->GetUserAgentForInheritance());
 
   // Simulate a second main frame navigation.
   manager_->AddPendingItem(
@@ -283,7 +285,7 @@
   EXPECT_EQ(GURL("http://www.1.com"), item1->GetURL());
   EXPECT_TRUE(ui::PageTransitionCoreTypeIs(ui::PAGE_TRANSITION_LINK,
                                            item1->GetTransitionType()));
-  EXPECT_EQ(UserAgentType::MOBILE, item1->GetUserAgentType());
+  EXPECT_EQ(UserAgentType::MOBILE, item1->GetUserAgentForInheritance());
   EXPECT_EQ(GURL("http://www.0.com"), item1->GetReferrer().url);
 
   // This item is created by CommitPendingItem.
@@ -292,7 +294,8 @@
   EXPECT_EQ(GURL("http://www.2.com"), item2->GetURL());
   EXPECT_TRUE(ui::PageTransitionCoreTypeIs(ui::PAGE_TRANSITION_TYPED,
                                            item2->GetTransitionType()));
-  EXPECT_EQ(UserAgentType::DESKTOP, item2->GetUserAgentType());
+  EXPECT_EQ(UserAgentType::DESKTOP, item2->GetUserAgentType(nil));
+  EXPECT_EQ(UserAgentType::DESKTOP, item2->GetUserAgentForInheritance());
   EXPECT_EQ(GURL(""), item2->GetReferrer().url);
 }
 
diff --git a/ios/web/public/navigation/navigation_item.h b/ios/web/public/navigation/navigation_item.h
index 03e9ff8..271ef2f 100644
--- a/ios/web/public/navigation/navigation_item.h
+++ b/ios/web/public/navigation/navigation_item.h
@@ -110,14 +110,10 @@
   virtual base::Time GetTimestamp() const = 0;
 
   // The type of user agent requested for the navigation.
-  // If |update_inherited_user_agent| is false, then the user agent type used
-  // for inheritance won't be changed. If it is true, the the user agent for
-  // inheritance will be updated to |type|.
-  // See NavigationManager UserAgentOverrideOption::INHERIT.
   // TODO(crbug.com/697512): Create equivalent enum type for WebContents.
-  virtual void SetUserAgentType(UserAgentType type,
-                                bool update_inherited_user_agent) = 0;
-  virtual UserAgentType GetUserAgentType() const = 0;
+  virtual void SetUserAgentType(UserAgentType type) = 0;
+  virtual UserAgentType GetUserAgentType(
+      id<UITraitEnvironment> web_view) const = 0;
 
   // Returns the type of user agent to be used for inheritance. Inheritance is
   // used to know the User Agent type when a new navigation is started. This
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 589e8eda..d902299 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -1402,7 +1402,7 @@
           : web::UserAgentType::MOBILE;
   web::NavigationItem* item = self.currentNavItem;
   web::UserAgentType userAgentType =
-      item ? item->GetUserAgentType() : defaultUserAgent;
+      item ? item->GetUserAgentType(_containerView) : defaultUserAgent;
   if (userAgentType == web::UserAgentType::AUTOMATIC) {
     userAgentType =
         web::GetWebClient()->GetDefaultUserAgent(_containerView, GURL());
diff --git a/ios/web/web_state/ui/crw_web_request_controller.mm b/ios/web/web_state/ui/crw_web_request_controller.mm
index 8622250..11649ff 100644
--- a/ios/web/web_state/ui/crw_web_request_controller.mm
+++ b/ios/web/web_state/ui/crw_web_request_controller.mm
@@ -556,18 +556,11 @@
   // in the web view, update |customUserAgent| property, which will be used by
   // the next request sent by this web view.
   web::UserAgentType itemUserAgentType =
-      self.currentNavItem->GetUserAgentType();
+      self.currentNavItem->GetUserAgentType(self.webView);
 
-  if (itemUserAgentType == web::UserAgentType::AUTOMATIC) {
-    DCHECK(base::FeatureList::IsEnabled(
-        web::features::kUseDefaultUserAgentInWebClient));
-    itemUserAgentType = web::GetWebClient()->GetDefaultUserAgent(
-        self.webView, self.currentNavItem->GetURL());
-    self.currentNavItem->SetUserAgentType(
-        itemUserAgentType, /*update_inherited_user_agent =*/false);
-  } else if (itemUserAgentType == web::UserAgentType::NONE &&
-             web::GetWebClient()->IsAppSpecificURL(
-                 self.currentNavItem->GetVirtualURL())) {
+  if (itemUserAgentType == web::UserAgentType::NONE &&
+      web::GetWebClient()->IsAppSpecificURL(
+          self.currentNavItem->GetVirtualURL())) {
     // In case the URL to be loaded is a WebUI URL and the user agent is nil,
     // get the mobile user agent.
     itemUserAgentType = web::UserAgentType::MOBILE;
diff --git a/ios/web_view/BUILD.gn b/ios/web_view/BUILD.gn
index 9bc2f49..355a6f35a 100644
--- a/ios/web_view/BUILD.gn
+++ b/ios/web_view/BUILD.gn
@@ -120,10 +120,6 @@
     "internal/autofill/web_view_personal_data_manager_factory.mm",
     "internal/autofill/web_view_strike_database_factory.h",
     "internal/autofill/web_view_strike_database_factory.mm",
-    "internal/content_settings/web_view_cookie_settings_factory.h",
-    "internal/content_settings/web_view_cookie_settings_factory.mm",
-    "internal/content_settings/web_view_host_content_settings_map_factory.h",
-    "internal/content_settings/web_view_host_content_settings_map_factory.mm",
     "internal/cwv_back_forward_list.mm",
     "internal/cwv_back_forward_list_internal.h",
     "internal/cwv_back_forward_list_item.mm",
@@ -184,6 +180,8 @@
     "internal/signin/ios_web_view_signin_client.mm",
     "internal/signin/web_view_device_accounts_provider_impl.h",
     "internal/signin/web_view_device_accounts_provider_impl.mm",
+    "internal/signin/web_view_gaia_auth_fetcher.h",
+    "internal/signin/web_view_gaia_auth_fetcher.mm",
     "internal/signin/web_view_identity_manager_factory.h",
     "internal/signin/web_view_identity_manager_factory.mm",
     "internal/signin/web_view_signin_client_factory.h",
@@ -254,7 +252,6 @@
     "//components/autofill/ios/browser",
     "//components/autofill/ios/form_util",
     "//components/browser_sync",
-    "//components/content_settings/core/browser",
     "//components/flags_ui",
     "//components/flags_ui:switches",
     "//components/gcm_driver",
@@ -277,7 +274,6 @@
     "//components/proxy_config",
     "//components/signin/core/browser",
     "//components/signin/ios/browser",
-    "//components/signin/ios/browser:active_state_manager",
     "//components/signin/public/identity_manager",
     "//components/signin/public/identity_manager/ios",
     "//components/signin/public/webdata",
@@ -409,6 +405,7 @@
     "internal/passwords/cwv_password_controller_fake.mm",
     "internal/passwords/cwv_password_unittest.mm",
     "internal/signin/cwv_identity_unittest.mm",
+    "internal/signin/web_view_gaia_auth_fetcher_unittest.mm",
     "internal/sync/cwv_sync_controller_unittest.mm",
     "internal/translate/cwv_translation_controller_unittest.mm",
     "internal/translate/cwv_translation_language_unittest.mm",
diff --git a/ios/web_view/internal/content_settings/web_view_cookie_settings_factory.h b/ios/web_view/internal/content_settings/web_view_cookie_settings_factory.h
deleted file mode 100644
index 0e45f55..0000000
--- a/ios/web_view/internal/content_settings/web_view_cookie_settings_factory.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_WEB_VIEW_INTERNAL_CONTENT_SETTINGS_WEB_VIEW_COOKIE_SETTINGS_FACTORY_H_
-#define IOS_WEB_VIEW_INTERNAL_CONTENT_SETTINGS_WEB_VIEW_COOKIE_SETTINGS_FACTORY_H_
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/no_destructor.h"
-#include "components/keyed_service/ios/refcounted_browser_state_keyed_service_factory.h"
-
-namespace content_settings {
-class CookieSettings;
-}
-
-namespace ios_web_view {
-
-class WebViewBrowserState;
-
-// Singleton that owns all CookieSettings and associates them with a
-// browser state.
-class WebViewCookieSettingsFactory
-    : public RefcountedBrowserStateKeyedServiceFactory {
- public:
-  static scoped_refptr<content_settings::CookieSettings> GetForBrowserState(
-      ios_web_view::WebViewBrowserState* browser_state);
-  static WebViewCookieSettingsFactory* GetInstance();
-
- private:
-  friend class base::NoDestructor<WebViewCookieSettingsFactory>;
-
-  WebViewCookieSettingsFactory();
-  ~WebViewCookieSettingsFactory() override;
-
-  // RefcountedBrowserStateKeyedServiceFactory implementation.
-  void RegisterBrowserStatePrefs(
-      user_prefs::PrefRegistrySyncable* registry) override;
-  web::BrowserState* GetBrowserStateToUse(
-      web::BrowserState* context) const override;
-  scoped_refptr<RefcountedKeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
-
-  DISALLOW_COPY_AND_ASSIGN(WebViewCookieSettingsFactory);
-};
-
-}  // namespace ios_web_view
-
-#endif  // IOS_WEB_VIEW_INTERNAL_CONTENT_SETTINGS_WEB_VIEW_COOKIE_SETTINGS_FACTORY_H_
diff --git a/ios/web_view/internal/content_settings/web_view_cookie_settings_factory.mm b/ios/web_view/internal/content_settings/web_view_cookie_settings_factory.mm
deleted file mode 100644
index b797176..0000000
--- a/ios/web_view/internal/content_settings/web_view_cookie_settings_factory.mm
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ios/web_view/internal/content_settings/web_view_cookie_settings_factory.h"
-
-#include "base/no_destructor.h"
-#include "components/content_settings/core/browser/cookie_settings.h"
-#include "components/keyed_service/ios/browser_state_dependency_manager.h"
-#include "ios/web_view/internal/content_settings/web_view_host_content_settings_map_factory.h"
-#include "ios/web_view/internal/web_view_browser_state.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace ios_web_view {
-
-// static
-scoped_refptr<content_settings::CookieSettings>
-WebViewCookieSettingsFactory::GetForBrowserState(
-    ios_web_view::WebViewBrowserState* browser_state) {
-  return static_cast<content_settings::CookieSettings*>(
-      GetInstance()->GetServiceForBrowserState(browser_state, true).get());
-}
-
-// static
-WebViewCookieSettingsFactory* WebViewCookieSettingsFactory::GetInstance() {
-  static base::NoDestructor<WebViewCookieSettingsFactory> instance;
-  return instance.get();
-}
-
-WebViewCookieSettingsFactory::WebViewCookieSettingsFactory()
-    : RefcountedBrowserStateKeyedServiceFactory(
-          "CookieSettings",
-          BrowserStateDependencyManager::GetInstance()) {}
-
-WebViewCookieSettingsFactory::~WebViewCookieSettingsFactory() {}
-
-void WebViewCookieSettingsFactory::RegisterBrowserStatePrefs(
-    user_prefs::PrefRegistrySyncable* registry) {
-  content_settings::CookieSettings::RegisterProfilePrefs(registry);
-}
-
-web::BrowserState* WebViewCookieSettingsFactory::GetBrowserStateToUse(
-    web::BrowserState* context) const {
-  return context;
-}
-
-scoped_refptr<RefcountedKeyedService>
-WebViewCookieSettingsFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
-  WebViewBrowserState* browser_state =
-      WebViewBrowserState::FromBrowserState(context);
-  return base::MakeRefCounted<content_settings::CookieSettings>(
-      WebViewHostContentSettingsMapFactory::GetForBrowserState(browser_state),
-      browser_state->GetPrefs(), browser_state->IsOffTheRecord());
-}
-
-}  // namespace ios_web_view
diff --git a/ios/web_view/internal/content_settings/web_view_host_content_settings_map_factory.h b/ios/web_view/internal/content_settings/web_view_host_content_settings_map_factory.h
deleted file mode 100644
index b9f49ce..0000000
--- a/ios/web_view/internal/content_settings/web_view_host_content_settings_map_factory.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_WEB_VIEW_INTERNAL_CONTENT_SETTINGS_WEB_VIEW_HOST_CONTENT_SETTINGS_MAP_FACTORY_H_
-#define IOS_WEB_VIEW_INTERNAL_CONTENT_SETTINGS_WEB_VIEW_HOST_CONTENT_SETTINGS_MAP_FACTORY_H_
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/no_destructor.h"
-#include "components/keyed_service/ios/refcounted_browser_state_keyed_service_factory.h"
-
-class HostContentSettingsMap;
-
-namespace ios_web_view {
-
-class WebViewBrowserState;
-
-// Singleton that owns all HostContentSettingsMaps and associates them with a
-// browser state.
-class WebViewHostContentSettingsMapFactory
-    : public RefcountedBrowserStateKeyedServiceFactory {
- public:
-  static HostContentSettingsMap* GetForBrowserState(
-      ios_web_view::WebViewBrowserState* browser_state);
-  static WebViewHostContentSettingsMapFactory* GetInstance();
-
- private:
-  friend class base::NoDestructor<WebViewHostContentSettingsMapFactory>;
-
-  WebViewHostContentSettingsMapFactory();
-  ~WebViewHostContentSettingsMapFactory() override;
-
-  // BrowserStateKeyedServiceFactory implementation.
-  scoped_refptr<RefcountedKeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
-  web::BrowserState* GetBrowserStateToUse(
-      web::BrowserState* context) const override;
-  void RegisterBrowserStatePrefs(
-      user_prefs::PrefRegistrySyncable* registry) override;
-
-  DISALLOW_COPY_AND_ASSIGN(WebViewHostContentSettingsMapFactory);
-};
-
-}  // namespace ios_web_view
-
-#endif  // IOS_WEB_VIEW_INTERNAL_CONTENT_SETTINGS_WEB_VIEW_HOST_CONTENT_SETTINGS_MAP_FACTORY_H_
diff --git a/ios/web_view/internal/content_settings/web_view_host_content_settings_map_factory.mm b/ios/web_view/internal/content_settings/web_view_host_content_settings_map_factory.mm
deleted file mode 100644
index 18c90c4c..0000000
--- a/ios/web_view/internal/content_settings/web_view_host_content_settings_map_factory.mm
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ios/web_view/internal/content_settings/web_view_host_content_settings_map_factory.h"
-
-#include "base/no_destructor.h"
-#include "components/content_settings/core/browser/host_content_settings_map.h"
-#include "components/keyed_service/ios/browser_state_dependency_manager.h"
-#include "components/prefs/pref_service.h"
-#include "ios/web_view/internal/web_view_browser_state.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace ios_web_view {
-
-// static
-HostContentSettingsMap*
-WebViewHostContentSettingsMapFactory::GetForBrowserState(
-    ios_web_view::WebViewBrowserState* browser_state) {
-  return static_cast<HostContentSettingsMap*>(
-      GetInstance()->GetServiceForBrowserState(browser_state, true).get());
-}
-
-// static
-WebViewHostContentSettingsMapFactory*
-WebViewHostContentSettingsMapFactory::GetInstance() {
-  static base::NoDestructor<WebViewHostContentSettingsMapFactory> instance;
-  return instance.get();
-}
-
-WebViewHostContentSettingsMapFactory::WebViewHostContentSettingsMapFactory()
-    : RefcountedBrowserStateKeyedServiceFactory(
-          "HostContentSettingsMap",
-          BrowserStateDependencyManager::GetInstance()) {}
-
-WebViewHostContentSettingsMapFactory::~WebViewHostContentSettingsMapFactory() {}
-
-void WebViewHostContentSettingsMapFactory::RegisterBrowserStatePrefs(
-    user_prefs::PrefRegistrySyncable* registry) {
-  HostContentSettingsMap::RegisterProfilePrefs(registry);
-}
-
-scoped_refptr<RefcountedKeyedService>
-WebViewHostContentSettingsMapFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
-  WebViewBrowserState* browser_state =
-      WebViewBrowserState::FromBrowserState(context);
-  return base::MakeRefCounted<HostContentSettingsMap>(
-      browser_state->GetPrefs(), browser_state->IsOffTheRecord(),
-      false /* store_last_modified */,
-      false /* migrate_requesting_and_top_level_origin_settings */);
-}
-
-web::BrowserState* WebViewHostContentSettingsMapFactory::GetBrowserStateToUse(
-    web::BrowserState* context) const {
-  return context;
-}
-
-}  // namespace ios_web_view
diff --git a/ios/web_view/internal/signin/ios_web_view_signin_client.h b/ios/web_view/internal/signin/ios_web_view_signin_client.h
index d6676df..0f4eeaa3 100644
--- a/ios/web_view/internal/signin/ios_web_view_signin_client.h
+++ b/ios/web_view/internal/signin/ios_web_view_signin_client.h
@@ -8,11 +8,8 @@
 #include <memory>
 
 #include "base/macros.h"
-#include "components/content_settings/core/browser/cookie_settings.h"
-#include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/signin/ios/browser/wait_for_network_callback_helper.h"
 #include "components/signin/public/base/signin_client.h"
-#include "net/cookies/cookie_change_dispatcher.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace ios_web_view {
@@ -22,11 +19,8 @@
 // iOS WebView specific signin client.
 class IOSWebViewSigninClient : public SigninClient {
  public:
-  IOSWebViewSigninClient(
-      PrefService* pref_service,
-      ios_web_view::WebViewBrowserState* browser_state,
-      scoped_refptr<content_settings::CookieSettings> cookie_settings,
-      scoped_refptr<HostContentSettingsMap> host_content_settings_map);
+  IOSWebViewSigninClient(PrefService* pref_service,
+                         ios_web_view::WebViewBrowserState* browser_state);
 
   ~IOSWebViewSigninClient() override;
 
@@ -57,11 +51,8 @@
   std::unique_ptr<WaitForNetworkCallbackHelper> network_callback_helper_;
   // The PrefService associated with this service.
   PrefService* pref_service_;
+  // The browser_state_ associated with this service.
   ios_web_view::WebViewBrowserState* browser_state_;
-  // Used to check if sign in cookies are allowed.
-  scoped_refptr<content_settings::CookieSettings> cookie_settings_;
-  // Used to add and remove content settings observers.
-  scoped_refptr<HostContentSettingsMap> host_content_settings_map_;
 
   DISALLOW_COPY_AND_ASSIGN(IOSWebViewSigninClient);
 };
diff --git a/ios/web_view/internal/signin/ios_web_view_signin_client.mm b/ios/web_view/internal/signin/ios_web_view_signin_client.mm
index d79495d0..111b1ec 100644
--- a/ios/web_view/internal/signin/ios_web_view_signin_client.mm
+++ b/ios/web_view/internal/signin/ios_web_view_signin_client.mm
@@ -4,8 +4,9 @@
 
 #include "ios/web_view/internal/signin/ios_web_view_signin_client.h"
 
+#include "base/macros.h"
 #include "components/signin/core/browser/cookie_settings_util.h"
-#include "google_apis/gaia/gaia_auth_fetcher.h"
+#include "ios/web_view/internal/signin/web_view_gaia_auth_fetcher.h"
 #include "ios/web_view/internal/web_view_browser_state.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
@@ -15,15 +16,11 @@
 
 IOSWebViewSigninClient::IOSWebViewSigninClient(
     PrefService* pref_service,
-    ios_web_view::WebViewBrowserState* browser_state,
-    scoped_refptr<content_settings::CookieSettings> cookie_settings,
-    scoped_refptr<HostContentSettingsMap> host_content_settings_map)
+    ios_web_view::WebViewBrowserState* browser_state)
     : network_callback_helper_(
           std::make_unique<WaitForNetworkCallbackHelper>()),
       pref_service_(pref_service),
-      browser_state_(browser_state),
-      cookie_settings_(cookie_settings),
-      host_content_settings_map_(host_content_settings_map) {}
+      browser_state_(browser_state) {}
 
 IOSWebViewSigninClient::~IOSWebViewSigninClient() {
 }
@@ -48,21 +45,21 @@
 void IOSWebViewSigninClient::DoFinalInit() {}
 
 bool IOSWebViewSigninClient::AreSigninCookiesAllowed() {
-  return signin::SettingsAllowSigninCookies(cookie_settings_.get());
+  return false;
 }
 
 bool IOSWebViewSigninClient::AreSigninCookiesDeletedOnExit() {
-  return signin::SettingsDeleteSigninCookiesOnExit(cookie_settings_.get());
+  return false;
 }
 
 void IOSWebViewSigninClient::AddContentSettingsObserver(
     content_settings::Observer* observer) {
-  host_content_settings_map_->AddObserver(observer);
+  NOTIMPLEMENTED();
 }
 
 void IOSWebViewSigninClient::RemoveContentSettingsObserver(
     content_settings::Observer* observer) {
-  host_content_settings_map_->RemoveObserver(observer);
+  NOTIMPLEMENTED();
 }
 
 void IOSWebViewSigninClient::PreSignOut(
@@ -78,7 +75,7 @@
 std::unique_ptr<GaiaAuthFetcher> IOSWebViewSigninClient::CreateGaiaAuthFetcher(
     GaiaAuthConsumer* consumer,
     gaia::GaiaSource source) {
-  return std::make_unique<GaiaAuthFetcher>(consumer, source,
-                                           GetURLLoaderFactory());
+  return std::make_unique<ios_web_view::WebViewGaiaAuthFetcher>(
+      consumer, source, GetURLLoaderFactory());
 }
 
diff --git a/ios/web_view/internal/signin/web_view_gaia_auth_fetcher.h b/ios/web_view/internal/signin/web_view_gaia_auth_fetcher.h
new file mode 100644
index 0000000..ed072e7c
--- /dev/null
+++ b/ios/web_view/internal/signin/web_view_gaia_auth_fetcher.h
@@ -0,0 +1,39 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_VIEW_INTERNAL_SIGNIN_WEB_VIEW_GAIA_AUTH_FETCHER_H_
+#define IOS_WEB_VIEW_INTERNAL_SIGNIN_WEB_VIEW_GAIA_AUTH_FETCHER_H_
+
+#include "base/memory/scoped_refptr.h"
+#include "google_apis/gaia/gaia_auth_consumer.h"
+#include "google_apis/gaia/gaia_auth_fetcher.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+
+namespace ios_web_view {
+
+// Implementation of GaiaAuthFetcher for ios/web_view.
+class WebViewGaiaAuthFetcher : public GaiaAuthFetcher {
+ public:
+  WebViewGaiaAuthFetcher(
+      GaiaAuthConsumer* consumer,
+      gaia::GaiaSource source,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
+
+ protected:
+  void CreateAndStartGaiaFetcher(
+      const std::string& body,
+      const std::string& body_content_type,
+      const std::string& headers,
+      const GURL& gaia_gurl,
+      network::mojom::CredentialsMode credentials_mode,
+      const net::NetworkTrafficAnnotationTag& traffic_annotation) override;
+
+ private:
+  // String representation of the passed in gaia::GaiaSource.
+  std::string source_;
+};
+
+}  // namespace ios_web_view
+
+#endif  // IOS_WEB_VIEW_INTERNAL_SIGNIN_WEB_VIEW_GAIA_AUTH_FETCHER_H_
diff --git a/ios/web_view/internal/signin/web_view_gaia_auth_fetcher.mm b/ios/web_view/internal/signin/web_view_gaia_auth_fetcher.mm
new file mode 100644
index 0000000..deebd56
--- /dev/null
+++ b/ios/web_view/internal/signin/web_view_gaia_auth_fetcher.mm
@@ -0,0 +1,40 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/web_view/internal/signin/web_view_gaia_auth_fetcher.h"
+
+#include "base/macros.h"
+#include "google_apis/gaia/gaia_urls.h"
+#include "net/base/net_errors.h"
+#include "net/http/http_status_code.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace ios_web_view {
+
+WebViewGaiaAuthFetcher::WebViewGaiaAuthFetcher(
+    GaiaAuthConsumer* consumer,
+    gaia::GaiaSource source,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
+    : GaiaAuthFetcher(consumer, source, url_loader_factory),
+      source_(source.ToString()) {}
+
+void WebViewGaiaAuthFetcher::CreateAndStartGaiaFetcher(
+    const std::string& body,
+    const std::string& body_content_type,
+    const std::string& headers,
+    const GURL& gaia_gurl,
+    network::mojom::CredentialsMode credentials_mode,
+    const net::NetworkTrafficAnnotationTag& traffic_annotation) {
+  // ios/web_view does not manage gaia auth cookies in the content area.
+  DCHECK_EQ(gaia_gurl,
+            GaiaUrls::GetInstance()->ListAccountsURLWithSource(source_));
+  DispatchFetchedRequest(gaia_gurl, /*data=*/"",
+                         net::Error::ERR_NOT_IMPLEMENTED,
+                         net::HttpStatusCode::HTTP_NOT_IMPLEMENTED);
+}
+
+}  // namespace ios_web_view
diff --git a/ios/web_view/internal/signin/web_view_gaia_auth_fetcher_unittest.mm b/ios/web_view/internal/signin/web_view_gaia_auth_fetcher_unittest.mm
new file mode 100644
index 0000000..bfc30c7
--- /dev/null
+++ b/ios/web_view/internal/signin/web_view_gaia_auth_fetcher_unittest.mm
@@ -0,0 +1,42 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/web_view/internal/signin/web_view_gaia_auth_fetcher.h"
+
+#include "google_apis/gaia/gaia_auth_consumer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace ios_web_view {
+
+class TestGaiaAuthConsumer : public GaiaAuthConsumer {
+ public:
+  void OnListAccountsSuccess(const std::string& data) override {
+    list_accounts_success_called_ = true;
+  }
+  void OnListAccountsFailure(const GoogleServiceAuthError& error) override {
+    list_accounts_failure_called_ = true;
+  }
+  bool list_accounts_success_called_ = false;
+  bool list_accounts_failure_called_ = false;
+};
+
+using WebViewGaiaAuthFetcherTest = PlatformTest;
+
+// Tests ListAccounts fails as expected.
+TEST_F(WebViewGaiaAuthFetcherTest, ListAccounts) {
+  TestGaiaAuthConsumer consumer;
+  WebViewGaiaAuthFetcher fetcher(&consumer, gaia::GaiaSource::kChrome,
+                                 /*url_loader_factory=*/nullptr);
+  fetcher.StartListAccounts();
+  EXPECT_FALSE(consumer.list_accounts_success_called_);
+  EXPECT_TRUE(consumer.list_accounts_failure_called_);
+}
+
+}  // namespace ios_web_view
diff --git a/ios/web_view/internal/signin/web_view_signin_client_factory.mm b/ios/web_view/internal/signin/web_view_signin_client_factory.mm
index 255f6eb6..02d5cde 100644
--- a/ios/web_view/internal/signin/web_view_signin_client_factory.mm
+++ b/ios/web_view/internal/signin/web_view_signin_client_factory.mm
@@ -8,8 +8,6 @@
 #include "components/keyed_service/core/service_access_type.h"
 #include "components/keyed_service/ios/browser_state_dependency_manager.h"
 #include "components/signin/public/base/signin_client.h"
-#include "ios/web_view/internal/content_settings/web_view_cookie_settings_factory.h"
-#include "ios/web_view/internal/content_settings/web_view_host_content_settings_map_factory.h"
 #include "ios/web_view/internal/signin/ios_web_view_signin_client.h"
 #include "ios/web_view/internal/web_view_browser_state.h"
 
@@ -36,8 +34,6 @@
     : BrowserStateKeyedServiceFactory(
           "SigninClient",
           BrowserStateDependencyManager::GetInstance()) {
-  DependsOn(WebViewCookieSettingsFactory::GetInstance());
-  DependsOn(WebViewHostContentSettingsMapFactory::GetInstance());
 }
 
 std::unique_ptr<KeyedService>
@@ -45,10 +41,8 @@
     web::BrowserState* context) const {
   WebViewBrowserState* browser_state =
       WebViewBrowserState::FromBrowserState(context);
-  return std::make_unique<IOSWebViewSigninClient>(
-      browser_state->GetPrefs(), browser_state,
-      WebViewCookieSettingsFactory::GetForBrowserState(browser_state),
-      WebViewHostContentSettingsMapFactory::GetForBrowserState(browser_state));
+  return std::make_unique<IOSWebViewSigninClient>(browser_state->GetPrefs(),
+                                                  browser_state);
 }
 
 }  // namespace ios_web_view
diff --git a/ios/web_view/internal/web_view_browser_state.mm b/ios/web_view/internal/web_view_browser_state.mm
index 9cc85c09..aa6d351 100644
--- a/ios/web_view/internal/web_view_browser_state.mm
+++ b/ios/web_view/internal/web_view_browser_state.mm
@@ -22,7 +22,6 @@
 #include "components/prefs/json_pref_store.h"
 #include "components/prefs/pref_filter.h"
 #include "components/prefs/pref_service_factory.h"
-#include "components/signin/ios/browser/active_state_manager.h"
 #include "components/sync/base/pref_names.h"
 #include "components/sync/base/sync_prefs.h"
 #include "components/sync_device_info/device_info_prefs.h"
@@ -34,8 +33,6 @@
 #include "ios/web_view/internal/app/application_context.h"
 #import "ios/web_view/internal/autofill/web_view_autofill_log_router_factory.h"
 #include "ios/web_view/internal/autofill/web_view_personal_data_manager_factory.h"
-#include "ios/web_view/internal/content_settings/web_view_cookie_settings_factory.h"
-#include "ios/web_view/internal/content_settings/web_view_host_content_settings_map_factory.h"
 #include "ios/web_view/internal/language/web_view_language_model_manager_factory.h"
 #include "ios/web_view/internal/language/web_view_url_language_histogram_factory.h"
 #import "ios/web_view/internal/passwords/web_view_password_manager_log_router_factory.h"
@@ -108,8 +105,6 @@
 
   base::ThreadRestrictions::SetIOAllowed(wasIOAllowed);
 
-  ActiveStateManager::FromBrowserState(this)->SetActive(true);
-
   BrowserStateDependencyManager::GetInstance()->CreateBrowserStateServices(
       this);
 }
@@ -118,8 +113,6 @@
   BrowserStateDependencyManager::GetInstance()->DestroyBrowserStateServices(
       this);
 
-  ActiveStateManager::FromBrowserState(this)->SetActive(false);
-
   base::PostTask(FROM_HERE, {web::WebThread::IO},
                  base::BindOnce(&WebViewURLRequestContextGetter::ShutDown,
                                 request_context_getter_));
@@ -181,8 +174,6 @@
   WebViewWebDataServiceWrapperFactory::GetInstance();
   WebViewPasswordManagerLogRouterFactory::GetInstance();
   WebViewPasswordStoreFactory::GetInstance();
-  WebViewCookieSettingsFactory::GetInstance();
-  WebViewHostContentSettingsMapFactory::GetInstance();
   WebViewSigninClientFactory::GetInstance();
   WebViewSigninErrorControllerFactory::GetInstance();
   WebViewIdentityManagerFactory::GetInstance();
diff --git a/media/gpu/v4l2/v4l2_video_encode_accelerator.cc b/media/gpu/v4l2/v4l2_video_encode_accelerator.cc
index 5bd1041..4aac0b1 100644
--- a/media/gpu/v4l2/v4l2_video_encode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_video_encode_accelerator.cc
@@ -459,6 +459,11 @@
   DCHECK(image_processor_);
   DCHECK_EQ(image_processor_->output_mode(),
             ImageProcessor::OutputMode::IMPORT);
+
+  // The existing buffers in |image_processor_output_buffers_| may be alive
+  // until they are actually consumed by the encoder driver, after they are
+  // destroyed here.
+  image_processor_output_buffers_.clear();
   image_processor_output_buffers_.resize(count);
   const ImageProcessor::PortConfig& output_config =
       image_processor_->output_config();
@@ -755,19 +760,36 @@
   }
 
   if (!input_buffer_map_.empty()) {
-    // TODO(crbug.com/1060057): Handle coded_size change.
-    if (frame.coded_size() != input_frame_size_) {
-      VLOGF(1) << "Input frame size is changed during encoding"
-               << ", frame.coded_size()=" << frame.coded_size().ToString()
-               << ", input_frame_size=" << input_frame_size_.ToString();
+    // ReconfigureFormatIfNeeded() has been called with the first VideoFrame.
+    // We checks here we need to (re)create ImageProcessor because the visible
+    // rectangle of |frame| differs from the first VideoFrame.
+    // |frame.natural_size()| is the size to be encoded. It must be the same as
+    // |encoder_input_visible_rect_.size()|, otherwise VEA client must recreate
+    // VEA with the new encoder resolution.
+    if (frame.natural_size() != encoder_input_visible_rect_.size()) {
+      VLOGF(1) << "Encoder resolution is changed during encoding"
+               << ", frame.natural_size()=" << frame.natural_size().ToString()
+               << ", encoder_input_visible_rect_="
+               << input_frame_size_.ToString();
       return false;
     }
-    return true;
-  }
+    if (frame.coded_size() == input_frame_size_) {
+      return true;
+    }
 
-  // Height and width that V4L2VEA needs to configure.
-  const gfx::Size buffer_size(frame.stride(0), frame.coded_size().height());
-  if (frame.coded_size() == input_frame_size_) {
+    // If a dimension of the underlying VideoFrame varies during video encoding
+    // (i.e. frame.coded_size() != input_frame_size_), we (re)create
+    // ImageProcessor to crop the VideoFrame, |frame.visible_rect()| ->
+    // |encoder_input_visible_rect_|.
+    // TODO(hiroh): if |frame.coded_size()| is the same as VideoFrame::
+    // DetermineAlignedSize(input_format, encoder_input_visible_rect_.size())
+    // and don't need a pixel format conversion, image processor is not
+    // necessary but we should rather NegotiateInputFormat().
+  } else if (frame.coded_size() == input_frame_size_) {
+    // This path is for the first frame on Encode().
+    // Height and width that V4L2VEA needs to configure.
+    const gfx::Size buffer_size(frame.stride(0), frame.coded_size().height());
+
     // A buffer given by client is allocated with the same dimension using
     // minigbm. However, it is possible that stride and height are different
     // from ones adjusted by a driver.
@@ -790,13 +812,30 @@
 
   // The |frame| dimension is different from the resolution configured to
   // V4L2VEA. This is the case that V4L2VEA needs to create ImageProcessor for
-  // scaling. Update |input_frame_size_| to check if succeeding frames'
-  // dimensions are not different from one of the first frame.
+  // cropping and scaling. Update |input_frame_size_| to check if succeeding
+  // frames' dimensions are not different from the current one.
   input_frame_size_ = frame.coded_size();
-  return CreateImageProcessor(frame.layout(), device_input_layout_->format(),
-                              device_input_layout_->coded_size(),
-                              frame.visible_rect(),
-                              encoder_input_visible_rect_);
+  if (!CreateImageProcessor(frame.layout(), device_input_layout_->format(),
+                            device_input_layout_->coded_size(),
+                            frame.visible_rect(),
+                            encoder_input_visible_rect_)) {
+    return false;
+  }
+
+  if (gfx::Size(image_processor_->output_config().planes[0].stride,
+                image_processor_->output_config().size.height()) !=
+      device_input_layout_->coded_size()) {
+    VLOGF(1) << "Image Processor's output buffer's size is different from "
+             << "input buffer size configure to the encoder driver. "
+             << "ip's output buffer size: "
+             << gfx::Size(image_processor_->output_config().planes[0].stride,
+                          image_processor_->output_config().size.height())
+                    .ToString()
+             << ", encoder's input buffer size: "
+             << device_input_layout_->coded_size().ToString();
+    return false;
+  }
+  return true;
 }
 
 void V4L2VideoEncodeAccelerator::InputImageProcessorTask() {
@@ -1496,8 +1535,28 @@
   if (!SetOutputFormat(output_profile))
     return false;
 
-  auto v4l2_format =
-      NegotiateInputFormat(input_format, encoder_input_visible_rect_.size());
+  gfx::Size input_size = encoder_input_visible_rect_.size();
+  if (native_input_mode_) {
+    DCHECK(!image_processor_gmb_factory_);
+    image_processor_gmb_factory_ =
+        gpu::GpuMemoryBufferFactory::CreateNativeType(nullptr);
+    if (!image_processor_gmb_factory_) {
+      VLOGF(1) << "Failed to create GpuMemoryBufferFactory";
+      return false;
+    }
+
+    auto input_layout = GetPlatformVideoFrameLayout(
+        image_processor_gmb_factory_.get(), input_format,
+        encoder_input_visible_rect_.size(),
+        gfx::BufferUsage::SCANOUT_VEA_READ_CAMERA_AND_CPU_READ_WRITE);
+    if (!input_layout)
+      return false;
+    input_size = gfx::Size(input_layout->planes()[0].stride,
+                           input_layout->coded_size().height());
+  }
+
+  DCHECK(input_frame_size_.IsEmpty());
+  auto v4l2_format = NegotiateInputFormat(input_format, input_size);
   if (!v4l2_format)
     return false;
 
diff --git a/media/mojo/mojom/video_encode_accelerator_mojom_traits_unittest.cc b/media/mojo/mojom/video_encode_accelerator_mojom_traits_unittest.cc
index fd15586..2c7ac94 100644
--- a/media/mojo/mojom/video_encode_accelerator_mojom_traits_unittest.cc
+++ b/media/mojo/mojom/video_encode_accelerator_mojom_traits_unittest.cc
@@ -64,10 +64,10 @@
 bool operator==(
     const ::media::VideoEncodeAccelerator::Config::SpatialLayer& l,
     const ::media::VideoEncodeAccelerator::Config::SpatialLayer& r) {
-  return l.width == r.width && l.height == r.height &&
-         l.bitrate_bps == r.bitrate_bps && l.framerate == r.framerate &&
-         l.max_qp == r.max_qp && l.num_of_temporal_layers &&
-         r.num_of_temporal_layers;
+  return (l.width == r.width && l.height == r.height &&
+          l.bitrate_bps == r.bitrate_bps && l.framerate == r.framerate &&
+          l.max_qp == r.max_qp &&
+          l.num_of_temporal_layers == r.num_of_temporal_layers);
 }
 
 bool operator==(const ::media::VideoEncodeAccelerator::Config& l,
@@ -109,21 +109,15 @@
   EXPECT_EQ(input, output);
 }
 
-// This test is failing on msan: crbug.com/1067758
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_RoundTrip DISABLED_RoundTrip
-#else
-#define MAYBE_RoundTrip RoundTrip
-#endif
-TEST(SpatialLayerStructTraitTest, MAYBE_RoundTrip) {
+TEST(SpatialLayerStructTraitTest, RoundTrip) {
   ::media::VideoEncodeAccelerator::Config::SpatialLayer input_spatial_layer;
-  input_spatial_layer.width = 320u;
-  input_spatial_layer.width = 180u;
-  input_spatial_layer.bitrate_bps = 12345678;
-  input_spatial_layer.framerate = 24;
-  input_spatial_layer.max_qp = 30;
-  input_spatial_layer.num_of_temporal_layers = 3;
-  ::media::VideoEncodeAccelerator::Config::SpatialLayer output_spatial_layer{};
+  input_spatial_layer.width = 320;
+  input_spatial_layer.width = 180;
+  input_spatial_layer.bitrate_bps = 12345678u;
+  input_spatial_layer.framerate = 24u;
+  input_spatial_layer.max_qp = 30u;
+  input_spatial_layer.num_of_temporal_layers = 3u;
+  ::media::VideoEncodeAccelerator::Config::SpatialLayer output_spatial_layer;
   ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::SpatialLayer>(
       &input_spatial_layer, &output_spatial_layer));
   EXPECT_EQ(input_spatial_layer, output_spatial_layer);
@@ -133,13 +127,13 @@
   std::vector<::media::VideoEncodeAccelerator::Config::SpatialLayer>
       input_spatial_layers(3);
   gfx::Size kBaseSize(320, 180);
-  uint32_t kBaseBitrateBps = 123456;
-  uint32_t kBaseFramerate = 24;
+  uint32_t kBaseBitrateBps = 123456u;
+  uint32_t kBaseFramerate = 24u;
   for (size_t i = 0; i < input_spatial_layers.size(); ++i) {
     input_spatial_layers[i].width =
-        static_cast<uint32_t>(kBaseSize.width() * (i + 1));
+        static_cast<int32_t>(kBaseSize.width() * (i + 1));
     input_spatial_layers[i].height =
-        static_cast<uint32_t>(kBaseSize.height() * (i + 1));
+        static_cast<int32_t>(kBaseSize.height() * (i + 1));
     input_spatial_layers[i].bitrate_bps = kBaseBitrateBps * (i + 1) / 2;
     input_spatial_layers[i].framerate = kBaseFramerate * 2 / (i + 1);
     input_spatial_layers[i].max_qp = 30 * (i + 1) / 2;
diff --git a/media/video/video_encode_accelerator.h b/media/video/video_encode_accelerator.h
index 114a8cf..26d1480 100644
--- a/media/video/video_encode_accelerator.h
+++ b/media/video/video_encode_accelerator.h
@@ -112,18 +112,18 @@
 
     struct MEDIA_EXPORT SpatialLayer {
       // The encoder dimension of the spatial layer.
-      int32_t width;
-      int32_t height;
+      int32_t width = 0;
+      int32_t height = 0;
       // The bitrate of encoded output stream of the spatial layer in bits per
       // second.
-      uint32_t bitrate_bps;
-      uint32_t framerate;
+      uint32_t bitrate_bps = 0u;
+      uint32_t framerate = 0u;
       // The recommended maximum qp value of the spatial layer. VEA can ignore
       // this value.
-      uint8_t max_qp;
+      uint8_t max_qp = 0u;
       // The number of temporal layers of the spatial layer. The detail of
       // the temporal layer structure is up to VideoEncodeAccelerator.
-      uint8_t num_of_temporal_layers;
+      uint8_t num_of_temporal_layers = 0u;
     };
 
     Config();
diff --git a/net/base/network_change_notifier_fuchsia_unittest.cc b/net/base/network_change_notifier_fuchsia_unittest.cc
index cc2ff2b..e5ca7fa 100644
--- a/net/base/network_change_notifier_fuchsia_unittest.cc
+++ b/net/base/network_change_notifier_fuchsia_unittest.cc
@@ -430,7 +430,7 @@
   netstack_.SetInterfaces(interfaces);
 
   // Expect a single OnIPAddressChanged() notification.
-  ip_observer_->RunAndExpectCallCount(1);
+  EXPECT_TRUE(ip_observer_->RunAndExpectCallCount(1));
 }
 
 TEST_F(NetworkChangeNotifierFuchsiaTest, IpChangeV6) {
@@ -451,7 +451,7 @@
   netstack_.SetInterfaces(interfaces);
 
   // Expect a single OnIPAddressChanged() notification.
-  ip_observer_->RunAndExpectCallCount(1);
+  EXPECT_TRUE(ip_observer_->RunAndExpectCallCount(1));
 }
 
 TEST_F(NetworkChangeNotifierFuchsiaTest, MultiV6IPChanged) {
@@ -471,7 +471,7 @@
   netstack_.SetInterfaces(interfaces);
 
   // Expect a single OnIPAddressChanged() notification.
-  ip_observer_->RunAndExpectCallCount(1);
+  EXPECT_TRUE(ip_observer_->RunAndExpectCallCount(1));
 }
 
 TEST_F(NetworkChangeNotifierFuchsiaTest, Ipv6AdditionalIpChange) {
@@ -487,7 +487,7 @@
   netstack_.SetInterfaces(interfaces);
 
   // Expect a single OnIPAddressChanged() notification.
-  ip_observer_->RunAndExpectCallCount(1);
+  EXPECT_TRUE(ip_observer_->RunAndExpectCallCount(1));
 }
 
 TEST_F(NetworkChangeNotifierFuchsiaTest, InterfaceDown) {
@@ -502,9 +502,9 @@
   interfaces[0].flags = 0;
   netstack_.SetInterfaces(interfaces);
 
-  type_observer_->RunAndExpectConnectionTypes(
-      {NetworkChangeNotifier::ConnectionType::CONNECTION_NONE});
-  ip_observer_->RunAndExpectCallCount(1);
+  EXPECT_TRUE(type_observer_->RunAndExpectConnectionTypes(
+      {NetworkChangeNotifier::ConnectionType::CONNECTION_NONE}));
+  EXPECT_TRUE(ip_observer_->RunAndExpectCallCount(1));
 }
 
 TEST_F(NetworkChangeNotifierFuchsiaTest, InterfaceUp) {
@@ -520,9 +520,9 @@
   interfaces[0].flags = fuchsia::netstack::NetInterfaceFlagUp;
   netstack_.SetInterfaces(interfaces);
 
-  type_observer_->RunAndExpectConnectionTypes(
-      {NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN});
-  ip_observer_->RunAndExpectCallCount(1);
+  EXPECT_TRUE(type_observer_->RunAndExpectConnectionTypes(
+      {NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN}));
+  EXPECT_TRUE(ip_observer_->RunAndExpectCallCount(1));
 }
 
 TEST_F(NetworkChangeNotifierFuchsiaTest, InterfaceDeleted) {
@@ -536,9 +536,9 @@
 
   netstack_.SetInterfaces({});
 
-  type_observer_->RunAndExpectConnectionTypes(
-      {NetworkChangeNotifier::ConnectionType::CONNECTION_NONE});
-  ip_observer_->RunAndExpectCallCount(1);
+  EXPECT_TRUE(type_observer_->RunAndExpectConnectionTypes(
+      {NetworkChangeNotifier::ConnectionType::CONNECTION_NONE}));
+  EXPECT_TRUE(ip_observer_->RunAndExpectCallCount(1));
 }
 
 TEST_F(NetworkChangeNotifierFuchsiaTest, InterfaceAdded) {
@@ -553,9 +553,9 @@
 
   netstack_.SetInterfaces(interfaces);
 
-  type_observer_->RunAndExpectConnectionTypes(
-      {NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI});
-  ip_observer_->RunAndExpectCallCount(1);
+  EXPECT_TRUE(type_observer_->RunAndExpectConnectionTypes(
+      {NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI}));
+  EXPECT_TRUE(ip_observer_->RunAndExpectCallCount(1));
 }
 
 TEST_F(NetworkChangeNotifierFuchsiaTest, SecondaryInterfaceAddedNoop) {
diff --git a/printing/BUILD.gn b/printing/BUILD.gn
index 246c15c7..54c76a54 100644
--- a/printing/BUILD.gn
+++ b/printing/BUILD.gn
@@ -362,6 +362,7 @@
   if (is_win) {
     sources += [
       "emf_win_unittest.cc",
+      "printed_document_unittest.cc",
       "printed_page_win_unittest.cc",
       "printing_context_win_unittest.cc",
     ]
@@ -369,10 +370,6 @@
     data = [ "test/data/emf/" ]
   }
 
-  if (is_win || is_mac) {
-    sources += [ "printed_document_unittest.cc" ]
-  }
-
   if (use_cups) {
     configs += [ ":cups" ]
 
diff --git a/printing/image_mac.cc b/printing/image_mac.cc
index 11fc4ca..a79eab6b 100644
--- a/printing/image_mac.cc
+++ b/printing/image_mac.cc
@@ -34,10 +34,8 @@
       color_space, kCGImageAlphaPremultipliedLast));
   DCHECK(bitmap_context.get());
 
-  struct Metafile::MacRenderPageParams params;
-  params.shrink_to_fit = true;
-  metafile.RenderPage(page_number, bitmap_context, rect.ToCGRect(), params);
-  return true;
+  return metafile.RenderPage(page_number, bitmap_context, rect.ToCGRect(),
+                             /*autorotate=*/false, /*fit_to_page=*/true);
 }
 
 }  // namespace printing
diff --git a/printing/metafile.h b/printing/metafile.h
index bf823ca..a1eac7f6 100644
--- a/printing/metafile.h
+++ b/printing/metafile.h
@@ -37,32 +37,6 @@
 // This class plays metafiles from data stream (usually PDF or EMF).
 class PRINTING_EXPORT MetafilePlayer {
  public:
-#if defined(OS_MACOSX)
-  struct MacRenderPageParams {
-    // Whether the output should be shrunk to fit a destination page if the
-    // source PDF is bigger than the destination page in any dimension. If this
-    // is false, parts of the source PDF page that lie outside the bounds will
-    // be clipped.
-    bool shrink_to_fit = false;
-
-    // Whether the output should be stretched to fit the destination page if the
-    // source page size is smaller in all dimensions.
-    bool stretch_to_fit = false;
-
-    // Whether the output (after any scaling is done) should be centered
-    // horizontally within the destination page.
-    bool center_horizontally = false;
-
-    // Whether the output (after any scaling is done) should be centered
-    // vertically within the destination page. Note that all scaling preserves
-    // the original aspect ratio of the page.
-    bool center_vertically = false;
-
-    // Whether the source PDF should be autorotated to fit on the destination
-    // page.
-    bool autorotate = false;
-  };
-#endif  // defined(OS_MACOSX)
   MetafilePlayer();
   virtual ~MetafilePlayer();
 
@@ -75,13 +49,16 @@
 
 #elif defined(OS_MACOSX)
   // Renders the given page into |rect| in the given context.
-  // Pages use a 1-based index. The rendering uses the arguments in
-  // |params| to determine scaling, translation, and rotation.
+  // Pages use a 1-based index. |autorotate| determines whether the source PDF
+  // should be autorotated to fit on the destination page. |fit_to_page|
+  // determines whether the source PDF should be scaled to fit on the
+  // destination page.
   virtual bool RenderPage(unsigned int page_number,
                           printing::NativeDrawingContext context,
                           const CGRect& rect,
-                          const MacRenderPageParams& params) const = 0;
-#endif  // if defined(OS_WIN)
+                          bool autorotate,
+                          bool fit_to_page) const = 0;
+#endif  // defined(OS_WIN)
 
   // Populates the buffer with the underlying data. This function should ONLY be
   // called after the metafile is closed. Returns true if writing succeeded.
diff --git a/printing/metafile_skia.cc b/printing/metafile_skia.cc
index 7baa981..67d7be5 100644
--- a/printing/metafile_skia.cc
+++ b/printing/metafile_skia.cc
@@ -280,7 +280,8 @@
 bool MetafileSkia::RenderPage(unsigned int page_number,
                               CGContextRef context,
                               const CGRect& rect,
-                              const MacRenderPageParams& params) const {
+                              bool autorotate,
+                              bool fit_to_page) const {
   DCHECK_GT(GetDataSize(), 0U);
   if (data_->pdf_cg.GetDataSize() == 0) {
     if (GetDataSize() == 0)
@@ -290,7 +291,8 @@
     (void)WriteAssetToBuffer(data_->data_stream.get(), &buffer[0], length);
     data_->pdf_cg.InitFromData(buffer);
   }
-  return data_->pdf_cg.RenderPage(page_number, context, rect, params);
+  return data_->pdf_cg.RenderPage(page_number, context, rect, autorotate,
+                                  fit_to_page);
 }
 #endif
 
diff --git a/printing/metafile_skia.h b/printing/metafile_skia.h
index eeff98a..c1fe8402 100644
--- a/printing/metafile_skia.h
+++ b/printing/metafile_skia.h
@@ -62,7 +62,8 @@
   bool RenderPage(unsigned int page_number,
                   printing::NativeDrawingContext context,
                   const CGRect& rect,
-                  const MacRenderPageParams& params) const override;
+                  bool autorotate,
+                  bool fit_to_page) const override;
 #endif
 
 #if defined(OS_ANDROID)
diff --git a/printing/pdf_metafile_cg_mac.cc b/printing/pdf_metafile_cg_mac.cc
index 53420ab..515f84f 100644
--- a/printing/pdf_metafile_cg_mac.cc
+++ b/printing/pdf_metafile_cg_mac.cc
@@ -158,7 +158,8 @@
 bool PdfMetafileCg::RenderPage(unsigned int page_number,
                                CGContextRef context,
                                const CGRect& rect,
-                               const MacRenderPageParams& params) const {
+                               bool autorotate,
+                               bool fit_to_page) const {
   CGPDFDocumentRef pdf_doc = GetPDFDocument();
   if (!pdf_doc) {
     LOG(ERROR) << "Unable to create PDF document from data";
@@ -172,12 +173,11 @@
 
   CGPDFPageRef pdf_page = CGPDFDocumentGetPage(pdf_doc, page_number);
   CGRect source_rect = CGPDFPageGetBoxRect(pdf_page, kCGPDFCropBox);
-  int pdf_src_rotation = CGPDFPageGetRotationAngle(pdf_page);
+  const int pdf_src_rotation = CGPDFPageGetRotationAngle(pdf_page);
   const bool source_is_landscape =
       (source_rect.size.width > source_rect.size.height);
   const bool dest_is_landscape = (rect.size.width > rect.size.height);
-  const bool rotate =
-      params.autorotate ? (source_is_landscape != dest_is_landscape) : false;
+  const bool rotate = autorotate && (source_is_landscape != dest_is_landscape);
   const float source_width =
       rotate ? source_rect.size.height : source_rect.size.width;
   const float source_height =
@@ -186,40 +186,16 @@
   // See if we need to scale the output.
   float scaling_factor = 1.0;
   const bool scaling_needed =
-      (params.shrink_to_fit && ((source_width > rect.size.width) ||
-                                (source_height > rect.size.height))) ||
-      (params.stretch_to_fit && ((source_width < rect.size.width) &&
-                                 (source_height < rect.size.height)));
+      fit_to_page && ((source_width != rect.size.width) ||
+                      (source_height != rect.size.height));
   if (scaling_needed) {
     float x_scaling_factor = rect.size.width / source_width;
     float y_scaling_factor = rect.size.height / source_height;
     scaling_factor = std::min(x_scaling_factor, y_scaling_factor);
   }
-  // Some PDFs have a non-zero origin. Need to take that into account and align
-  // the PDF to the origin.
-  const float x_origin_offset = -1 * source_rect.origin.x;
-  const float y_origin_offset = -1 * source_rect.origin.y;
-
-  // If the PDF needs to be centered, calculate the offsets here.
-  float x_offset =
-      params.center_horizontally
-          ? ((rect.size.width - (source_width * scaling_factor)) / 2)
-          : 0;
-  if (rotate)
-    x_offset = -x_offset;
-
-  float y_offset =
-      params.center_vertically
-          ? ((rect.size.height - (source_height * scaling_factor)) / 2)
-          : 0;
 
   CGContextSaveGState(context);
 
-  // The transform operations specified here gets applied in reverse order.
-  // i.e. the origin offset translation happens first.
-  // Origin is at bottom-left.
-  CGContextTranslateCTM(context, x_offset, y_offset);
-
   int num_rotations = 0;
   if (rotate) {
     if (pdf_src_rotation == 0 || pdf_src_rotation == 270) {
@@ -235,6 +211,24 @@
   RotatePage(context, rect, num_rotations);
 
   CGContextScaleCTM(context, scaling_factor, scaling_factor);
+
+  // Some PDFs have a non-zero origin. Need to take that into account and align
+  // the PDF to the CoreGraphics's coordinate system origin. Also realign the
+  // contents from the bottom-left of the page to top-left in order to stay
+  // consistent with Print Preview.
+  // A rotational vertical offset is calculated to determine how much to offset
+  // the y-component of the origin to move the origin from bottom-left to
+  // top-right. When the source is not rotated, the offset is simply the
+  // difference between the paper height and the source height. When rotated,
+  // the y-axis of the source falls along the width of the source and paper, so
+  // the offset becomes the difference between the paper width and the source
+  // width.
+  const float rotational_vertical_offset =
+      rotate ? (rect.size.width - (scaling_factor * source_width))
+             : (rect.size.height - (scaling_factor * source_height));
+  const float x_origin_offset = -1 * source_rect.origin.x;
+  const float y_origin_offset =
+      rotational_vertical_offset - source_rect.origin.y;
   CGContextTranslateCTM(context, x_origin_offset, y_origin_offset);
 
   CGContextDrawPDFPage(context, pdf_page);
diff --git a/printing/pdf_metafile_cg_mac.h b/printing/pdf_metafile_cg_mac.h
index 6a51669..a7d1a15 100644
--- a/printing/pdf_metafile_cg_mac.h
+++ b/printing/pdf_metafile_cg_mac.h
@@ -44,7 +44,8 @@
   bool RenderPage(unsigned int page_number,
                   printing::NativeDrawingContext context,
                   const CGRect& rect,
-                  const MacRenderPageParams& params) const override;
+                  bool autorotate,
+                  bool fit_to_page) const override;
 
  private:
   // Returns a CGPDFDocumentRef version of |pdf_data_|.
diff --git a/printing/pdf_metafile_cg_mac_unittest.cc b/printing/pdf_metafile_cg_mac_unittest.cc
index 4fbcef80..15517fd 100644
--- a/printing/pdf_metafile_cg_mac_unittest.cc
+++ b/printing/pdf_metafile_cg_mac_unittest.cc
@@ -62,6 +62,8 @@
                      size_t page_number,
                      const gfx::Rect& expected_page_bounds,
                      const gfx::Size& dest_size,
+                     bool autorotate,
+                     bool fit_to_page,
                      base::SHA1Digest* rendered_hash) {
   // Initialize and verify the metafile.
   std::unique_ptr<PdfMetafileCg> pdf_cg = GetPdfMetafile(pdf_filename);
@@ -83,10 +85,9 @@
       kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little));
 
   // Render using metafile and calculate the output hash.
-  Metafile::MacRenderPageParams params;
-  params.autorotate = true;
   ASSERT_TRUE(pdf_cg->RenderPage(page_number, context,
-                                 gfx::Rect(dest_size).ToCGRect(), params));
+                                 gfx::Rect(dest_size).ToCGRect(), autorotate,
+                                 fit_to_page));
   *rendered_hash = base::SHA1HashSpan(rendered_bitmap);
 }
 
@@ -111,14 +112,17 @@
   *expected_hash = base::SHA1HashSpan(expected_png_bitmap);
 }
 
-void TestRenderPage(const base::FilePath::StringType& pdf_filename,
-                    size_t page_number,
-                    const gfx::Rect& expected_page_bounds,
-                    const base::FilePath::StringType& expected_png_filename,
-                    const gfx::Size& dest_size) {
+void TestRenderPageWithTransformParams(
+    const base::FilePath::StringType& pdf_filename,
+    size_t page_number,
+    const gfx::Rect& expected_page_bounds,
+    const base::FilePath::StringType& expected_png_filename,
+    const gfx::Size& dest_size,
+    bool autorotate,
+    bool fit_to_page) {
   base::SHA1Digest rendered_hash;
   RenderedPdfSha1(pdf_filename, page_number, expected_page_bounds, dest_size,
-                  &rendered_hash);
+                  autorotate, fit_to_page, &rendered_hash);
   base::SHA1Digest expected_hash;
   ExpectedPngSha1(expected_png_filename, dest_size, &expected_hash);
 
@@ -126,6 +130,16 @@
   EXPECT_EQ(expected_hash, rendered_hash);
 }
 
+void TestRenderPage(const base::FilePath::StringType& pdf_filename,
+                    size_t page_number,
+                    const gfx::Rect& expected_page_bounds,
+                    const base::FilePath::StringType& expected_png_filename,
+                    const gfx::Size& dest_size) {
+  TestRenderPageWithTransformParams(
+      pdf_filename, page_number, expected_page_bounds, expected_png_filename,
+      dest_size, /*autorotate=*/true, /*fit_to_page=*/false);
+}
+
 }  // namespace
 
 TEST(PdfMetafileCgTest, Pdf) {
@@ -299,4 +313,24 @@
                  kDestinationSize);
 }
 
+TEST(PdfMetafileCgTest, RenderScaledLargeLandscapeRectangles) {
+  constexpr gfx::Rect kPageBounds(800, 500);
+  constexpr gfx::Size kDestinationSize(300, 450);
+  TestRenderPageWithTransformParams(
+      "landscape_rectangles.pdf", /*page_number=*/1, kPageBounds,
+      "render_scaled_large_landscape_rectangles_expected.0.png",
+      kDestinationSize,
+      /*autorotate=*/true, /*fit_to_page=*/true);
+}
+
+TEST(PdfMetafileCgTest, RenderScaledSmallLandscapeRectangles) {
+  constexpr gfx::Rect kPageBounds(800, 500);
+  constexpr gfx::Size kDestinationSize(600, 900);
+  TestRenderPageWithTransformParams(
+      "landscape_rectangles.pdf", /*page_number=*/1, kPageBounds,
+      "render_scaled_small_landscape_rectangles_expected.0.png",
+      kDestinationSize,
+      /*autorotate=*/true, /*fit_to_page=*/true);
+}
+
 }  // namespace printing
diff --git a/printing/printed_document.cc b/printing/printed_document.cc
index af32ba52..69c47212 100644
--- a/printing/printed_document.cc
+++ b/printing/printed_document.cc
@@ -169,16 +169,10 @@
 }
 #endif  // defined(OS_WIN)
 
-void PrintedDocument::SetDocument(std::unique_ptr<MetafilePlayer> metafile,
-                                  const gfx::Size& page_size,
-                                  const gfx::Rect& page_content_rect) {
+void PrintedDocument::SetDocument(std::unique_ptr<MetafilePlayer> metafile) {
   {
     base::AutoLock lock(lock_);
     mutable_.metafile_ = std::move(metafile);
-#if defined(OS_MACOSX)
-    mutable_.page_size_ = page_size;
-    mutable_.page_content_rect_ = page_content_rect;
-#endif
   }
 
   if (HasDebugDumpPath()) {
@@ -285,7 +279,7 @@
                      base::RetainedRef(data)));
 }
 
-#if defined(OS_WIN) || defined(OS_MACOSX)
+#if defined(OS_WIN)
 gfx::Rect PrintedDocument::GetCenteredPageContentRect(
     const gfx::Size& paper_size,
     const gfx::Size& page_size,
diff --git a/printing/printed_document.h b/printing/printed_document.h
index 2810e264..ec93f0e 100644
--- a/printing/printed_document.h
+++ b/printing/printed_document.h
@@ -67,9 +67,7 @@
 #endif  // defined(OS_WIN)
 
   // Sets the document data. Note: locks for a short amount of time.
-  void SetDocument(std::unique_ptr<MetafilePlayer> metafile,
-                   const gfx::Size& page_size,
-                   const gfx::Rect& page_content_rect);
+  void SetDocument(std::unique_ptr<MetafilePlayer> metafile);
 
   // Retrieves the metafile with the data to print. Lock must be held when
   // calling this function
@@ -131,7 +129,7 @@
   void DebugDumpData(const base::RefCountedMemory* data,
                      const base::FilePath::StringType& extension);
 
-#if defined(OS_WIN) || defined(OS_MACOSX)
+#if defined(OS_WIN)
   // Get page content rect adjusted based on
   // http://dev.w3.org/csswg/css3-page/#positioning-page-box
   gfx::Rect GetCenteredPageContentRect(const gfx::Size& paper_size,
@@ -173,11 +171,6 @@
     // Whether the PDF is being converted for printing.
     bool converting_pdf_ = false;
 #endif
-
-#if defined(OS_MACOSX)
-    gfx::Size page_size_;
-    gfx::Rect page_content_rect_;
-#endif
   };
 
   // Contains all the immutable stuff. All this stuff can be accessed without
diff --git a/printing/printed_document_mac.cc b/printing/printed_document_mac.cc
index 0df77e6..bb63008 100644
--- a/printing/printed_document_mac.cc
+++ b/printing/printed_document_mac.cc
@@ -17,29 +17,22 @@
   DCHECK(context);
 
   const MetafilePlayer* metafile;
-  gfx::Size page_size;
-  gfx::Rect page_content_rect;
   {
     base::AutoLock lock(lock_);
     metafile = GetMetafile();
-    page_size = mutable_.page_size_;
-    page_content_rect = mutable_.page_content_rect_;
   }
 
   DCHECK(metafile);
   const PageSetup& page_setup = immutable_.settings_->page_setup_device_units();
-  gfx::Rect content_area = GetCenteredPageContentRect(
-      page_setup.physical_size(), page_size, page_content_rect);
+  const CGRect paper_rect = gfx::Rect(page_setup.physical_size()).ToCGRect();
 
-  struct Metafile::MacRenderPageParams params;
-  params.autorotate = true;
   size_t num_pages = expected_page_count();
   for (size_t metafile_page_number = 1; metafile_page_number <= num_pages;
        metafile_page_number++) {
     if (context->NewPage() != PrintingContext::OK)
       return false;
-    metafile->RenderPage(metafile_page_number, context->context(),
-                         content_area.ToCGRect(), params);
+    metafile->RenderPage(metafile_page_number, context->context(), paper_rect,
+                         /*autorotate=*/true, /*fit_to_page=*/false);
     if (context->PageDone() != PrintingContext::OK)
       return false;
   }
diff --git a/printing/test/data/pdf_cg/render_large_landscape_rectangles_expected.0.png b/printing/test/data/pdf_cg/render_large_landscape_rectangles_expected.0.png
index 20a70b2..a6ce0b6 100644
--- a/printing/test/data/pdf_cg/render_large_landscape_rectangles_expected.0.png
+++ b/printing/test/data/pdf_cg/render_large_landscape_rectangles_expected.0.png
Binary files differ
diff --git a/printing/test/data/pdf_cg/render_large_portrait_rectangles_expected.0.png b/printing/test/data/pdf_cg/render_large_portrait_rectangles_expected.0.png
index acaa3b5d..e84c60ef 100644
--- a/printing/test/data/pdf_cg/render_large_portrait_rectangles_expected.0.png
+++ b/printing/test/data/pdf_cg/render_large_portrait_rectangles_expected.0.png
Binary files differ
diff --git a/printing/test/data/pdf_cg/render_scaled_large_landscape_rectangles_expected.0.png b/printing/test/data/pdf_cg/render_scaled_large_landscape_rectangles_expected.0.png
new file mode 100644
index 0000000..853da05
--- /dev/null
+++ b/printing/test/data/pdf_cg/render_scaled_large_landscape_rectangles_expected.0.png
Binary files differ
diff --git a/printing/test/data/pdf_cg/render_scaled_small_landscape_rectangles_expected.0.png b/printing/test/data/pdf_cg/render_scaled_small_landscape_rectangles_expected.0.png
new file mode 100644
index 0000000..e6b7874
--- /dev/null
+++ b/printing/test/data/pdf_cg/render_scaled_small_landscape_rectangles_expected.0.png
Binary files differ
diff --git a/printing/test/data/pdf_cg/render_small_landscape_rectangles_expected.0.png b/printing/test/data/pdf_cg/render_small_landscape_rectangles_expected.0.png
index d638aad..9e1fe5b 100644
--- a/printing/test/data/pdf_cg/render_small_landscape_rectangles_expected.0.png
+++ b/printing/test/data/pdf_cg/render_small_landscape_rectangles_expected.0.png
Binary files differ
diff --git a/printing/test/data/pdf_cg/render_small_portrait_rectangles_expected.0.png b/printing/test/data/pdf_cg/render_small_portrait_rectangles_expected.0.png
index e535f29..a0aa5d6 100644
--- a/printing/test/data/pdf_cg/render_small_portrait_rectangles_expected.0.png
+++ b/printing/test/data/pdf_cg/render_small_portrait_rectangles_expected.0.png
Binary files differ
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom
index 75bc4ea..797d8c6 100644
--- a/services/network/public/mojom/network_context.mojom
+++ b/services/network/public/mojom/network_context.mojom
@@ -772,10 +772,14 @@
   //
   // If |is_service_worker| is false, |process_id| and |routing_id| identify
   // the relevant frame.
+  //
+  // |devtools_request_id| contains the DevTools request id of the request
+  // that triggered the cookie change, if the change was triggered by a request.
+  // May be set regardless of |is_service_worker|.
   OnCookiesChanged(
       bool is_service_worker, int32 process_id, int32 routing_id,
       url.mojom.Url url, SiteForCookies site_for_cookies,
-      array<CookieWithStatus> cookie_list);
+      array<CookieWithStatus> cookie_list, string? devtools_request_id);
 
   // Called when an attempt has been made to read the cookies in |cookie_list|,
   // with the status indicating whether the cookies were actually used or
@@ -794,10 +798,14 @@
   //
   // If |is_service_worker| is false, |process_id| and |routing_id| identify
   // the relevant frame.
+  //
+  // |devtools_request_id| contains the DevTools request id of the request
+  // that triggered the cookie change, if the read was triggered by a request.
+  // May be set regardless of |is_service_worker|.
   OnCookiesRead(
       bool is_service_worker, int32 process_id, int32 routing_id,
       url.mojom.Url url, SiteForCookies site_for_cookies,
-      array<CookieWithStatus> cookie_list);
+      array<CookieWithStatus> cookie_list, string? devtools_request_id);
 
   // Called to generate an auth token for SPNEGO authentication on Android.
   [EnableIf=is_android]
diff --git a/services/network/restricted_cookie_manager.cc b/services/network/restricted_cookie_manager.cc
index b0da2ec..e94ee3b 100644
--- a/services/network/restricted_cookie_manager.cc
+++ b/services/network/restricted_cookie_manager.cc
@@ -296,7 +296,7 @@
   if (network_context_client_) {
     network_context_client_->OnCookiesRead(is_service_worker_, process_id_,
                                            frame_id_, url, site_for_cookies,
-                                           result_with_status);
+                                           result_with_status, base::nullopt);
   }
 
   if (blocked) {
@@ -349,7 +349,7 @@
           {cookie, status}};
       network_context_client_->OnCookiesChanged(
           is_service_worker_, process_id_, frame_id_, url, site_for_cookies,
-          result_with_status);
+          result_with_status, base::nullopt);
     }
     std::move(callback).Run(false);
     return;
@@ -397,7 +397,7 @@
       notify.push_back({cookie, status});
       network_context_client_->OnCookiesChanged(
           is_service_worker_, process_id_, frame_id_, url, site_for_cookies,
-          std::move(notify));
+          std::move(notify), base::nullopt);
     }
   }
   std::move(user_callback).Run(status.IsInclude());
diff --git a/services/network/restricted_cookie_manager_unittest.cc b/services/network/restricted_cookie_manager_unittest.cc
index e83a45c6..e3d24e5 100644
--- a/services/network/restricted_cookie_manager_unittest.cc
+++ b/services/network/restricted_cookie_manager_unittest.cc
@@ -45,10 +45,11 @@
     // one thing.
     std::vector<net::CanonicalCookie> cookie;
     net::CanonicalCookie::CookieInclusionStatus status;
+    base::Optional<std::string> devtools_request_id;
   };
 
-  RecordingNetworkContextClient() {}
-  ~RecordingNetworkContextClient() override {}
+  RecordingNetworkContextClient() = default;
+  ~RecordingNetworkContextClient() override = default;
 
   const std::vector<CookieOp>& recorded_activity() const {
     return recorded_activity_;
@@ -60,7 +61,8 @@
       int32_t routing_id,
       const GURL& url,
       const net::SiteForCookies& site_for_cookies,
-      const std::vector<net::CookieWithStatus>& cookie_list) override {
+      const std::vector<net::CookieWithStatus>& cookie_list,
+      const base::Optional<std::string>& devtools_request_id) override {
     EXPECT_EQ(false, is_service_worker);
     EXPECT_EQ(kProcessId, process_id);
     EXPECT_EQ(kRoutingId, routing_id);
@@ -70,6 +72,7 @@
       set.site_for_cookies = site_for_cookies.RepresentativeUrl();
       set.cookie.push_back(cookie_and_status.cookie);
       set.status = cookie_and_status.status;
+      set.devtools_request_id = devtools_request_id;
       recorded_activity_.push_back(set);
     }
   }
@@ -80,7 +83,8 @@
       int32_t routing_id,
       const GURL& url,
       const net::SiteForCookies& site_for_cookies,
-      const std::vector<net::CookieWithStatus>& cookie_list) override {
+      const std::vector<net::CookieWithStatus>& cookie_list,
+      const base::Optional<std::string>& devtools_request_id) override {
     EXPECT_EQ(false, is_service_worker);
     EXPECT_EQ(kProcessId, process_id);
     EXPECT_EQ(kRoutingId, routing_id);
@@ -91,6 +95,7 @@
       get.site_for_cookies = site_for_cookies.RepresentativeUrl();
       get.cookie.push_back(cookie_and_status.cookie);
       get.status = cookie_and_status.status;
+      get.devtools_request_id = devtools_request_id;
       recorded_activity_.push_back(get);
     }
   }
diff --git a/services/network/test/test_network_context_client.h b/services/network/test/test_network_context_client.h
index a70a9f62..6eeedade 100644
--- a/services/network/test/test_network_context_client.h
+++ b/services/network/test/test_network_context_client.h
@@ -75,14 +75,16 @@
       int32_t routing_id,
       const GURL& url,
       const net::SiteForCookies& site_for_cookies,
-      const std::vector<net::CookieWithStatus>& cookie_list) override {}
+      const std::vector<net::CookieWithStatus>& cookie_list,
+      const base::Optional<std::string>& devtools_request_id) override {}
   void OnCookiesRead(
       bool is_service_worker,
       int32_t process_id,
       int32_t routing_id,
       const GURL& url,
       const net::SiteForCookies& site_for_cookies,
-      const std::vector<net::CookieWithStatus>& cookie_list) override {}
+      const std::vector<net::CookieWithStatus>& cookie_list,
+      const base::Optional<std::string>& devtools_request_id) override {}
 #if defined(OS_ANDROID)
   void OnGenerateHttpNegotiateAuthToken(
       const std::string& server_auth_token,
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index 4bb0a62e..c69610b 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -1737,7 +1737,7 @@
       network_context_client_->OnCookiesRead(
           /* is_service_worker = */ false, GetProcessId(), GetRenderFrameId(),
           url_request_->url(), url_request_->site_for_cookies(),
-          reported_cookies);
+          reported_cookies, devtools_request_id());
     }
   }
 
@@ -1951,7 +1951,7 @@
       network_context_client_->OnCookiesChanged(
           /* is_service_worker = */ false, GetProcessId(), GetRenderFrameId(),
           url_request_->url(), url_request_->site_for_cookies(),
-          reported_cookies);
+          reported_cookies, devtools_request_id());
     }
   }
 }
diff --git a/services/network/url_loader_unittest.cc b/services/network/url_loader_unittest.cc
index afcb65d..92c64ff 100644
--- a/services/network/url_loader_unittest.cc
+++ b/services/network/url_loader_unittest.cc
@@ -2779,7 +2779,8 @@
       int32_t routing_id,
       const GURL& url,
       const net::SiteForCookies& site_for_cookies,
-      const std::vector<net::CookieWithStatus>& cookie_list) override {
+      const std::vector<net::CookieWithStatus>& cookie_list,
+      const base::Optional<std::string>& devtools_request_id) override {
     for (const auto& cookie_and_status : cookie_list) {
       reported_response_cookies_.push_back(
           CookieInfo(url, site_for_cookies.RepresentativeUrl(),
@@ -2798,7 +2799,8 @@
       int32_t routing_id,
       const GURL& url,
       const net::SiteForCookies& site_for_cookies,
-      const std::vector<net::CookieWithStatus>& cookie_list) override {
+      const std::vector<net::CookieWithStatus>& cookie_list,
+      const base::Optional<std::string>& devtools_request_id) override {
     for (const auto& cookie_and_status : cookie_list) {
       reported_request_cookies_.push_back(
           CookieInfo(url, site_for_cookies.RepresentativeUrl(),
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index 23b4e608..3c8ffdd 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -211,10 +211,6 @@
 // Staging for lowp::bilerp_clamp_8888, and for planned misc. others.
 #define SK_DISABLE_LOWP_BILERP_CLAMP_CLAMP_STAGE
 
-#ifndef SK_SUPPORT_LEGACY_DIDCONCAT44
-#define SK_SUPPORT_LEGACY_DIDCONCAT44
-#endif
-
 ///////////////////////// Imported from BUILD.gn and skia_common.gypi
 
 /* In some places Skia can use static initializers for global initialization,
diff --git a/skia/ext/benchmarking_canvas.cc b/skia/ext/benchmarking_canvas.cc
index efff1c2..81607e8 100644
--- a/skia/ext/benchmarking_canvas.cc
+++ b/skia/ext/benchmarking_canvas.cc
@@ -428,9 +428,11 @@
   INHERITED::willRestore();
 }
 
-void BenchmarkingCanvas::didConcat44(const SkScalar m[16]) {
+void BenchmarkingCanvas::didConcat44(const SkM44& m) {
+  SkScalar values[16];
+  m.getColMajor(values);
   AutoOp op(this, "Concat44");
-  op.addParam("column-major", AsListValue(m, 16));
+  op.addParam("column-major", AsListValue(values, 16));
 
   INHERITED::didConcat44(m);
 }
diff --git a/skia/ext/benchmarking_canvas.h b/skia/ext/benchmarking_canvas.h
index cb52c42..fed7cd5 100644
--- a/skia/ext/benchmarking_canvas.h
+++ b/skia/ext/benchmarking_canvas.h
@@ -32,7 +32,7 @@
   SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override;
   void willRestore() override;
 
-  void didConcat44(const SkScalar[16]) override;
+  void didConcat44(const SkM44&) override;
   void didConcat(const SkMatrix&) override;
   void didScale(SkScalar, SkScalar) override;
   void didTranslate(SkScalar, SkScalar) override;
diff --git a/third_party/blink/common/scheduler/web_scheduler_tracked_feature.cc b/third_party/blink/common/scheduler/web_scheduler_tracked_feature.cc
index 0a2446b..771b0b1 100644
--- a/third_party/blink/common/scheduler/web_scheduler_tracked_feature.cc
+++ b/third_party/blink/common/scheduler/web_scheduler_tracked_feature.cc
@@ -89,6 +89,10 @@
       return "WebNfc";
     case WebSchedulerTrackedFeature::kWebFileSystem:
       return "WebFileSystem";
+    case WebSchedulerTrackedFeature::kAppBanner:
+      return "AppBanner";
+    case WebSchedulerTrackedFeature::kPrinting:
+      return "Printing";
   }
 }
 
diff --git a/third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h b/third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h
index ba38906..a71ad8cb 100644
--- a/third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h
+++ b/third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h
@@ -84,8 +84,11 @@
   kOutstandingNetworkRequestFetch = 40,
   kOutstandingNetworkRequestXHR = 41,
 
+  kAppBanner = 42,
+  kPrinting = 43,
+
   // NB: This enum is used in a bitmask, so kMaxValue must be less than 64.
-  kMaxValue = kOutstandingNetworkRequestXHR,
+  kMaxValue = kPrinting
 };
 
 static_assert(static_cast<uint32_t>(WebSchedulerTrackedFeature::kMaxValue) < 64,
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
index f444e47..18c7020f 100644
--- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl
+++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -454,9 +454,13 @@
       string name
       string path
       string domain
-      # Optionally identifies the site-for-cookies, which may be used by the
-      # front-end as additional context.
-      optional string siteForCookies
+
+  # Information about a request that is affected by an inspector issue.
+  type AffectedRequest extends object
+    properties
+      # The unique request id.
+      Network.RequestId requestId
+      optional string url
 
   type SameSiteCookieExclusionReason extends string
     enum
@@ -475,29 +479,36 @@
       WarnSameSiteCrossSchemeInsecureUrlLax
       WarnSameSiteCrossSchemeInsecureUrlStrict
 
+  type SameSiteCookieOperation extends string
+    enum
+      SetCookie
+      ReadCookie
+
   # This information is currently necessary, as the front-end has a difficult
   # time finding a specific cookie. With this, we can convey specific error
   # information without the cookie.
   type SameSiteCookieIssueDetails extends object
     properties
+      AffectedCookie cookie
       array of SameSiteCookieWarningReason cookieWarningReasons
       array of SameSiteCookieExclusionReason cookieExclusionReasons
-
-  type AffectedResources extends object
-    properties
-      optional array of AffectedCookie cookies
+      # Optionally identifies the site-for-cookies and the cookie url, which
+      # may be used by the front-end as additional context.
+      SameSiteCookieOperation operation
+      optional string siteForCookies
+      optional string cookieUrl
+      optional AffectedRequest request
 
   # A unique identifier for the type of issue. Each type may use one of the
   # optional fields in InspectorIssueDetails to convey more specific
-  # information about the kind of issue, and AffectedResources to identify
-  # resources that are affected by this issue.
+  # information about the kind of issue.
   type InspectorIssueCode extends string
     enum
       SameSiteCookieIssue
 
   # This struct holds a list of optional fields with additional information
-  # pertaining to the kind of issue. This is useful if there is a number of
-  # very similar issues that only differ in details.
+  # specific to the kind of issue. When adding a new issue code, please also
+  # add a new optional field to this type.
   type InspectorIssueDetails extends object
     properties
       optional SameSiteCookieIssueDetails sameSiteCookieIssueDetails
@@ -507,7 +518,6 @@
     properties
       InspectorIssueCode code
       InspectorIssueDetails details
-      AffectedResources resources
 
   # Returns the response body and size if it were re-encoded with the specified settings. Only
   # applies to images.
diff --git a/third_party/blink/public/mojom/devtools/inspector_issue.mojom b/third_party/blink/public/mojom/devtools/inspector_issue.mojom
index 296fe74..3a32524e 100644
--- a/third_party/blink/public/mojom/devtools/inspector_issue.mojom
+++ b/third_party/blink/public/mojom/devtools/inspector_issue.mojom
@@ -18,12 +18,15 @@
   string name;
   string path;
   string domain;
-  url.mojom.Url? site_for_cookies;
 };
 
-// The resources affected by an InspectorIssue.
-struct AffectedResources {
-  array<AffectedCookie> cookies;
+struct AffectedRequest {
+  string request_id;
+  string? url;
+};
+
+enum SameSiteCookieOperation {
+  SetCookie, ReadCookie
 };
 
 enum SameSiteCookieExclusionReason {
@@ -45,8 +48,13 @@
 
 // Specific information about |kSameSiteCookieIssue| type issues.
 struct SameSiteCookieIssueDetails {
+  AffectedCookie cookie;
   array<SameSiteCookieExclusionReason> exclusionReason;
   array<SameSiteCookieWarningReason> warningReason;
+  SameSiteCookieOperation operation;
+  url.mojom.Url? site_for_cookies;
+  url.mojom.Url? cookie_url;
+  AffectedRequest? request;
 };
 
 // A collection of optional fields that may store additional data depending
@@ -58,5 +66,4 @@
 struct InspectorIssueInfo {
   InspectorIssueCode code;
   InspectorIssueDetails details;
-  AffectedResources resources;
 };
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
index 9795640..d8226fe9 100644
--- a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
+++ b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
@@ -1987,6 +1987,27 @@
         EmptyNode(),
     ])
 
+    if "Global" in cg_context.interface.extended_attributes:
+        body.append(
+            TextNode("""\
+// 7.4.8 [[Set]] ( P, V, Receiver )
+// https://html.spec.whatwg.org/C/#windowproxy-set
+// step 2. If ! IsPlatformObjectSameOrigin(W) is true, then return
+//   ? OrdinarySet(this, P, V, Receiver).
+//
+// 7.4.6 [[DefineOwnProperty]] ( P, Desc )
+// https://html.spec.whatwg.org/C/#windowproxy-defineownproperty
+// step 2.1. If P is an array index property name, return false.
+bindings::V8SetReturnValue(${info}, nullptr);
+if (${info}.ShouldThrowOnError()) {
+  ExceptionState exception_state(${info}.GetIsolate(),
+                                 ExceptionState::kIndexedSetterContext,
+                                 "${interface.identifier}");
+  exception_state.ThrowTypeError(
+      "Indexed property setter is not supported.");
+}"""))
+        return func_decl, func_def
+
     if not cg_context.indexed_property_setter:
         body.append(
             TextNode("""\
@@ -2135,6 +2156,25 @@
     body.extend([
         make_runtime_call_timer_scope(cg_context, "IndexedPropertyDefiner"),
         EmptyNode(),
+    ])
+
+    if "Global" in cg_context.interface.extended_attributes:
+        body.append(
+            TextNode("""\
+// 7.4.6 [[DefineOwnProperty]] ( P, Desc )
+// https://html.spec.whatwg.org/C/#windowproxy-defineownproperty
+// step 2.1. If P is an array index property name, return false.
+bindings::V8SetReturnValue(${info}, nullptr);
+if (${info}.ShouldThrowOnError()) {
+  ExceptionState exception_state(${info}.GetIsolate(),
+                                 ExceptionState::kIndexedSetterContext,
+                                 "${interface.identifier}");
+  exception_state.ThrowTypeError(
+      "Indexed property setter is not supported.");
+}"""))
+        return func_decl, func_def
+
+    body.append(
         TextNode("""\
 // 3.8.3. [[DefineOwnProperty]]
 // https://heycam.github.io/webidl/#legacy-platform-object-defineownproperty
@@ -2150,8 +2190,7 @@
   }
   return;
 }
-"""),
-    ])
+"""))
 
     if not cg_context.interface.indexed_and_named_properties.indexed_setter:
         body.append(
@@ -2401,6 +2440,13 @@
         EmptyNode(),
     ])
 
+    if "Global" in cg_context.interface.extended_attributes:
+        body.append(
+            TextNode("""\
+// Do not intercept.  Fallback to the default behavior.\
+"""))
+        return func_decl, func_def
+
     if not cg_context.named_property_setter:
         body.append(
             TextNode("""\
@@ -2517,6 +2563,21 @@
         EmptyNode(),
     ])
 
+    if "Global" in cg_context.interface.extended_attributes:
+        body.append(
+            TextNode("""\
+// 3.6.4.3. [[Delete]]
+// https://heycam.github.io/webidl/#named-properties-object-delete
+// step 1. Return false.
+bindings::V8SetReturnValue(${info}, false);
+if (${info}.ShouldThrowOnError()) {
+  ExceptionState exception_state(${info}.GetIsolate(),
+                                 ExceptionState::kDeletionContext,
+                                 "${interface.identifier}");
+  exception_state.ThrowTypeError("Named property deleter is not supported.");
+}"""))
+        return func_decl, func_def
+
     props = cg_context.interface.indexed_and_named_properties
     if (not cg_context.named_property_deleter
             and "NotEnumerable" in props.named_getter.extended_attributes):
@@ -2629,14 +2690,28 @@
     body.extend([
         make_runtime_call_timer_scope(cg_context, "NamedPropertyDefiner"),
         EmptyNode(),
-        TextNode("""\
-// 3.8.3. [[DefineOwnProperty]]
-// https://heycam.github.io/webidl/#legacy-platform-object-defineownproperty\
-"""),
     ])
+
+    if "Global" in cg_context.interface.extended_attributes:
+        body.append(
+            TextNode("""\
+// 3.6.4.2. [[DefineOwnProperty]]
+// https://heycam.github.io/webidl/#named-properties-object-defineownproperty
+// step 1. Return false.
+bindings::V8SetReturnValue(${info}, nullptr);
+if (${info}.ShouldThrowOnError()) {
+  ExceptionState exception_state(${info}.GetIsolate(),
+                                 ExceptionState::kSetterContext,
+                                 "${interface.identifier}");
+  exception_state.ThrowTypeError("Named property setter is not supported.");
+}"""))
+        return func_decl, func_def
+
     if not cg_context.interface.indexed_and_named_properties.named_setter:
         body.append(
             TextNode("""\
+// 3.8.3. [[DefineOwnProperty]]
+// https://heycam.github.io/webidl/#legacy-platform-object-defineownproperty
 // step 2.1. Let creating be true if P is not a supported property name, and
 //   false otherwise.
 // step 2.2.1. If creating is false and O does not implement an interface
@@ -2659,6 +2734,8 @@
     else:
         body.append(
             TextNode("""\
+// 3.8.3. [[DefineOwnProperty]]
+// https://heycam.github.io/webidl/#legacy-platform-object-defineownproperty
 // step 2.2.2. If O implements an interface with a named property setter,
 //   then:
 // step 2.2.2.1. If the result of calling IsDataDescriptor(Desc) is false,
@@ -2714,7 +2791,29 @@
         EmptyNode(),
     ])
 
-    pattern = """\
+    if "Global" in cg_context.interface.extended_attributes:
+        pattern = """\
+// 3.6.4.1. [[GetOwnProperty]]
+// https://heycam.github.io/webidl/#named-properties-object-getownproperty
+// step 4. If the result of running the named property visibility algorithm
+//   with property name P and object object is true, then:
+// step 5. Return OrdinaryGetOwnProperty(O, P).
+${class_name}::NamedPropertyGetterCallback(${v8_property_name}, ${info});
+v8::Local<v8::Value> v8_value = ${info}.GetReturnValue().Get();
+if (v8_value->IsUndefined())
+  return;  // Do not intercept.  Fallback to OrdinaryGetOwnProperty.
+
+// step 7. If A implements an interface with the
+//   [LegacyUnenumerableNamedProperties] extended attribute, then set
+//   desc.[[Enumerable]] to false, otherwise set it to true.
+// step 8. Set desc.[[Writable]] to true and desc.[[Configurable]] to true.
+v8::PropertyDescriptor desc(v8_value, /*writable=*/true);
+desc.set_enumerable({cxx_enumerable});
+desc.set_configurable(true);
+bindings::V8SetReturnValue(${info}, desc);\
+"""
+    else:
+        pattern = """\
 // LegacyPlatformObjectGetOwnProperty
 // https://heycam.github.io/webidl/#LegacyPlatformObjectGetOwnProperty
 // step 2.1.3. If operation was defined without an identifier, then set
@@ -2743,7 +2842,8 @@
 v8::PropertyDescriptor desc(v8_value, /*writable=*/{cxx_writable});
 desc.set_enumerable({cxx_enumerable});
 desc.set_configurable(true);
-bindings::V8SetReturnValue(${info}, desc);"""
+bindings::V8SetReturnValue(${info}, desc);\
+"""
     props = cg_context.interface.indexed_and_named_properties
     writable = bool(props.named_setter)
     cxx_writable = "true" if writable else "false"
@@ -4043,6 +4143,10 @@
     v8::Undefined(${isolate}),
     static_cast<v8::PropertyAttribute>(
         v8::ReadOnly | v8::DontEnum | v8::DontDelete));
+// 7.7.4.2 [[SetPrototypeOf]] ( V )
+// https://html.spec.whatwg.org/C/#location-setprototypeof
+${instance_template}->SetImmutableProto();
+${prototype_template}->SetImmutableProto();
 """))
 
     if indexed_and_named_property_install_nodes:
@@ -4076,17 +4180,24 @@
     V8AtomicString(${isolate}, "forEach"), v8::kArrayProto_forEach, v8::None);
 """))
 
-    if ("Global" in cg_context.class_like.extended_attributes
-            or cg_context.class_like.identifier == "Location"):
-        if "Global" in cg_context.class_like.extended_attributes:
-            body.append(T("// [Global]"))
-        if cg_context.class_like.identifier == "Location":
-            body.append(T("// Location exotic object"))
-        body.extend([
-            T("${instance_template}->SetImmutableProto();"),
-            T("${prototype_template}->SetImmutableProto();"),
-            EmptyNode(),
-        ])
+    if "Global" in cg_context.class_like.extended_attributes:
+        body.append(
+            TextNode("""\
+// [Global]
+// 3.7.1. [[SetPrototypeOf]]
+// https://heycam.github.io/webidl/#platform-object-setprototypeof
+${instance_template}->SetImmutableProto();
+${prototype_template}->SetImmutableProto();
+"""))
+    elif any("Global" in derived.extended_attributes
+             for derived in cg_context.class_like.deriveds):
+        body.append(
+            TextNode("""\
+// [Global] - prototype object in the prototype chain of global objects
+// 3.7.1. [[SetPrototypeOf]]
+// https://heycam.github.io/webidl/#platform-object-setprototypeof
+${prototype_template}->SetImmutableProto();
+"""))
 
     func_call_pattern = ("{}(${isolate}, ${world}, ${instance_template}, "
                          "${prototype_template}, ${interface_template});")
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py b/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py
index 65d5f4d..0a53592e 100644
--- a/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py
+++ b/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py
@@ -391,6 +391,8 @@
 
         self._ir_map.move_to_new_phase()
 
+        identifier_to_derived_set = {}
+
         for old_interface in old_interfaces.values():
             new_interface = make_copy(old_interface)
             self._ir_map.add(new_interface)
@@ -413,6 +415,17 @@
                     if is_own_member(operation)
                 ])
 
+                identifier_to_derived_set.setdefault(
+                    interface.identifier, set()).add(new_interface.identifier)
+
+        for new_interface in self._ir_map.irs_of_kind(IRMap.IR.Kind.INTERFACE):
+            assert not new_interface.deriveds
+            derived_set = identifier_to_derived_set.get(
+                new_interface.identifier, set())
+            new_interface.deriveds = map(
+                lambda id_: self._ref_to_idl_def_factory.create(id_),
+                sorted(derived_set))
+
     def _supplement_missing_html_constructor_operation(self):
         # Temporary mitigation of misuse of [HTMLConstructor]
         # https://html.spec.whatwg.org/C/#htmlconstructor
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/interface.py b/third_party/blink/renderer/bindings/scripts/web_idl/interface.py
index ae67aab..4759c6fd 100644
--- a/third_party/blink/renderer/bindings/scripts/web_idl/interface.py
+++ b/third_party/blink/renderer/bindings/scripts/web_idl/interface.py
@@ -107,6 +107,7 @@
             self.is_partial = is_partial
             self.is_mixin = is_mixin
             self.inherited = inherited
+            self.deriveds = []
             self.attributes = list(attributes)
             self.constants = list(constants)
             self.constructors = list(constructors)
@@ -149,6 +150,7 @@
 
         self._is_mixin = ir.is_mixin
         self._inherited = ir.inherited
+        self._deriveds = tuple(ir.deriveds)
         self._attributes = tuple([
             Attribute(attribute_ir, owner=self)
             for attribute_ir in ir.attributes
@@ -229,6 +231,11 @@
         return self._inherited.target_object if self._inherited else None
 
     @property
+    def deriveds(self):
+        """Returns the list of the derived interfaces."""
+        return tuple(map(lambda ref: ref.target_object, self._deriveds))
+
+    @property
     def inclusive_inherited_interfaces(self):
         """
         Returns the list of inclusive inherited interfaces.
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/namespace.py b/third_party/blink/renderer/bindings/scripts/web_idl/namespace.py
index c83a37f..0c3b2ef 100644
--- a/third_party/blink/renderer/bindings/scripts/web_idl/namespace.py
+++ b/third_party/blink/renderer/bindings/scripts/web_idl/namespace.py
@@ -115,6 +115,11 @@
         return None
 
     @property
+    def deriveds(self):
+        """Returns the list of the derived namespaces."""
+        return ()
+
+    @property
     def attributes(self):
         """Returns attributes."""
         return self._attributes
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
index b336c49b..d03c887b 100644
--- a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
@@ -1834,11 +1834,6 @@
       has_root_font_units, absolutized, g_null_atom, WTF::TextEncoding());
 }
 
-const CSSToLengthConversionData&
-StyleBuilderConverter::CssToLengthConversionData(StyleResolverState& state) {
-  return state.CssToLengthConversionData();
-}
-
 LengthSize StyleBuilderConverter::ConvertIntrinsicSize(
     StyleResolverState& state,
     const CSSValue& value) {
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_converter.h b/third_party/blink/renderer/core/css/resolver/style_builder_converter.h
index d81b234..98921c52 100644
--- a/third_party/blink/renderer/core/css/resolver/style_builder_converter.h
+++ b/third_party/blink/renderer/core/css/resolver/style_builder_converter.h
@@ -280,17 +280,13 @@
                                              const CSSValue& value);
 
   static AtomicString ConvertPage(StyleResolverState&, const CSSValue&);
-
- private:
-  static const CSSToLengthConversionData& CssToLengthConversionData(
-      StyleResolverState&);
 };
 
 template <typename T>
 T StyleBuilderConverter::ConvertComputedLength(StyleResolverState& state,
                                                const CSSValue& value) {
   return To<CSSPrimitiveValue>(value).ComputeLength<T>(
-      CssToLengthConversionData(state));
+      state.CssToLengthConversionData());
 }
 
 template <typename T>
@@ -327,7 +323,7 @@
   // device pixels or zoom adjusted CSS pixels instead of raw CSS pixels.
   // Reference crbug.com/485650 and crbug.com/382483
   double result =
-      primitive_value.ComputeLength<double>(CssToLengthConversionData(state));
+      primitive_value.ComputeLength<double>(state.CssToLengthConversionData());
   double zoomed_result = state.StyleRef().EffectiveZoom() * result;
   if (zoomed_result > 0.0 && zoomed_result < 1.0)
     return 1.0;
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 8e0e2dd..49c51f6 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -2432,6 +2432,11 @@
     AtomicString old_id = GetElementData()->IdForStyleResolution();
     AtomicString new_id = MakeIdForStyleResolution(
         params.new_value, GetDocument().InQuirksMode());
+    // Treat empty IDs the same way as nonexistent ID, per
+    // https://dom.spec.whatwg.org/#concept-id.
+    if (new_id.IsEmpty()) {
+      new_id = g_null_atom;
+    }
     if (new_id != old_id) {
       GetElementData()->SetIdForStyleResolution(new_id);
       GetDocument().GetStyleEngine().IdChangedForElement(old_id, new_id, *this);
diff --git a/third_party/blink/renderer/core/dom/element.h b/third_party/blink/renderer/core/dom/element.h
index 541b0321..84fdc7a 100644
--- a/third_party/blink/renderer/core/dom/element.h
+++ b/third_party/blink/renderer/core/dom/element.h
@@ -1299,7 +1299,17 @@
 }
 
 inline const AtomicString& Element::GetIdAttribute() const {
-  return HasID() ? FastGetAttribute(html_names::kIdAttr) : g_null_atom;
+  // Note: HasID() can return false even if the id attribute exists. This
+  // happens when the attribute value is empty, which per spec is equivalent to
+  // not having an id attribute at all:
+  // https://dom.spec.whatwg.org/#concept-id. On the other hand, if HasID()
+  // returns true then there must be a non-empty id attribute.
+  if (HasID()) {
+    const AtomicString& attr_value = FastGetAttribute(html_names::kIdAttr);
+    DCHECK(!attr_value.IsEmpty());
+    return attr_value;
+  }
+  return g_null_atom;
 }
 
 inline const AtomicString& Element::GetNameAttribute() const {
diff --git a/third_party/blink/renderer/core/dom/tree_scope.cc b/third_party/blink/renderer/core/dom/tree_scope.cc
index f1aef84..7855cb5 100644
--- a/third_party/blink/renderer/core/dom/tree_scope.cc
+++ b/third_party/blink/renderer/core/dom/tree_scope.cc
@@ -110,7 +110,9 @@
 }
 
 Element* TreeScope::getElementById(const AtomicString& element_id) const {
-  if (element_id.IsEmpty())
+  // |element_id| can never be null for calls that originated from JavaScript,
+  // but sometimes other C++ code can call this function with g_null_atom.
+  if (element_id.IsNull())
     return nullptr;
   if (!elements_by_id_)
     return nullptr;
diff --git a/third_party/blink/renderer/core/frame/csp/navigation_initiator_impl.cc b/third_party/blink/renderer/core/frame/csp/navigation_initiator_impl.cc
index bce1d06..c9bdc143 100644
--- a/third_party/blink/renderer/core/frame/csp/navigation_initiator_impl.cc
+++ b/third_party/blink/renderer/core/frame/csp/navigation_initiator_impl.cc
@@ -14,7 +14,7 @@
 namespace blink {
 
 NavigationInitiatorImpl::NavigationInitiatorImpl(Document& document)
-    : navigation_initiator_receivers_(document.GetExecutionContext()),
+    : navigation_initiator_receivers_(this, document.GetExecutionContext()),
       document_(document) {
   DCHECK(document.GetExecutionContext());
 }
@@ -50,8 +50,7 @@
 void NavigationInitiatorImpl::BindReceiver(
     mojo::PendingReceiver<mojom::blink::NavigationInitiator> receiver) {
   navigation_initiator_receivers_.Add(
-      this, std::move(receiver),
-      document_->GetTaskRunner(TaskType::kNetworking));
+      std::move(receiver), document_->GetTaskRunner(TaskType::kNetworking));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/csp/navigation_initiator_impl.h b/third_party/blink/renderer/core/frame/csp/navigation_initiator_impl.h
index 7a9e2f7c..5516abd 100644
--- a/third_party/blink/renderer/core/frame/csp/navigation_initiator_impl.h
+++ b/third_party/blink/renderer/core/frame/csp/navigation_initiator_impl.h
@@ -35,6 +35,7 @@
   // document. Used to report CSP violations that result from CSP blocking
   // navigation requests that were initiated by the owner document.
   HeapMojoReceiverSet<mojom::blink::NavigationInitiator,
+                      NavigationInitiatorImpl,
                       HeapMojoWrapperMode::kWithoutContextObserver>
       navigation_initiator_receivers_;
 
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
index 2660078..e4f4ed4 100644
--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
+++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
@@ -254,6 +254,7 @@
 #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
 #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
+#include "third_party/blink/renderer/platform/scheduler/public/scheduling_policy.h"
 #include "third_party/blink/renderer/platform/text/text_direction.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
@@ -1491,6 +1492,11 @@
   is_in_printing_ = true;
 #endif
 
+  // Disable BackForwardCache when printing API is used.
+  GetFrame()->GetFrameScheduler()->RegisterStickyFeature(
+      blink::SchedulingPolicy::Feature::kPrinting,
+      {blink::SchedulingPolicy::RecordMetricsForBackForwardCache()});
+
   GetFrame()->GetDocument()->SetPrinting(Document::kBeforePrinting);
   DispatchPrintEventRecursively(event_type_names::kBeforeprint);
 }
@@ -2497,8 +2503,7 @@
     mojom::blink::InspectorIssueCode code) {
   DCHECK(GetFrame());
   auto info = mojom::blink::InspectorIssueInfo::New(
-      code, mojom::blink::InspectorIssueDetails::New(),
-      mojom::blink::AffectedResources::New());
+      code, mojom::blink::InspectorIssueDetails::New());
   GetFrame()->GetDocument()->AddInspectorIssue(
       InspectorIssue::Create(std::move(info)));
 }
diff --git a/third_party/blink/renderer/core/inspector/inspector_audits_agent.cc b/third_party/blink/renderer/core/inspector/inspector_audits_agent.cc
index 7dfae51..3b959d2 100644
--- a/third_party/blink/renderer/core/inspector/inspector_audits_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_audits_agent.cc
@@ -153,21 +153,23 @@
 }
 
 namespace {
-std::unique_ptr<protocol::Array<protocol::Audits::AffectedCookie>> BuildCookies(
-    const WTF::Vector<mojom::blink::AffectedCookiePtr>& cookies) {
-  auto result =
-      std::make_unique<protocol::Array<protocol::Audits::AffectedCookie>>();
-  for (const auto& cookie : cookies) {
-    auto protocol_cookie = std::move(protocol::Audits::AffectedCookie::create()
-                                         .setName(cookie->name)
-                                         .setPath(cookie->path)
-                                         .setDomain(cookie->domain));
-    if (cookie->site_for_cookies) {
-      protocol_cookie.setSiteForCookies(*cookie->site_for_cookies);
-    }
-    result->push_back(protocol_cookie.build());
+std::unique_ptr<protocol::Audits::AffectedCookie> BuildAffectedCookie(
+    const mojom::blink::AffectedCookiePtr& cookie) {
+  auto protocol_cookie = std::move(protocol::Audits::AffectedCookie::create()
+                                       .setName(cookie->name)
+                                       .setPath(cookie->path)
+                                       .setDomain(cookie->domain));
+  return protocol_cookie.build();
+}
+std::unique_ptr<protocol::Audits::AffectedRequest> BuildAffectedRequest(
+    const mojom::blink::AffectedRequestPtr& request) {
+  auto protocol_request = protocol::Audits::AffectedRequest::create()
+                              .setRequestId(request->request_id)
+                              .build();
+  if (!request->url.IsEmpty()) {
+    protocol_request->setUrl(request->url);
   }
-  return result;
+  return protocol_request;
 }
 blink::protocol::String InspectorIssueCodeValue(
     mojom::blink::InspectorIssueCode code) {
@@ -257,32 +259,47 @@
   }
   return protocol_warning_reasons;
 }
+protocol::String BuildCookieOperation(
+    mojom::blink::SameSiteCookieOperation operation) {
+  switch (operation) {
+    case blink::mojom::blink::SameSiteCookieOperation::SetCookie:
+      return protocol::Audits::SameSiteCookieOperationEnum::SetCookie;
+    case blink::mojom::blink::SameSiteCookieOperation::ReadCookie:
+      return protocol::Audits::SameSiteCookieOperationEnum::ReadCookie;
+  }
+  NOTREACHED();
+  return "unknown";
+}
 }  // namespace
 
 void InspectorAuditsAgent::InspectorIssueAdded(InspectorIssue* issue) {
   auto issueDetails = protocol::Audits::InspectorIssueDetails::create();
 
-  if (issue->Details()->sameSiteCookieIssueDetails) {
+  if (const auto& d = issue->Details()->sameSiteCookieIssueDetails) {
     auto sameSiteCookieDetails =
-        protocol::Audits::SameSiteCookieIssueDetails::create()
-            .setCookieExclusionReasons(BuildCookieExclusionReasons(
-                issue->Details()->sameSiteCookieIssueDetails->exclusionReason))
-            .setCookieWarningReasons(BuildCookieWarningReasons(
-                issue->Details()->sameSiteCookieIssueDetails->warningReason))
-            .build();
-    issueDetails.setSameSiteCookieIssueDetails(
-        std::move(sameSiteCookieDetails));
-  }
+        std::move(protocol::Audits::SameSiteCookieIssueDetails::create()
+                      .setCookie(BuildAffectedCookie(d->cookie))
+                      .setCookieExclusionReasons(
+                          BuildCookieExclusionReasons(d->exclusionReason))
+                      .setCookieWarningReasons(
+                          BuildCookieWarningReasons(d->warningReason))
+                      .setOperation(BuildCookieOperation(d->operation)));
 
-  auto affectedResources =
-      protocol::Audits::AffectedResources::create()
-          .setCookies(BuildCookies(issue->Resources()->cookies))
-          .build();
+    if (d->site_for_cookies) {
+      sameSiteCookieDetails.setSiteForCookies(*d->site_for_cookies);
+    }
+    if (d->cookie_url) {
+      sameSiteCookieDetails.setCookieUrl(*d->cookie_url);
+    }
+    if (d->request) {
+      sameSiteCookieDetails.setRequest(BuildAffectedRequest(d->request));
+    }
+    issueDetails.setSameSiteCookieIssueDetails(sameSiteCookieDetails.build());
+  }
 
   auto inspector_issue = protocol::Audits::InspectorIssue::create()
                              .setCode(InspectorIssueCodeValue(issue->Code()))
                              .setDetails(issueDetails.build())
-                             .setResources(std::move(affectedResources))
                              .build();
 
   GetFrontend()->issueAdded(std::move(inspector_issue));
diff --git a/third_party/blink/renderer/core/inspector/inspector_issue.cc b/third_party/blink/renderer/core/inspector/inspector_issue.cc
index 93749eb..2c993d7f 100644
--- a/third_party/blink/renderer/core/inspector/inspector_issue.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_issue.cc
@@ -16,13 +16,9 @@
 namespace blink {
 
 InspectorIssue::InspectorIssue(mojom::blink::InspectorIssueCode code,
-                               mojom::blink::InspectorIssueDetailsPtr details,
-                               mojom::blink::AffectedResourcesPtr resources)
-    : code_(code),
-      details_(std::move(details)),
-      resources_(std::move(resources)) {
+                               mojom::blink::InspectorIssueDetailsPtr details)
+    : code_(code), details_(std::move(details)) {
   DCHECK(details_);
-  DCHECK(resources_);
 }
 
 InspectorIssue::~InspectorIssue() = default;
@@ -30,9 +26,8 @@
 InspectorIssue* InspectorIssue::Create(
     mojom::blink::InspectorIssueInfoPtr info) {
   DCHECK(info->details);
-  DCHECK(info->resources);
-  return MakeGarbageCollected<InspectorIssue>(
-      info->code, std::move(info->details), std::move(info->resources));
+  return MakeGarbageCollected<InspectorIssue>(info->code,
+                                              std::move(info->details));
 }
 
 mojom::blink::InspectorIssueCode InspectorIssue::Code() const {
@@ -43,10 +38,6 @@
   return details_;
 }
 
-const mojom::blink::AffectedResourcesPtr& InspectorIssue::Resources() const {
-  return resources_;
-}
-
 void InspectorIssue::Trace(blink::Visitor* visitor) {}
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/inspector/inspector_issue.h b/third_party/blink/renderer/core/inspector/inspector_issue.h
index a97cd2b..3dc9037 100644
--- a/third_party/blink/renderer/core/inspector/inspector_issue.h
+++ b/third_party/blink/renderer/core/inspector/inspector_issue.h
@@ -19,22 +19,19 @@
   InspectorIssue() = delete;
   InspectorIssue(mojom::blink::InspectorIssueCode code,
 
-                 mojom::blink::InspectorIssueDetailsPtr details,
-                 mojom::blink::AffectedResourcesPtr resources);
+                 mojom::blink::InspectorIssueDetailsPtr details);
   ~InspectorIssue();
 
   static InspectorIssue* Create(mojom::blink::InspectorIssueInfoPtr info);
 
   mojom::blink::InspectorIssueCode Code() const;
   const mojom::blink::InspectorIssueDetailsPtr& Details() const;
-  const mojom::blink::AffectedResourcesPtr& Resources() const;
 
   void Trace(Visitor*);
 
  private:
   mojom::blink::InspectorIssueCode code_;
   mojom::blink::InspectorIssueDetailsPtr details_;
-  mojom::blink::AffectedResourcesPtr resources_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/layout_details_marker.h b/third_party/blink/renderer/core/layout/layout_details_marker.h
index a2efcbff..e39df8ed 100644
--- a/third_party/blink/renderer/core/layout/layout_details_marker.h
+++ b/third_party/blink/renderer/core/layout/layout_details_marker.h
@@ -33,6 +33,8 @@
 
   Orientation GetOrientation() const;
 
+  bool CreatesNewFormattingContext() const override { return true; }
+
   const char* GetName() const override { return "LayoutDetailsMarker"; }
 
  private:
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_segment.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_segment.cc
index a0a671d..238c856 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_segment.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_segment.cc
@@ -143,15 +143,6 @@
   return Iterator(start_offset, end_offset, segment);
 }
 
-void NGInlineItemSegments::ComputeSegments(
-    RunSegmenter* segmenter,
-    RunSegmenter::RunSegmenterRange* range) {
-  segments_.Shrink(0);
-  do {
-    segments_.emplace_back(*range);
-  } while (segmenter->Consume(range));
-}
-
 unsigned NGInlineItemSegments::AppendMixedFontOrientation(
     const String& text_content,
     unsigned start_offset,
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_segment.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_segment.h
index f011dfa9..dd9e38af 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_segment.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_segment.h
@@ -88,10 +88,6 @@
     segments_.emplace_back(std::forward<Args>(args)...);
   }
 
-  // Compute segments from the given |RunSegmenter|.
-  void ComputeSegments(RunSegmenter* segmenter,
-                       RunSegmenter::RunSegmenterRange* range);
-
   // Append mixed-vertical font orientation segments for the specified range.
   // This is separated from |ComputeSegments| because this result depends on
   // fonts.
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 740ab5a2..fbfdfed 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
@@ -891,41 +891,85 @@
 
 // Segment NGInlineItem by script, Emoji, and orientation using RunSegmenter.
 void NGInlineNode::SegmentScriptRuns(NGInlineNodeData* data) {
+  DCHECK_EQ(data->segments, nullptr);
+
   String& text_content = data->text_content;
   if (text_content.IsEmpty()) {
-    data->segments = nullptr;
+    return;
+  }
+
+  Vector<NGInlineItem>& items = data->items;
+  if (items.IsEmpty()) {
     return;
   }
 
   if (text_content.Is8Bit() && !data->is_bidi_enabled_) {
-    if (data->items.size()) {
-      RunSegmenter::RunSegmenterRange range = {
-          0u, data->text_content.length(), USCRIPT_LATIN,
-          OrientationIterator::kOrientationKeep, FontFallbackPriority::kText};
-      NGInlineItem::SetSegmentData(range, &data->items);
-    }
-    data->segments = nullptr;
+    RunSegmenter::RunSegmenterRange range = {
+        0u, data->text_content.length(), USCRIPT_LATIN,
+        OrientationIterator::kOrientationKeep, FontFallbackPriority::kText};
+    NGInlineItem::SetSegmentData(range, &items);
     return;
   }
 
   // Segment by script and Emoji.
   // Orientation is segmented separately, because it may vary by items.
   text_content.Ensure16Bit();
-  RunSegmenter segmenter(text_content.Characters16(), text_content.length(),
-                         FontOrientation::kHorizontal);
+
+  NGInlineItem* current_item = &items.front();
+  unsigned range_length = current_item->Length();
+
   RunSegmenter::RunSegmenterRange range = RunSegmenter::NullRange();
-  bool consumed = segmenter.Consume(&range);
-  DCHECK(consumed);
-  if (range.end == text_content.length()) {
-    NGInlineItem::SetSegmentData(range, &data->items);
-    data->segments = nullptr;
+  if (data->is_bidi_enabled_) {
+    // run RunSegmenter for each bidi run
+    for (wtf_size_t idx = 1; idx < items.size(); idx++) {
+      NGInlineItem& item = items[idx];
+      if (item.BidiLevel() == current_item->BidiLevel()) {
+        // same bidi level as the previous item. We can merge
+        range_length += item.Length();
+        continue;
+      }
+
+      // We have reached the boundary of a bidi run. We need to run the script
+      // segmenter.
+      if (!data->segments) {
+        data->segments = std::make_unique<NGInlineItemSegments>();
+      }
+      RunSegmenter segmenter(text_content.Characters16(), range_length,
+                             FontOrientation::kHorizontal,
+                             current_item->StartOffset());
+      while (segmenter.Consume(&range)) {
+        data->segments->Append(range);
+      }
+      range_length = item.Length();
+      current_item = &item;
+    }
+  } else {
+    range_length = text_content.length();
+  }
+
+  // We will now handle the last item. If the text is not bidirectional, it
+  // will be the only one.
+
+  if (range_length == 0) {
     return;
   }
 
-  // This node has multiple segments.
-  if (!data->segments)
+  RunSegmenter segmenter(text_content.Characters16(), range_length,
+                         FontOrientation::kHorizontal,
+                         current_item->StartOffset());
+  bool consumed = segmenter.Consume(&range);
+  DCHECK(consumed);
+  if (range.start == 0 && range.end == text_content.length()) {
+    NGInlineItem::SetSegmentData(range, &items);
+    return;
+  }
+
+  if (!data->segments) {
     data->segments = std::make_unique<NGInlineItemSegments>();
-  data->segments->ComputeSegments(&segmenter, &range);
+  }
+  do {
+    data->segments->Append(range);
+  } while (segmenter.Consume(&range));
   DCHECK_EQ(range.end, text_content.length());
 }
 
diff --git a/third_party/blink/renderer/core/testing/internals.cc b/third_party/blink/renderer/core/testing/internals.cc
index 01b71d8..c494d2f 100644
--- a/third_party/blink/renderer/core/testing/internals.cc
+++ b/third_party/blink/renderer/core/testing/internals.cc
@@ -1970,8 +1970,7 @@
   DCHECK(document);
   auto info = mojom::blink::InspectorIssueInfo::New(
       mojom::InspectorIssueCode::kSameSiteCookieIssue,
-      mojom::blink::InspectorIssueDetails::New(),
-      mojom::blink::AffectedResources::New());
+      mojom::blink::InspectorIssueDetails::New());
   document->AddInspectorIssue(InspectorIssue::Create(std::move(info)));
 }
 
diff --git a/third_party/blink/renderer/core/typed_arrays/array_buffer/array_buffer_contents.cc b/third_party/blink/renderer/core/typed_arrays/array_buffer/array_buffer_contents.cc
index 095ca3db..fe4485a 100644
--- a/third_party/blink/renderer/core/typed_arrays/array_buffer/array_buffer_contents.cc
+++ b/third_party/blink/renderer/core/typed_arrays/array_buffer/array_buffer_contents.cc
@@ -29,6 +29,7 @@
 
 #include <string.h>
 #include "base/allocator/partition_allocator/partition_alloc.h"
+#include "third_party/blink/renderer/platform/instrumentation/instance_counters.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/partitions.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
 
@@ -118,6 +119,8 @@
   void* data = PartitionAllocGenericFlags(
       WTF::Partitions::ArrayBufferPartition(), flags, size,
       WTF_HEAP_PROFILER_TYPE_NAME(ArrayBufferContents));
+  InstanceCounters::IncrementCounter(
+      InstanceCounters::kArrayBufferContentsCounter);
   return data;
 }
 
@@ -127,6 +130,8 @@
 }
 
 void ArrayBufferContents::FreeMemory(void* data) {
+  InstanceCounters::DecrementCounter(
+      InstanceCounters::kArrayBufferContentsCounter);
   WTF::Partitions::ArrayBufferPartition()->Free(data);
 }
 
diff --git a/third_party/blink/renderer/modules/app_banner/app_banner_controller.cc b/third_party/blink/renderer/modules/app_banner/app_banner_controller.cc
index 2e74f9c..beae80d 100644
--- a/third_party/blink/renderer/modules/app_banner/app_banner_controller.cc
+++ b/third_party/blink/renderer/modules/app_banner/app_banner_controller.cc
@@ -12,6 +12,8 @@
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/modules/app_banner/before_install_prompt_event.h"
+#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
+#include "third_party/blink/renderer/platform/scheduler/public/scheduling_policy.h"
 
 namespace blink {
 
@@ -39,6 +41,10 @@
     return;
   }
 
+  frame_->GetFrameScheduler()->RegisterStickyFeature(
+      blink::SchedulingPolicy::Feature::kAppBanner,
+      {blink::SchedulingPolicy::RecordMetricsForBackForwardCache()});
+
   mojom::AppBannerPromptReply reply =
       frame_->DomWindow()->DispatchEvent(*BeforeInstallPromptEvent::Create(
           event_type_names::kBeforeinstallprompt, *frame_,
diff --git a/third_party/blink/renderer/modules/cache_storage/cache_storage.cc b/third_party/blink/renderer/modules/cache_storage/cache_storage.cc
index 29cd652..da5e7a7 100644
--- a/third_party/blink/renderer/modules/cache_storage/cache_storage.cc
+++ b/third_party/blink/renderer/modules/cache_storage/cache_storage.cc
@@ -472,8 +472,7 @@
     mojo::PendingRemote<mojom::blink::CacheStorage> info =
         service_worker->TakeCacheStorage();
     if (info) {
-      cache_storage_remote_ =
-          HeapMojoRemote<mojom::blink::CacheStorage>(context);
+      cache_storage_remote_.reset();
       cache_storage_remote_.Bind(std::move(info), task_runner);
       return;
     }
diff --git a/third_party/blink/renderer/modules/manifest/manifest_manager.cc b/third_party/blink/renderer/modules/manifest/manifest_manager.cc
index db4f04f..229640e6 100644
--- a/third_party/blink/renderer/modules/manifest/manifest_manager.cc
+++ b/third_party/blink/renderer/modules/manifest/manifest_manager.cc
@@ -53,7 +53,7 @@
       ExecutionContextLifecycleObserver(frame.GetDocument()),
       may_have_manifest_(false),
       manifest_dirty_(true),
-      receivers_(GetExecutionContext()) {
+      receivers_(this, GetExecutionContext()) {
   if (frame.IsMainFrame()) {
     manifest_change_notifier_ =
         MakeGarbageCollected<ManifestChangeNotifier>(frame);
@@ -258,7 +258,7 @@
 void ManifestManager::BindReceiver(
     mojo::PendingReceiver<mojom::blink::ManifestManager> receiver) {
   receivers_.Add(
-      this, std::move(receiver),
+      std::move(receiver),
       GetSupplementable()->GetDocument()->ToExecutionContext()->GetTaskRunner(
           TaskType::kNetworking));
 }
diff --git a/third_party/blink/renderer/modules/manifest/manifest_manager.h b/third_party/blink/renderer/modules/manifest/manifest_manager.h
index 7aee0af2..266508f 100644
--- a/third_party/blink/renderer/modules/manifest/manifest_manager.h
+++ b/third_party/blink/renderer/modules/manifest/manifest_manager.h
@@ -111,7 +111,8 @@
 
   Vector<InternalRequestManifestCallback> pending_callbacks_;
 
-  HeapMojoReceiverSet<mojom::blink::ManifestManager> receivers_;
+  HeapMojoReceiverSet<mojom::blink::ManifestManager, ManifestManager>
+      receivers_;
 
   DISALLOW_COPY_AND_ASSIGN(ManifestManager);
 };
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 c4d14b7..98952985 100644
--- a/third_party/blink/renderer/modules/quota/navigator_storage_quota.cc
+++ b/third_party/blink/renderer/modules/quota/navigator_storage_quota.cc
@@ -30,6 +30,7 @@
 
 #include "third_party/blink/renderer/modules/quota/navigator_storage_quota.h"
 
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/navigator.h"
 #include "third_party/blink/renderer/modules/quota/deprecated_storage_quota.h"
 #include "third_party/blink/renderer/modules/quota/storage_manager.h"
@@ -51,7 +52,6 @@
   return *supplement;
 }
 
-
 DeprecatedStorageQuota* NavigatorStorageQuota::webkitTemporaryStorage(
     Navigator& navigator) {
   return NavigatorStorageQuota::From(navigator).webkitTemporaryStorage();
@@ -83,8 +83,10 @@
 }
 
 StorageManager* NavigatorStorageQuota::storage() const {
-  if (!storage_manager_)
-    storage_manager_ = MakeGarbageCollected<StorageManager>();
+  if (!storage_manager_) {
+    storage_manager_ = MakeGarbageCollected<StorageManager>(
+        GetSupplementable() ? GetSupplementable()->DomWindow() : nullptr);
+  }
   return storage_manager_.Get();
 }
 
diff --git a/third_party/blink/renderer/modules/quota/storage_manager.cc b/third_party/blink/renderer/modules/quota/storage_manager.cc
index f677a61..fc1ab352 100644
--- a/third_party/blink/renderer/modules/quota/storage_manager.cc
+++ b/third_party/blink/renderer/modules/quota/storage_manager.cc
@@ -84,6 +84,9 @@
 
 }  // namespace
 
+StorageManager::StorageManager(ContextLifecycleNotifier* notifier)
+    : permission_service_(notifier), quota_host_(notifier) {}
+
 ScriptPromise StorageManager::persist(ScriptState* script_state) {
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
   ScriptPromise promise = resolver->Promise();
@@ -158,9 +161,15 @@
   return promise;
 }
 
+void StorageManager::Trace(Visitor* visitor) {
+  visitor->Trace(permission_service_);
+  visitor->Trace(quota_host_);
+  ScriptWrappable::Trace(visitor);
+}
+
 PermissionService* StorageManager::GetPermissionService(
     ExecutionContext* execution_context) {
-  if (!permission_service_) {
+  if (!permission_service_.is_bound()) {
     ConnectToPermissionService(
         execution_context,
         permission_service_.BindNewPipeAndPassReceiver(
@@ -186,7 +195,7 @@
 
 mojom::blink::QuotaManagerHost* StorageManager::GetQuotaHost(
     ExecutionContext* execution_context) {
-  if (!quota_host_) {
+  if (!quota_host_.is_bound()) {
     ConnectToQuotaManagerHost(
         execution_context,
         quota_host_.BindNewPipeAndPassReceiver(
diff --git a/third_party/blink/renderer/modules/quota/storage_manager.h b/third_party/blink/renderer/modules/quota/storage_manager.h
index 05c5d75..7b983114 100644
--- a/third_party/blink/renderer/modules/quota/storage_manager.h
+++ b/third_party/blink/renderer/modules/quota/storage_manager.h
@@ -5,11 +5,12 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_QUOTA_STORAGE_MANAGER_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_QUOTA_STORAGE_MANAGER_H_
 
-#include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/blink/public/mojom/permissions/permission.mojom-blink.h"
 #include "third_party/blink/public/mojom/quota/quota_manager_host.mojom-blink.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
+#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
 
 namespace blink {
 
@@ -22,11 +23,15 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
+  explicit StorageManager(ContextLifecycleNotifier* notifier);
+
   ScriptPromise persisted(ScriptState*);
   ScriptPromise persist(ScriptState*);
 
   ScriptPromise estimate(ScriptState*);
 
+  void Trace(Visitor* visitor) override;
+
  private:
   mojom::blink::PermissionService* GetPermissionService(ExecutionContext*);
   void PermissionServiceConnectionError();
@@ -37,8 +42,12 @@
   // provider, and returns it,
   mojom::blink::QuotaManagerHost* GetQuotaHost(ExecutionContext*);
 
-  mojo::Remote<mojom::blink::PermissionService> permission_service_;
-  mojo::Remote<mojom::blink::QuotaManagerHost> quota_host_;
+  HeapMojoRemote<mojom::blink::PermissionService,
+                 HeapMojoWrapperMode::kWithoutContextObserver>
+      permission_service_;
+  HeapMojoRemote<mojom::blink::QuotaManagerHost,
+                 HeapMojoWrapperMode::kWithoutContextObserver>
+      quota_host_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/quota/worker_navigator_storage_quota.cc b/third_party/blink/renderer/modules/quota/worker_navigator_storage_quota.cc
index f0f8a65..96c8c280 100644
--- a/third_party/blink/renderer/modules/quota/worker_navigator_storage_quota.cc
+++ b/third_party/blink/renderer/modules/quota/worker_navigator_storage_quota.cc
@@ -57,8 +57,11 @@
 }
 
 StorageManager* WorkerNavigatorStorageQuota::storage() const {
-  if (!storage_manager_)
-    storage_manager_ = MakeGarbageCollected<StorageManager>();
+  if (!storage_manager_) {
+    storage_manager_ = MakeGarbageCollected<StorageManager>(
+        GetSupplementable() ? GetSupplementable()->GetExecutionContext()
+                            : nullptr);
+  }
   return storage_manager_.Get();
 }
 
diff --git a/third_party/blink/renderer/modules/webmidi/midi_access_initializer.cc b/third_party/blink/renderer/modules/webmidi/midi_access_initializer.cc
index d0ceda2..f3ea799 100644
--- a/third_party/blink/renderer/modules/webmidi/midi_access_initializer.cc
+++ b/third_party/blink/renderer/modules/webmidi/midi_access_initializer.cc
@@ -32,7 +32,7 @@
                                              const MIDIOptions* options)
     : ScriptPromiseResolver(script_state),
       options_(options),
-      permission_service_(GetExecutionContext()) {}
+      permission_service_(ExecutionContext::From(script_state)) {}
 
 void MIDIAccessInitializer::Dispose() {
   dispatcher_.reset();
diff --git a/third_party/blink/renderer/platform/bindings/parkable_string.cc b/third_party/blink/renderer/platform/bindings/parkable_string.cc
index e2f8e56..e5fb243 100644
--- a/third_party/blink/renderer/platform/bindings/parkable_string.cc
+++ b/third_party/blink/renderer/platform/bindings/parkable_string.cc
@@ -4,8 +4,6 @@
 
 #include "third_party/blink/renderer/platform/bindings/parkable_string.h"
 
-#include <string>
-
 #include "base/allocator/partition_allocator/partition_alloc.h"
 #include "base/bind.h"
 #include "base/logging.h"
@@ -33,6 +31,15 @@
 
 namespace {
 
+ParkableStringImpl::Age MakeOlder(ParkableStringImpl::Age age) {
+  switch (age) {
+    case ParkableStringImpl::Age::kYoung:
+      return ParkableStringImpl::Age::kOld;
+    case ParkableStringImpl::Age::kOld:
+      return ParkableStringImpl::Age::kOld;
+  }
+}
+
 enum class ParkingAction { kParked, kUnparked };
 
 void RecordStatistics(size_t size,
@@ -120,41 +127,49 @@
 
 }  // namespace
 
+struct TaskParams {
+  explicit TaskParams(
+      scoped_refptr<base::SingleThreadTaskRunner> callback_task_runner)
+      : callback_task_runner(callback_task_runner) {
+    DCHECK(IsMainThread());
+  }
+  virtual ~TaskParams() { DCHECK(IsMainThread()); }
+
+  const scoped_refptr<base::SingleThreadTaskRunner> callback_task_runner;
+
+  TaskParams(TaskParams&&) = delete;
+  DISALLOW_COPY_AND_ASSIGN(TaskParams);
+};
+
 // Created and destroyed on the same thread, accessed on a background thread as
 // well. |string|'s reference counting is *not* thread-safe, hence |string|'s
 // reference count must *not* change on the background thread.
-struct CompressionTaskParams final {
+struct CompressionTaskParams final : public TaskParams {
   CompressionTaskParams(
       scoped_refptr<ParkableStringImpl> string,
       const void* data,
       size_t size,
       scoped_refptr<base::SingleThreadTaskRunner> callback_task_runner)
-      : string(string),
+      : TaskParams(callback_task_runner),
+        string(string),
         data(data),
-        size(size),
-        callback_task_runner(std::move(callback_task_runner)) {
-    DCHECK(IsMainThread());
-  }
-
-  ~CompressionTaskParams() { DCHECK(IsMainThread()); }
+        size(size) {}
 
   const scoped_refptr<ParkableStringImpl> string;
   const void* data;
   const size_t size;
-  const scoped_refptr<base::SingleThreadTaskRunner> callback_task_runner;
-
-  CompressionTaskParams(CompressionTaskParams&&) = delete;
-  DISALLOW_COPY_AND_ASSIGN(CompressionTaskParams);
 };
 
 // Valid transitions are:
+//
+// Compression:
 // 1. kUnparked -> kParkingInProgress: Parking started asynchronously
 // 2. kParkingInProgress -> kUnparked: Parking did not complete
 // 3. kParkingInProgress -> kParked: Parking completed normally
 // 4. kParked -> kUnparked: String has been unparked.
 //
-// See |Park()| for (1), |OnParkingCompleteOnMainThread()| for 2-3, and
-// |Unpark()| for (4).
+// See |PostBackgroundCompressionTask()| for (1),
+// |OnParkingCompleteOnMainThread()| for 2-3, and |Unpark()| for (4).
 //
 // Each state can be combined with a string that is either old or
 // young. Examples below:
@@ -194,7 +209,7 @@
       state_(State::kUnparked),
       compressed_(nullptr),
       digest_(*digest),
-      is_young_(true),
+      age_(Age::kYoung),
       is_8bit_(string.Is8Bit()),
       length_(string.length()) {}
 
@@ -255,6 +270,8 @@
 
   DCHECK_EQ(0, lock_depth_for_testing());
   AsanUnpoisonString(string_);
+  // Cannot destroy while parking is in progress, as the object is kept alive by
+  // the background task.
   DCHECK(metadata_->state_ == State::kParked ||
          metadata_->state_ == State::kUnparked);
 
@@ -356,18 +373,19 @@
   MutexLocker locker(metadata_->mutex_);
   AssertOnValidThread();
   DCHECK(may_be_parked());
-  DCHECK(!is_parked());
 
   Status status = CurrentStatus();
-  if (metadata_->is_young_) {
+  Age age = metadata_->age_;
+  if (age == Age::kYoung) {
     if (status == Status::kUnreferencedExternally)
-      metadata_->is_young_ = false;
-  } else {
+      metadata_->age_ = MakeOlder(age);
+  } else if (age == Age::kOld) {
     if (metadata_->state_ == State::kParkingInProgress)
       return AgeOrParkResult::kSuccessOrTransientFailure;
 
     if (CanParkNow()) {
-      ParkInternal(ParkingMode::kAlways);
+      bool ok = ParkInternal(ParkingMode::kCompress);
+      DCHECK(ok);
       return AgeOrParkResult::kSuccessOrTransientFailure;
     }
   }
@@ -390,7 +408,7 @@
 
   // Making the string old to cancel parking if it is accessed/locked before
   // parking is complete.
-  metadata_->is_young_ = false;
+  metadata_->age_ = Age::kOld;
   if (!CanParkNow())
     return false;
 
@@ -398,13 +416,37 @@
   return true;
 }
 
-bool ParkableStringImpl::is_parked() const {
-  DCHECK(may_be_parked());
-  return metadata_->state_ == State::kParked;
+bool ParkableStringImpl::ParkInternal(ParkingMode mode) {
+  DCHECK(metadata_->state_ == State::kUnparked);
+  DCHECK(metadata_->age_ != Age::kYoung);
+  DCHECK(CanParkNow());
+
+  switch (mode) {
+    case ParkingMode::kSynchronousOnly:
+      if (has_compressed_data())
+        DiscardUncompressedData();
+      break;
+    case ParkingMode::kCompress:
+      if (has_compressed_data())
+        DiscardUncompressedData();
+      else
+        PostBackgroundCompressionTask();
+      break;
+  }
+  return true;
 }
 
-void ParkableStringImpl::MakeYoung() {
-  metadata_->is_young_ = true;
+void ParkableStringImpl::DiscardUncompressedData() {
+  // Must unpoison the memory before releasing it.
+  AsanUnpoisonString(string_);
+  string_ = String();
+
+  metadata_->state_ = State::kParked;
+  ParkableStringManager::Instance().OnParked(this);
+}
+
+bool ParkableStringImpl::is_parked() const {
+  return metadata_->state_ == State::kParked;
 }
 
 ParkableStringImpl::Status ParkableStringImpl::CurrentStatus() const {
@@ -416,42 +458,20 @@
   //   reference to |string_|, it must the only one.
   if (metadata_->lock_depth_ != 0)
     return Status::kLocked;
+
+  // Can be null if it is compressed.
+  if (string_.IsNull())
+    return Status::kUnreferencedExternally;
+
   if (!string_.Impl()->HasOneRef())
     return Status::kTooManyReferences;
+
   return Status::kUnreferencedExternally;
 }
 
 bool ParkableStringImpl::CanParkNow() const {
   return CurrentStatus() == Status::kUnreferencedExternally &&
-         !metadata_->is_young_;
-}
-
-void ParkableStringImpl::ParkInternal(ParkingMode mode) {
-  DCHECK_EQ(State::kUnparked, metadata_->state_);
-  DCHECK(!metadata_->is_young_);
-  DCHECK(CanParkNow());
-
-  // Parking can proceed synchronously.
-  if (has_compressed_data()) {
-    metadata_->state_ = State::kParked;
-    ParkableStringManager::Instance().OnParked(this);
-
-    // Must unpoison the memory before releasing it.
-    AsanUnpoisonString(string_);
-    string_ = String();
-  } else if (mode == ParkingMode::kAlways) {
-    // |string_|'s data should not be touched except in the compression task.
-    AsanPoisonString(string_);
-    // |params| keeps |this| alive until |OnParkingCompleteOnMainThread()|.
-    auto params = std::make_unique<CompressionTaskParams>(
-        this, string_.Bytes(), string_.CharactersSizeInBytes(),
-        Thread::Current()->GetTaskRunner());
-    worker_pool::PostTask(
-        FROM_HERE,
-        CrossThreadBindOnce(&ParkableStringImpl::CompressInBackground,
-                            WTF::Passed(std::move(params))));
-    metadata_->state_ = State::kParkingInProgress;
-  }
+         metadata_->age_ != Age::kYoung;
 }
 
 void ParkableStringImpl::Unpark() {
@@ -468,7 +488,7 @@
   ParkableStringManager::Instance().OnUnparked(this);
 }
 
-String ParkableStringImpl::UnparkInternal() const {
+String ParkableStringImpl::UnparkInternal() {
   AssertOnValidThread();
   DCHECK(is_parked());
   // Note: No need for |mutex_| to be held, this doesn't touch any member
@@ -515,40 +535,17 @@
   return uncompressed;
 }
 
-void ParkableStringImpl::OnParkingCompleteOnMainThread(
-    std::unique_ptr<CompressionTaskParams> params,
-    std::unique_ptr<Vector<uint8_t>> compressed,
-    base::TimeDelta parking_thread_time) {
-  MutexLocker locker(metadata_->mutex_);
-  DCHECK_EQ(State::kParkingInProgress, metadata_->state_);
-
-  // Always keep the compressed data. Compression is expensive, so even if the
-  // uncompressed representation cannot be discarded now, avoid compressing
-  // multiple times. This will allow synchronous parking next time.
-  DCHECK(!metadata_->compressed_);
-  if (compressed)
-    metadata_->compressed_ = std::move(compressed);
-
-  // Between |Park()| and now, things may have happened:
-  // 1. |ToString()| or
-  // 2. |Lock()| may have been called.
-  //
-  // Both of these will make the string young again, and if so we don't
-  // discard the compressed representation yet.
-  if (CanParkNow() && metadata_->compressed_) {
-    metadata_->state_ = State::kParked;
-    ParkableStringManager::Instance().OnParked(this);
-
-    // Must unpoison the memory before releasing it.
-    AsanUnpoisonString(string_);
-    string_ = String();
-  } else {
-    metadata_->state_ = State::kUnparked;
-  }
-  // Record the time no matter whether the string was parked or not, as the
-  // parking cost was paid.
-  ParkableStringManager::Instance().RecordParkingThreadTime(
-      parking_thread_time);
+void ParkableStringImpl::PostBackgroundCompressionTask() {
+  // |string_|'s data should not be touched except in the compression task.
+  AsanPoisonString(string_);
+  // |params| keeps |this| alive until |OnParkingCompleteOnMainThread()|.
+  auto params = std::make_unique<CompressionTaskParams>(
+      this, string_.Bytes(), string_.CharactersSizeInBytes(),
+      Thread::Current()->GetTaskRunner());
+  worker_pool::PostTask(
+      FROM_HERE, CrossThreadBindOnce(&ParkableStringImpl::CompressInBackground,
+                                     WTF::Passed(std::move(params))));
+  metadata_->state_ = State::kParkingInProgress;
 }
 
 // static
@@ -634,6 +631,36 @@
   RecordStatistics(size, timer.Elapsed(), ParkingAction::kParked);
 }
 
+void ParkableStringImpl::OnParkingCompleteOnMainThread(
+    std::unique_ptr<CompressionTaskParams> params,
+    std::unique_ptr<Vector<uint8_t>> compressed,
+    base::TimeDelta parking_thread_time) {
+  MutexLocker locker(metadata_->mutex_);
+  DCHECK_EQ(State::kParkingInProgress, metadata_->state_);
+
+  // Always keep the compressed data. Compression is expensive, so even if the
+  // uncompressed representation cannot be discarded now, avoid compressing
+  // multiple times. This will allow synchronous parking next time.
+  DCHECK(!metadata_->compressed_);
+  if (compressed)
+    metadata_->compressed_ = std::move(compressed);
+
+  // Between |Park()| and now, things may have happened:
+  // 1. |ToString()| or
+  // 2. |Lock()| may have been called.
+  //
+  // Both of these will make the string young again, and if so we don't
+  // discard the compressed representation yet.
+  if (CanParkNow() && metadata_->compressed_) {
+    DiscardUncompressedData();
+  } else {
+    metadata_->state_ = State::kUnparked;
+  }
+  // Record the time no matter whether the string was parked or not, as the
+  // parking cost was paid.
+  ParkableStringManager::Instance().RecordParkingThreadTime(
+      parking_thread_time);
+}
 
 ParkableString::ParkableString(scoped_refptr<StringImpl>&& impl) {
   if (!impl) {
diff --git a/third_party/blink/renderer/platform/bindings/parkable_string.h b/third_party/blink/renderer/platform/bindings/parkable_string.h
index b9d2bd8..7e28bbd 100644
--- a/third_party/blink/renderer/platform/bindings/parkable_string.h
+++ b/third_party/blink/renderer/platform/bindings/parkable_string.h
@@ -41,11 +41,12 @@
 class PLATFORM_EXPORT ParkableStringImpl final
     : public RefCounted<ParkableStringImpl> {
  public:
-  enum class ParkingMode { kIfCompressedDataExists, kAlways };
+  enum class ParkingMode { kSynchronousOnly, kCompress };
   enum class AgeOrParkResult {
     kSuccessOrTransientFailure,
     kNonTransientFailure
   };
+  enum class Age { kYoung = 0, kOld = 1 };
 
   constexpr static size_t kDigestSize = 32;  // SHA256.
   using SecureDigest = Vector<uint8_t, kDigestSize>;
@@ -121,7 +122,6 @@
 
   // Returns true if the string is parked.
   bool is_parked() const;
-
   // Returns whether synchronous parking is possible, that is the string was
   // parked in the past.
   bool has_compressed_data() const { return !!metadata_->compressed_; }
@@ -133,9 +133,9 @@
     return metadata_->compressed_->size();
   }
 
-  bool is_young_for_testing() {
+  Age age_for_testing() {
     MutexLocker locker(metadata_->mutex_);
-    return metadata_->is_young_;
+    return metadata_->age_;
   }
 
   const SecureDigest* digest() const {
@@ -164,17 +164,24 @@
   void LockWithoutMakingYoung();
 #endif  // defined(ADDRESS_SANITIZER)
   // May be called from any thread.
-  void MakeYoung() EXCLUSIVE_LOCKS_REQUIRED(metadata_->mutex_);
+
+  void MakeYoung() EXCLUSIVE_LOCKS_REQUIRED(metadata_->mutex_) {
+    metadata_->age_ = Age::kYoung;
+  }
   // Whether the string is referenced or locked. The return value is valid as
   // long as |mutex_| is held.
   Status CurrentStatus() const EXCLUSIVE_LOCKS_REQUIRED(metadata_->mutex_);
   bool CanParkNow() const EXCLUSIVE_LOCKS_REQUIRED(metadata_->mutex_);
-  void ParkInternal(ParkingMode mode)
+  bool ParkInternal(ParkingMode mode)
       EXCLUSIVE_LOCKS_REQUIRED(metadata_->mutex_);
   void Unpark() EXCLUSIVE_LOCKS_REQUIRED(metadata_->mutex_);
-  String UnparkInternal() const EXCLUSIVE_LOCKS_REQUIRED(metadata_->mutex_);
+  String UnparkInternal() EXCLUSIVE_LOCKS_REQUIRED(metadata_->mutex_);
+
+  void PostBackgroundCompressionTask();
+  static void CompressInBackground(std::unique_ptr<CompressionTaskParams>);
   // Called on the main thread after compression is done.
-  // |params| is the same as the one passed to |CompressInBackground()|,
+  // |params| is the same as the one passed to
+  // |PostBackgroundCompressionTask()|,
   // |compressed| is the compressed data, nullptr if compression failed.
   // |parking_thread_time| is the CPU time used by the background compression
   // task.
@@ -183,8 +190,7 @@
       std::unique_ptr<Vector<uint8_t>> compressed,
       base::TimeDelta parking_thread_time);
 
-  // Background thread.
-  static void CompressInBackground(std::unique_ptr<CompressionTaskParams>);
+  void DiscardUncompressedData();
 
   int lock_depth_for_testing() {
     MutexLocker locker_(metadata_->mutex_);
@@ -203,8 +209,10 @@
     std::unique_ptr<Vector<uint8_t>> compressed_;
     const SecureDigest digest_;
 
-    // A string can either be "young" or "old". It starts young, and transitions
-    // are:
+    // A string can be young or old. It starts young, and ages with
+    // |MaybeAgeOrParkString()|.
+    //
+    // Transitions are:
     // Young -> Old: By calling |MaybeAgeOrParkString()|.
     // Old -> Young: When the string is accessed, either by |Lock()|-ing it or
     //               calling |ToString()|.
@@ -212,7 +220,7 @@
     // Thread safety: it is typically not safe to guard only one part of a
     // bitfield with a mutex, but this is correct here, as the other members are
     // const (and never change).
-    bool is_young_ : 1 GUARDED_BY(mutex_);
+    Age age_ : 3 GUARDED_BY(mutex_);
     const bool is_8bit_ : 1;
     const unsigned length_;
 
diff --git a/third_party/blink/renderer/platform/bindings/parkable_string_manager.cc b/third_party/blink/renderer/platform/bindings/parkable_string_manager.cc
index dd987fac..d3b6c0e 100644
--- a/third_party/blink/renderer/platform/bindings/parkable_string_manager.cc
+++ b/third_party/blink/renderer/platform/bindings/parkable_string_manager.cc
@@ -60,6 +60,28 @@
   }
 };
 
+Vector<ParkableStringImpl*> EnumerateStrings(
+    const ParkableStringManager::StringMap& strings) {
+  WTF::Vector<ParkableStringImpl*> all_strings;
+  all_strings.ReserveCapacity(strings.size());
+
+  for (const auto& kv : strings)
+    all_strings.push_back(kv.value);
+
+  return all_strings;
+}
+
+void MoveString(ParkableStringImpl* string,
+                ParkableStringManager::StringMap* from,
+                ParkableStringManager::StringMap* to) {
+  auto it = from->find(string->digest());
+  DCHECK(it != from->end());
+  DCHECK_EQ(it->value, string);
+  from->erase(it);
+  auto insert_result = to->insert(string->digest(), string);
+  DCHECK(insert_result.is_new_entry);
+}
+
 }  // namespace
 
 const char* ParkableStringManager::kAllocatorDumpName = "parkable_strings";
@@ -103,7 +125,6 @@
     default;
 
 ParkableStringManager& ParkableStringManager::Instance() {
-  DCHECK(IsMainThread());
   DEFINE_STATIC_LOCAL(ParkableStringManager, instance, ());
   return instance;
 }
@@ -170,10 +191,9 @@
   if (it != parked_strings_.end())
     return it->value;
 
+  // No hit, new unparked string.
   auto new_parkable = ParkableStringImpl::MakeParkable(std::move(string_impl),
                                                        std::move(digest));
-
-  // No hit, new unparked string.
   auto insert_result =
       unparked_strings_.insert(new_parkable->digest(), new_parkable.get());
   DCHECK(insert_result.is_new_entry);
@@ -209,37 +229,29 @@
   DCHECK(string->may_be_parked());
   DCHECK(string->digest());
 
-  if (string->is_parked()) {
-    auto it = parked_strings_.find(string->digest());
-    DCHECK(it != parked_strings_.end());
-    parked_strings_.erase(it);
-  } else {
-    auto it = unparked_strings_.find(string->digest());
-    DCHECK(it != unparked_strings_.end());
-    unparked_strings_.erase(it);
-  }
+  StringMap* map = nullptr;
+  if (string->is_parked())
+    map = &parked_strings_;
+  else
+    map = &unparked_strings_;
+
+  auto it = map->find(string->digest());
+  DCHECK(it != map->end());
+  map->erase(it);
 }
 
 void ParkableStringManager::OnParked(ParkableStringImpl* newly_parked_string) {
   DCHECK(IsMainThread());
   DCHECK(newly_parked_string->may_be_parked());
   DCHECK(newly_parked_string->is_parked());
-  auto it = unparked_strings_.find(newly_parked_string->digest());
-  DCHECK(it != unparked_strings_.end());
-  DCHECK_EQ(it->value, newly_parked_string);
-  unparked_strings_.erase(it);
-  parked_strings_.insert(newly_parked_string->digest(), newly_parked_string);
+  MoveString(newly_parked_string, &unparked_strings_, &parked_strings_);
 }
 
 void ParkableStringManager::OnUnparked(ParkableStringImpl* was_parked_string) {
   DCHECK(IsMainThread());
   DCHECK(was_parked_string->may_be_parked());
   DCHECK(!was_parked_string->is_parked());
-  auto it = parked_strings_.find(was_parked_string->digest());
-  DCHECK(it != parked_strings_.end());
-  DCHECK_EQ(it->value, was_parked_string);
-  parked_strings_.erase(it);
-  unparked_strings_.insert(was_parked_string->digest(), was_parked_string);
+  MoveString(was_parked_string, &parked_strings_, &unparked_strings_);
   ScheduleAgingTaskIfNeeded();
 }
 
@@ -265,7 +277,7 @@
   // and |unparked_strings_| can contain a few 10s of strings (and we will
   // trigger expensive compression), or this is a subsequent one, and
   // |unparked_strings_| will have few entries.
-  WTF::Vector<ParkableStringImpl*> unparked = GetUnparkedStrings();
+  auto unparked = EnumerateStrings(unparked_strings_);
 
   for (ParkableStringImpl* str : unparked) {
     str->Park(mode);
@@ -274,6 +286,8 @@
 }
 
 size_t ParkableStringManager::Size() const {
+  DCHECK(IsMainThread());
+
   return parked_strings_.size() + unparked_strings_.size();
 }
 
@@ -307,12 +321,13 @@
   TRACE_EVENT0("blink", "ParkableStringManager::AgeStringsAndPark");
   has_pending_aging_task_ = false;
 
-  WTF::Vector<ParkableStringImpl*> unparked = GetUnparkedStrings();
+  auto unparked = EnumerateStrings(unparked_strings_);
   bool can_make_progress = false;
   for (ParkableStringImpl* str : unparked) {
     if (str->MaybeAgeOrParkString() ==
-        ParkableStringImpl::AgeOrParkResult::kSuccessOrTransientFailure)
+        ParkableStringImpl::AgeOrParkResult::kSuccessOrTransientFailure) {
       can_make_progress = true;
+    }
   }
 
   // Some strings will never be parkable because there are lasting external
@@ -350,7 +365,7 @@
   DCHECK(IsMainThread());
   DCHECK(CompressionEnabled());
 
-  ParkAll(ParkableStringImpl::ParkingMode::kAlways);
+  ParkAll(ParkableStringImpl::ParkingMode::kCompress);
   // Critical memory pressure: drop compressed data for strings that we cannot
   // park now.
   //
@@ -363,15 +378,6 @@
   }
 }
 
-Vector<ParkableStringImpl*> ParkableStringManager::GetUnparkedStrings() const {
-  WTF::Vector<ParkableStringImpl*> unparked;
-  unparked.ReserveCapacity(unparked_strings_.size());
-  for (const auto& kv : unparked_strings_)
-    unparked.push_back(kv.value);
-
-  return unparked;
-}
-
 ParkableStringManager::Statistics ParkableStringManager::ComputeStatistics()
     const {
   ParkableStringManager::Statistics stats = {};
@@ -439,10 +445,6 @@
     : backgrounded_(false),
       has_pending_aging_task_(false),
       has_posted_unparking_time_accounting_task_(false),
-      did_register_memory_pressure_listener_(false),
-      total_unparking_time_(),
-      total_parking_thread_time_(),
-      unparked_strings_(),
-      parked_strings_() {}
+      did_register_memory_pressure_listener_(false) {}
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/bindings/parkable_string_manager.h b/third_party/blink/renderer/platform/bindings/parkable_string_manager.h
index e7fd729..d7828f6 100644
--- a/third_party/blink/renderer/platform/bindings/parkable_string_manager.h
+++ b/third_party/blink/renderer/platform/bindings/parkable_string_manager.h
@@ -5,6 +5,9 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_PARKABLE_STRING_MANAGER_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_PARKABLE_STRING_MANAGER_H_
 
+#include <memory>
+#include <utility>
+
 #include "base/feature_list.h"
 #include "base/macros.h"
 #include "base/memory/scoped_refptr.h"
@@ -68,11 +71,16 @@
   constexpr static int kAgingIntervalInSeconds = 2;
 
   static const char* kAllocatorDumpName;
+  // Relies on secure hash equality for deduplication. If one day SHA256 becomes
+  // insecure, then this would need to be updated to a more robust hash.
+  struct SecureDigestHash;
+  using StringMap = WTF::HashMap<const ParkableStringImpl::SecureDigest*,
+                                 ParkableStringImpl*,
+                                 SecureDigestHash>;
 
  private:
   friend class ParkableString;
   friend class ParkableStringImpl;
-  struct SecureDigestHash;
 
   scoped_refptr<ParkableStringImpl> Add(scoped_refptr<StringImpl>&&);
   void Remove(ParkableStringImpl*);
@@ -88,11 +96,9 @@
   void RecordParkingThreadTime(base::TimeDelta parking_thread_time) {
     total_parking_thread_time_ += parking_thread_time;
   }
-  Vector<ParkableStringImpl*> GetUnparkedStrings() const;
   Statistics ComputeStatistics() const;
 
   void ResetForTesting();
-
   ParkableStringManager();
 
   bool backgrounded_;
@@ -102,16 +108,8 @@
   base::TimeDelta total_unparking_time_;
   base::TimeDelta total_parking_thread_time_;
 
-  // Relies on secure hash equality for deduplication. If one day SHA256 becomes
-  // insecure, then this would need to be updated to a more robust hash.
-  WTF::HashMap<const ParkableStringImpl::SecureDigest*,
-               ParkableStringImpl*,
-               SecureDigestHash>
-      unparked_strings_;
-  WTF::HashMap<const ParkableStringImpl::SecureDigest*,
-               ParkableStringImpl*,
-               SecureDigestHash>
-      parked_strings_;
+  StringMap unparked_strings_;
+  StringMap parked_strings_;
 
   friend class ParkableStringTest;
   FRIEND_TEST_ALL_PREFIXES(ParkableStringTest, SynchronousCompression);
diff --git a/third_party/blink/renderer/platform/bindings/parkable_string_test.cc b/third_party/blink/renderer/platform/bindings/parkable_string_test.cc
index a1e7a6a9..138c456 100644
--- a/third_party/blink/renderer/platform/bindings/parkable_string_test.cc
+++ b/third_party/blink/renderer/platform/bindings/parkable_string_test.cc
@@ -54,7 +54,7 @@
 
   bool ParkAndWait(const ParkableString& string) {
     bool success =
-        string.Impl()->Park(ParkableStringImpl::ParkingMode::kAlways);
+        string.Impl()->Park(ParkableStringImpl::ParkingMode::kCompress);
     RunPostedTasks();
     return success;
   }
@@ -110,7 +110,8 @@
 // doesn't change. If it does, |kCompressedsize| will need to be updated.
 TEST_F(ParkableStringTest, CheckCompressedSize) {
   ParkableString parkable(MakeLargeString().ReleaseImpl());
-  EXPECT_TRUE(parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kAlways));
+  EXPECT_TRUE(
+      parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kCompress));
   RunPostedTasks();
   EXPECT_TRUE(parkable.Impl()->is_parked());
   EXPECT_EQ(kCompressedSize, parkable.Impl()->compressed_size());
@@ -132,7 +133,8 @@
   }
   ParkableString parkable(String(data.data(), data.size()).ReleaseImpl());
 
-  EXPECT_TRUE(parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kAlways));
+  EXPECT_TRUE(
+      parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kCompress));
   RunPostedTasks();
   // Not parked because the temporary buffer wasn't large enough.
   EXPECT_FALSE(parkable.Impl()->is_parked());
@@ -140,7 +142,8 @@
 
 TEST_F(ParkableStringTest, ParkUnparkIdenticalContent) {
   ParkableString parkable(MakeLargeString().ReleaseImpl());
-  EXPECT_TRUE(parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kAlways));
+  EXPECT_TRUE(
+      parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kCompress));
   RunPostedTasks();
   EXPECT_TRUE(parkable.Impl()->is_parked());
 
@@ -165,7 +168,8 @@
   EXPECT_EQ(size_in_chars, parkable.length());
   EXPECT_EQ(sizeof(UChar) * size_in_chars, parkable.CharactersSizeInBytes());
 
-  EXPECT_TRUE(parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kAlways));
+  EXPECT_TRUE(
+      parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kCompress));
   RunPostedTasks();
   EXPECT_TRUE(parkable.Impl()->is_parked());
 
@@ -215,10 +219,10 @@
     EXPECT_TRUE(parkable.may_be_parked());
     EXPECT_FALSE(parkable.Impl()->is_parked());
     EXPECT_TRUE(
-        parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kAlways));
+        parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kCompress));
     // Should not crash, it is allowed to call |Park()| twice in a row.
     EXPECT_TRUE(
-        parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kAlways));
+        parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kCompress));
     parkable = ParkableString();  // Release the reference.
     RunPostedTasks();             // Should not crash.
   }
@@ -253,7 +257,7 @@
 
     // The string is locked at the end of parking, should cancel it.
     EXPECT_TRUE(
-        parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kAlways));
+        parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kCompress));
     parkable.Impl()->Lock();
     RunPostedTasks();
     EXPECT_FALSE(parkable.Impl()->is_parked());
@@ -267,7 +271,7 @@
     ParkableString parkable(MakeLargeString().ReleaseImpl());
     // |ToString()| cancels parking as |content| is kept alive.
     EXPECT_TRUE(
-        parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kAlways));
+        parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kCompress));
     {
       String content = parkable.Impl()->ToString();
       RunPostedTasks();
@@ -280,7 +284,7 @@
     ParkableString parkable(MakeLargeString().ReleaseImpl());
     // Transient |Lock()| or |ToString()| cancel parking.
     EXPECT_TRUE(
-        parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kAlways));
+        parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kCompress));
     parkable.Impl()->Lock();
     parkable.Impl()->ToString();
     parkable.Impl()->Unlock();
@@ -290,7 +294,7 @@
     // In order to test synchronous parking below, need to park the string
     // first.
     EXPECT_TRUE(
-        parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kAlways));
+        parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kCompress));
     RunPostedTasks();
     EXPECT_TRUE(parkable.Impl()->is_parked());
     parkable.ToString();
@@ -300,16 +304,16 @@
     EXPECT_TRUE(parkable.Impl()->has_compressed_data());
     parkable.Lock();
     EXPECT_FALSE(
-        parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kAlways));
+        parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kCompress));
     parkable.Unlock();
     {
       String content = parkable.ToString();
       EXPECT_FALSE(
-          parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kAlways));
+          parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kCompress));
     }
     // Parking is synchronous.
     EXPECT_TRUE(
-        parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kAlways));
+        parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kCompress));
     EXPECT_TRUE(parkable.Impl()->is_parked());
   }
 }
@@ -319,7 +323,8 @@
   EXPECT_TRUE(parkable.may_be_parked());
   EXPECT_FALSE(parkable.Impl()->is_parked());
 
-  EXPECT_TRUE(parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kAlways));
+  EXPECT_TRUE(
+      parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kCompress));
   parkable.ToString();  // Cancels parking.
   RunPostedTasks();
   EXPECT_FALSE(parkable.Impl()->is_parked());
@@ -327,7 +332,8 @@
   EXPECT_TRUE(parkable.Impl()->has_compressed_data());
 
   // Synchronous parking.
-  EXPECT_TRUE(parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kAlways));
+  EXPECT_TRUE(
+      parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kCompress));
   EXPECT_TRUE(parkable.Impl()->is_parked());
 }
 
@@ -509,7 +515,8 @@
 // Non-regression test for crbug.com/905137.
 TEST_F(ParkableStringTest, CorrectAsanPoisoning) {
   ParkableString parkable(MakeLargeString().ReleaseImpl());
-  EXPECT_TRUE(parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kAlways));
+  EXPECT_TRUE(
+      parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kCompress));
   // A main thread task is posted once compression is done.
   while (task_environment_.GetPendingMainThreadTaskCount() == 0) {
     parkable.Lock();
@@ -531,8 +538,7 @@
   parkable.ToString();  // First decompression.
   EXPECT_FALSE(impl->is_parked());
   EXPECT_TRUE(impl->has_compressed_data());
-  EXPECT_TRUE(
-      impl->Park(ParkableStringImpl::ParkingMode::kIfCompressedDataExists));
+  EXPECT_TRUE(impl->Park(ParkableStringImpl::ParkingMode::kSynchronousOnly));
   EXPECT_TRUE(impl->is_parked());
   parkable.ToString();  // Second decompression.
 
@@ -558,7 +564,7 @@
   parkable.ToString();
   EXPECT_TRUE(parkable.Impl()->has_compressed_data());
   // No waiting, synchronous compression.
-  manager.ParkAll(ParkableStringImpl::ParkingMode::kIfCompressedDataExists);
+  manager.ParkAll(ParkableStringImpl::ParkingMode::kSynchronousOnly);
   EXPECT_TRUE(parkable.Impl()->is_parked());
   task_environment_.FastForwardUntilNoTasksRemain();
 }
@@ -701,37 +707,44 @@
 
 TEST_F(ParkableStringTest, Aging) {
   ParkableString parkable(MakeLargeString().ReleaseImpl());
-  EXPECT_TRUE(parkable.Impl()->is_young_for_testing());
+  EXPECT_EQ(ParkableStringImpl::Age::kYoung,
+            parkable.Impl()->age_for_testing());
   WaitForAging();
-  EXPECT_FALSE(parkable.Impl()->is_young_for_testing());
+  EXPECT_EQ(ParkableStringImpl::Age::kOld, parkable.Impl()->age_for_testing());
 
   parkable.Lock();
-  EXPECT_TRUE(parkable.Impl()->is_young_for_testing());
+  EXPECT_EQ(ParkableStringImpl::Age::kYoung,
+            parkable.Impl()->age_for_testing());
   // Locked strings don't age.
   WaitForAging();
-  EXPECT_TRUE(parkable.Impl()->is_young_for_testing());
+  EXPECT_EQ(ParkableStringImpl::Age::kYoung,
+            parkable.Impl()->age_for_testing());
   parkable.Unlock();
   WaitForAging();
-  EXPECT_FALSE(parkable.Impl()->is_young_for_testing());
+  EXPECT_EQ(ParkableStringImpl::Age::kOld, parkable.Impl()->age_for_testing());
 
   parkable.ToString();
-  EXPECT_TRUE(parkable.Impl()->is_young_for_testing());
+  EXPECT_EQ(ParkableStringImpl::Age::kYoung,
+            parkable.Impl()->age_for_testing());
   // No external reference, can age again.
   WaitForAging();
-  EXPECT_FALSE(parkable.Impl()->is_young_for_testing());
+  EXPECT_EQ(ParkableStringImpl::Age::kOld, parkable.Impl()->age_for_testing());
 
   // External references prevent a string from aging.
   String retained = parkable.ToString();
-  EXPECT_TRUE(parkable.Impl()->is_young_for_testing());
+  EXPECT_EQ(ParkableStringImpl::Age::kYoung,
+            parkable.Impl()->age_for_testing());
   WaitForAging();
-  EXPECT_TRUE(parkable.Impl()->is_young_for_testing());
+  EXPECT_EQ(ParkableStringImpl::Age::kYoung,
+            parkable.Impl()->age_for_testing());
 }
 
 TEST_F(ParkableStringTest, OldStringsAreParked) {
   ParkableString parkable(MakeLargeString().ReleaseImpl());
-  EXPECT_TRUE(parkable.Impl()->is_young_for_testing());
+  EXPECT_EQ(ParkableStringImpl::Age::kYoung,
+            parkable.Impl()->age_for_testing());
   WaitForAging();
-  EXPECT_FALSE(parkable.Impl()->is_young_for_testing());
+  EXPECT_EQ(ParkableStringImpl::Age::kOld, parkable.Impl()->age_for_testing());
   WaitForAging();
   EXPECT_TRUE(parkable.Impl()->is_parked());
 
@@ -890,7 +903,7 @@
   ParkableString parkable(MakeLargeString().ReleaseImpl());
 
   WaitForAging();
-  parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kAlways);
+  parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kCompress);
 
   // Advance the main thread until aging occurs. This uses RunLoop combined with
   // ThreadPoolExecutionMode::QUEUED to force the 2-seconds-delayed aging task
diff --git a/third_party/blink/renderer/platform/fonts/shaping/run_segmenter.cc b/third_party/blink/renderer/platform/fonts/shaping/run_segmenter.cc
index 910b4ba..3b0074e 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/run_segmenter.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/run_segmenter.cc
@@ -18,18 +18,22 @@
 
 RunSegmenter::RunSegmenter(const UChar* buffer,
                            unsigned buffer_size,
-                           FontOrientation run_orientation)
+                           FontOrientation run_orientation,
+                           unsigned start_offset)
     : buffer_size_(buffer_size),
-      candidate_range_(NullRange()),
+      start_offset_(start_offset),
+      candidate_range_(NullRange(start_offset)),
       script_run_iterator_(
-          std::make_unique<ScriptRunIterator>(buffer, buffer_size)),
+          std::make_unique<ScriptRunIterator>(buffer + start_offset,
+                                              buffer_size)),
       orientation_iterator_(
           run_orientation == FontOrientation::kVerticalMixed
-              ? std::make_unique<OrientationIterator>(buffer,
+              ? std::make_unique<OrientationIterator>(buffer + start_offset,
                                                       buffer_size,
                                                       run_orientation)
               : nullptr),
-      symbols_iterator_(std::make_unique<SymbolsIterator>(buffer, buffer_size)),
+      symbols_iterator_(std::make_unique<SymbolsIterator>(buffer + start_offset,
+                                                          buffer_size)),
       last_split_(0),
       script_run_iterator_position_(0),
       orientation_iterator_position_(
@@ -73,10 +77,10 @@
   last_split_ = *std::min_element(std::begin(positions), std::end(positions));
 
   candidate_range_.start = candidate_range_.end;
-  candidate_range_.end = last_split_;
+  candidate_range_.end = last_split_ + start_offset_;
   *next_range = candidate_range_;
 
-  at_end_ = last_split_ == buffer_size_;
+  at_end_ = (last_split_ == buffer_size_);
   return true;
 }
 
diff --git a/third_party/blink/renderer/platform/fonts/shaping/run_segmenter.h b/third_party/blink/renderer/platform/fonts/shaping/run_segmenter.h
index f11791d1..94c61cfe 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/run_segmenter.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/run_segmenter.h
@@ -35,13 +35,16 @@
   };
 
   // Initialize a RunSegmenter.
-  RunSegmenter(const UChar* buffer, unsigned buffer_size, FontOrientation);
+  RunSegmenter(const UChar* buffer,
+               unsigned buffer_size,
+               FontOrientation,
+               unsigned start_offset = 0);
 
   bool Consume(RunSegmenterRange*);
 
-  static RunSegmenterRange NullRange() {
-    return {0, 0, USCRIPT_INVALID_CODE, OrientationIterator::kOrientationKeep,
-            FontFallbackPriority::kText};
+  static RunSegmenterRange NullRange(unsigned offset = 0) {
+    return {offset, offset, USCRIPT_INVALID_CODE,
+            OrientationIterator::kOrientationKeep, FontFallbackPriority::kText};
   }
 
  private:
@@ -52,6 +55,7 @@
       SegmentationCategory* segmentation_category);
 
   unsigned buffer_size_;
+  unsigned start_offset_;
   RunSegmenterRange candidate_range_;
   std::unique_ptr<ScriptRunIterator> script_run_iterator_;
   std::unique_ptr<OrientationIterator> orientation_iterator_;
diff --git a/third_party/blink/renderer/platform/fonts/shaping/run_segmenter_test.cc b/third_party/blink/renderer/platform/fonts/shaping/run_segmenter_test.cc
index 8ab1e186..43c6f6d 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/run_segmenter_test.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/run_segmenter_test.cc
@@ -252,4 +252,20 @@
         FontFallbackPriority::kText}});
 }
 
+TEST_F(RunSegmenterTest, StartOffset) {
+  String text = String::FromUTF8("abcשלום");
+  text.Ensure16Bit();
+
+  // skip first 3 characters
+  unsigned start_offset = 3;
+  Vector<SegmenterExpectedRun> expect;
+  expect.push_back(SegmenterExpectedRun(
+      start_offset, text.length(), USCRIPT_HEBREW,
+      OrientationIterator::kOrientationKeep, FontFallbackPriority::kText));
+
+  RunSegmenter run_segmenter(text.Characters16(), text.length() - start_offset,
+                             FontOrientation::kHorizontal, start_offset);
+  VerifyRuns(&run_segmenter, expect);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/intercepting_canvas.h b/third_party/blink/renderer/platform/graphics/intercepting_canvas.h
index 8ede555..8038f79e 100644
--- a/third_party/blink/renderer/platform/graphics/intercepting_canvas.h
+++ b/third_party/blink/renderer/platform/graphics/intercepting_canvas.h
@@ -114,7 +114,7 @@
                      const SkMatrix*,
                      const SkPaint*) override = 0;
   void didSetMatrix(const SkMatrix&) override = 0;
-  void didConcat44(const SkScalar[16]) override = 0;
+  void didConcat44(const SkM44&) override = 0;
   void didConcat(const SkMatrix&) override = 0;
   void didScale(SkScalar, SkScalar) override = 0;
   void didTranslate(SkScalar, SkScalar) override = 0;
@@ -252,9 +252,7 @@
     Interceptor interceptor(this);
   }
 
-  void didConcat44(const SkScalar m[16]) override {
-    Interceptor interceptor(this);
-  }
+  void didConcat44(const SkM44&) override { Interceptor interceptor(this); }
 
   void didConcat(const SkMatrix& matrix) override {
     Interceptor interceptor(this);
diff --git a/third_party/blink/renderer/platform/graphics/logging_canvas.cc b/third_party/blink/renderer/platform/graphics/logging_canvas.cc
index 9fe75a4..6549038 100644
--- a/third_party/blink/renderer/platform/graphics/logging_canvas.cc
+++ b/third_party/blink/renderer/platform/graphics/logging_canvas.cc
@@ -582,7 +582,9 @@
   params->SetArray("matrix", ArrayForSkMatrix(matrix));
 }
 
-void LoggingCanvas::didConcat44(const SkScalar m[16]) {
+void LoggingCanvas::didConcat44(const SkM44& matrix) {
+  SkScalar m[16];
+  matrix.getColMajor(m);
   AutoLogger logger(this);
   JSONObject* params = logger.LogItemWithParams("concat44");
   params->SetArray("matrix44", ArrayForSkScalars(16, m));
diff --git a/third_party/blink/renderer/platform/graphics/logging_canvas.h b/third_party/blink/renderer/platform/graphics/logging_canvas.h
index 82b0097..96a856d 100644
--- a/third_party/blink/renderer/platform/graphics/logging_canvas.h
+++ b/third_party/blink/renderer/platform/graphics/logging_canvas.h
@@ -78,7 +78,7 @@
                      const SkMatrix*,
                      const SkPaint*) override;
   void didSetMatrix(const SkMatrix&) override;
-  void didConcat44(const SkScalar[16]) override;
+  void didConcat44(const SkM44&) override;
   void didConcat(const SkMatrix&) override;
   void didScale(SkScalar, SkScalar) override;
   void didTranslate(SkScalar, SkScalar) override;
diff --git a/third_party/blink/renderer/platform/instrumentation/instance_counters.h b/third_party/blink/renderer/platform/instrumentation/instance_counters.h
index 6a34431..1363d0d 100644
--- a/third_party/blink/renderer/platform/instrumentation/instance_counters.h
+++ b/third_party/blink/renderer/platform/instrumentation/instance_counters.h
@@ -55,7 +55,8 @@
   V(RTCPeerConnection)             \
   V(ResourceFetcher)               \
   V(AdSubframe)                    \
-  V(DetachedScriptState)
+  V(DetachedScriptState)           \
+  V(ArrayBufferContents)
 
 // Atomic counters of the number of instances of objects that exist.
 //
diff --git a/third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h b/third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h
index 1fe5775..69c3145 100644
--- a/third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h
+++ b/third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h
@@ -35,6 +35,8 @@
     static_assert(IsGarbageCollectedType<Owner>::value,
                   "Owner needs to be a garbage collected object");
   }
+  HeapMojoReceiver(const HeapMojoReceiver&) = delete;
+  HeapMojoReceiver& operator=(const HeapMojoReceiver&) = delete;
 
   // Methods to redirect to mojo::Receiver:
   bool is_bound() const { return wrapper_->receiver().is_bound(); }
diff --git a/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_set.h b/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_set.h
index 36b7a74..fc93427 100644
--- a/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_set.h
+++ b/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_set.h
@@ -23,24 +23,28 @@
 // TODO(crbug.com/1058076) HeapMojoWrapperMode should be removed once we ensure
 // that the interface is not used after ContextDestroyed().
 template <typename Interface,
+          typename Owner,
           HeapMojoWrapperMode Mode = HeapMojoWrapperMode::kWithContextObserver>
 class HeapMojoReceiverSet {
   DISALLOW_NEW();
 
  public:
-  using ImplPointerType = typename mojo::Receiver<Interface>::ImplPointerType;
-
-  explicit HeapMojoReceiverSet(ContextLifecycleNotifier* context)
-      : wrapper_(MakeGarbageCollected<Wrapper>(context)) {
+  explicit HeapMojoReceiverSet(Owner* owner, ContextLifecycleNotifier* context)
+      : wrapper_(MakeGarbageCollected<Wrapper>(owner, context)) {
+    static_assert(std::is_base_of<Interface, Owner>::value,
+                  "Owner should implement Interface");
+    static_assert(IsGarbageCollectedType<Owner>::value,
+                  "Owner needs to be a garbage collected object");
     DCHECK(context);
   }
+  HeapMojoReceiverSet(const HeapMojoReceiverSet&) = delete;
+  HeapMojoReceiverSet& operator=(const HeapMojoReceiverSet&) = delete;
 
   // Methods to redirect to mojo::ReceiverSet:
-  mojo::ReceiverId Add(ImplPointerType impl,
-                       mojo::PendingReceiver<Interface> receiver,
+  mojo::ReceiverId Add(mojo::PendingReceiver<Interface> receiver,
                        scoped_refptr<base::SequencedTaskRunner> task_runner) {
     DCHECK(task_runner);
-    return wrapper_->receiver_set().Add(std::move(impl), std::move(receiver),
+    return wrapper_->receiver_set().Add(wrapper_->owner(), std::move(receiver),
                                         task_runner);
   }
 
@@ -57,6 +61,9 @@
   void Trace(Visitor* visitor) { visitor->Trace(wrapper_); }
 
  private:
+  FRIEND_TEST_ALL_PREFIXES(HeapMojoReceiverSetGCWithContextObserverTest,
+                           NoClearOnConservativeGC);
+
   // Garbage collected wrapper class to add a prefinalizer.
   class Wrapper final : public GarbageCollected<Wrapper>,
                         public ContextLifecycleObserver {
@@ -64,17 +71,20 @@
     USING_GARBAGE_COLLECTED_MIXIN(Wrapper);
 
    public:
-    explicit Wrapper(ContextLifecycleNotifier* notifier) {
+    explicit Wrapper(Owner* owner, ContextLifecycleNotifier* notifier)
+        : owner_(owner) {
       SetContextLifecycleNotifier(notifier);
     }
 
     void Trace(Visitor* visitor) override {
+      visitor->Trace(owner_);
       ContextLifecycleObserver::Trace(visitor);
     }
 
     void Dispose() { receiver_set_.Clear(); }
 
     mojo::ReceiverSet<Interface>& receiver_set() { return receiver_set_; }
+    Owner* owner() { return owner_; }
 
     // ContextLifecycleObserver methods
     void ContextDestroyed() override {
@@ -83,6 +93,7 @@
     }
 
    private:
+    Member<Owner> owner_;
     mojo::ReceiverSet<Interface> receiver_set_;
   };
 
diff --git a/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_set_test.cc b/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_set_test.cc
index aa13bc2b..6f560dba 100644
--- a/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_set_test.cc
+++ b/third_party/blink/renderer/platform/mojo/heap_mojo_receiver_set_test.cc
@@ -50,29 +50,37 @@
   HeapObserverList<ContextLifecycleObserver> observers_;
 };
 
-class MockService : public sample::blink::Service {
+template <HeapMojoWrapperMode Mode>
+class HeapMojoReceiverSetGCBaseTest;
+
+template <HeapMojoWrapperMode Mode>
+class GCOwner : public GarbageCollected<GCOwner<Mode>>,
+                public sample::blink::Service {
  public:
-  MockService() = default;
+  explicit GCOwner(FakeContextNotifier* context,
+                   HeapMojoReceiverSetGCBaseTest<Mode>* test)
+      : receiver_set_(this, context), test_(test) {
+    test_->set_is_owner_alive(true);
+  }
+  void Dispose() {
+    test_->set_is_owner_alive(false);
+    ;
+  }
+  void Trace(Visitor* visitor) { visitor->Trace(receiver_set_); }
+
+  HeapMojoReceiverSet<sample::blink::Service, GCOwner, Mode>& receiver_set() {
+    return receiver_set_;
+  }
 
   void Frobinate(sample::blink::FooPtr foo,
                  Service::BazOptions baz,
                  mojo::PendingRemote<sample::blink::Port> port,
                  FrobinateCallback callback) override {}
   void GetPort(mojo::PendingReceiver<sample::blink::Port> receiver) override {}
-};
-
-template <HeapMojoWrapperMode Mode>
-class GCOwner : public GarbageCollected<GCOwner<Mode>> {
- public:
-  explicit GCOwner(FakeContextNotifier* context) : receiver_set_(context) {}
-  void Trace(Visitor* visitor) { visitor->Trace(receiver_set_); }
-
-  HeapMojoReceiverSet<sample::blink::Service, Mode>& receiver_set() {
-    return receiver_set_;
-  }
 
  private:
-  HeapMojoReceiverSet<sample::blink::Service, Mode> receiver_set_;
+  HeapMojoReceiverSet<sample::blink::Service, GCOwner, Mode> receiver_set_;
+  HeapMojoReceiverSetGCBaseTest<Mode>* test_;
 };
 
 template <HeapMojoWrapperMode Mode>
@@ -83,18 +91,23 @@
     return null_task_runner_;
   }
   GCOwner<Mode>* owner() { return owner_; }
+  void set_is_owner_alive(bool alive) { is_owner_alive_ = alive; }
 
   void ClearOwner() { owner_ = nullptr; }
 
  protected:
   void SetUp() override {
     context_ = MakeGarbageCollected<FakeContextNotifier>();
-    owner_ = MakeGarbageCollected<GCOwner<Mode>>(context());
+    owner_ = MakeGarbageCollected<GCOwner<Mode>>(context(), this);
   }
-  void TearDown() override {}
+  void TearDown() override {
+    owner_ = nullptr;
+    PreciselyCollectGarbage();
+  }
 
   Persistent<FakeContextNotifier> context_;
   Persistent<GCOwner<Mode>> owner_;
+  bool is_owner_alive_ = false;
   scoped_refptr<base::NullTaskRunner> null_task_runner_ =
       base::MakeRefCounted<base::NullTaskRunner>();
 };
@@ -111,13 +124,11 @@
 // GC the HeapMojoReceiverSet with context observer and verify that the receiver
 // is no longer part of the set, and that the service was deleted.
 TEST_F(HeapMojoReceiverSetGCWithContextObserverTest, RemovesReceiver) {
-  auto receiver_set = owner()->receiver_set();
-  MockService service;
+  auto& receiver_set = owner()->receiver_set();
   auto receiver = mojo::PendingReceiver<sample::blink::Service>(
       mojo::MessagePipe().handle0);
 
-  mojo::ReceiverId rid =
-      receiver_set.Add(&service, std::move(receiver), task_runner());
+  mojo::ReceiverId rid = receiver_set.Add(std::move(receiver), task_runner());
   EXPECT_TRUE(receiver_set.HasReceiver(rid));
 
   receiver_set.Remove(rid);
@@ -125,16 +136,35 @@
   EXPECT_FALSE(receiver_set.HasReceiver(rid));
 }
 
-// GC the HeapMojoReceiverSet without context observer and verify that the
-// receiver is no longer part of the set, and that the service was deleted.
-TEST_F(HeapMojoReceiverSetGCWithoutContextObserverTest, RemovesReceiver) {
-  auto receiver_set = owner()->receiver_set();
-  MockService service;
+// Check that the wrapper does not outlive the owner when ConservativeGC finds
+// the wrapper.
+TEST_F(HeapMojoReceiverSetGCWithContextObserverTest, NoClearOnConservativeGC) {
+  auto* wrapper = owner_->receiver_set().wrapper_.Get();
+
   auto receiver = mojo::PendingReceiver<sample::blink::Service>(
       mojo::MessagePipe().handle0);
 
   mojo::ReceiverId rid =
-      receiver_set.Add(&service, std::move(receiver), task_runner());
+      owner()->receiver_set().Add(std::move(receiver), task_runner());
+  EXPECT_TRUE(wrapper->receiver_set().HasReceiver(rid));
+
+  ClearOwner();
+  EXPECT_TRUE(is_owner_alive_);
+
+  ConservativelyCollectGarbage();
+
+  EXPECT_TRUE(wrapper->receiver_set().HasReceiver(rid));
+  EXPECT_TRUE(is_owner_alive_);
+}
+
+// GC the HeapMojoReceiverSet without context observer and verify that the
+// receiver is no longer part of the set, and that the service was deleted.
+TEST_F(HeapMojoReceiverSetGCWithoutContextObserverTest, RemovesReceiver) {
+  auto& receiver_set = owner()->receiver_set();
+  auto receiver = mojo::PendingReceiver<sample::blink::Service>(
+      mojo::MessagePipe().handle0);
+
+  mojo::ReceiverId rid = receiver_set.Add(std::move(receiver), task_runner());
   EXPECT_TRUE(receiver_set.HasReceiver(rid));
 
   receiver_set.Remove(rid);
@@ -145,13 +175,11 @@
 // GC the HeapMojoReceiverSet with context observer and verify that the receiver
 // is no longer part of the set, and that the service was deleted.
 TEST_F(HeapMojoReceiverSetGCWithContextObserverTest, ClearLeavesSetEmpty) {
-  auto receiver_set = owner()->receiver_set();
-  MockService service;
+  auto& receiver_set = owner()->receiver_set();
   auto receiver = mojo::PendingReceiver<sample::blink::Service>(
       mojo::MessagePipe().handle0);
 
-  mojo::ReceiverId rid =
-      receiver_set.Add(&service, std::move(receiver), task_runner());
+  mojo::ReceiverId rid = receiver_set.Add(std::move(receiver), task_runner());
   EXPECT_TRUE(receiver_set.HasReceiver(rid));
 
   receiver_set.Clear();
@@ -162,13 +190,11 @@
 // GC the HeapMojoReceiverSet without context observer and verify that the
 // receiver is no longer part of the set, and that the service was deleted.
 TEST_F(HeapMojoReceiverSetGCWithoutContextObserverTest, ClearLeavesSetEmpty) {
-  auto receiver_set = owner()->receiver_set();
-  MockService service;
+  auto& receiver_set = owner()->receiver_set();
   auto receiver = mojo::PendingReceiver<sample::blink::Service>(
       mojo::MessagePipe().handle0);
 
-  mojo::ReceiverId rid =
-      receiver_set.Add(&service, std::move(receiver), task_runner());
+  mojo::ReceiverId rid = receiver_set.Add(std::move(receiver), task_runner());
   EXPECT_TRUE(receiver_set.HasReceiver(rid));
 
   receiver_set.Clear();
diff --git a/third_party/blink/renderer/platform/mojo/heap_mojo_remote.h b/third_party/blink/renderer/platform/mojo/heap_mojo_remote.h
index dd5da3c..c017569 100644
--- a/third_party/blink/renderer/platform/mojo/heap_mojo_remote.h
+++ b/third_party/blink/renderer/platform/mojo/heap_mojo_remote.h
@@ -31,6 +31,8 @@
  public:
   explicit HeapMojoRemote(ContextLifecycleNotifier* notifier)
       : wrapper_(MakeGarbageCollected<Wrapper>(notifier)) {}
+  HeapMojoRemote(const HeapMojoRemote&) = delete;
+  HeapMojoRemote& operator=(const HeapMojoRemote&) = delete;
 
   // Methods to redirect to mojo::Remote.
   using Proxy = typename Interface::Proxy_;
diff --git a/third_party/blink/renderer/platform/mojo/heap_mojo_unique_receiver_set.h b/third_party/blink/renderer/platform/mojo/heap_mojo_unique_receiver_set.h
index 8479bf54..7b99f1aa 100644
--- a/third_party/blink/renderer/platform/mojo/heap_mojo_unique_receiver_set.h
+++ b/third_party/blink/renderer/platform/mojo/heap_mojo_unique_receiver_set.h
@@ -35,6 +35,9 @@
       : wrapper_(MakeGarbageCollected<Wrapper>(context)) {
     DCHECK(context);
   }
+  HeapMojoUniqueReceiverSet(const HeapMojoUniqueReceiverSet&) = delete;
+  HeapMojoUniqueReceiverSet& operator=(const HeapMojoUniqueReceiverSet&) =
+      delete;
 
   // Methods to redirect to mojo::ReceiverSet:
   mojo::ReceiverId Add(ImplPointerType impl,
diff --git a/third_party/blink/renderer/platform/mojo/heap_mojo_unique_receiver_set_test.cc b/third_party/blink/renderer/platform/mojo/heap_mojo_unique_receiver_set_test.cc
index 5438160..ec6a5d3 100644
--- a/third_party/blink/renderer/platform/mojo/heap_mojo_unique_receiver_set_test.cc
+++ b/third_party/blink/renderer/platform/mojo/heap_mojo_unique_receiver_set_test.cc
@@ -128,7 +128,7 @@
 // GC the HeapMojoUniqueReceiverSet with context observer and verify that the
 // receiver is no longer part of the set, and that the service was deleted.
 TEST_F(HeapMojoUniqueReceiverSetWithContextObserverTest, ResetsOnGC) {
-  auto receiver_set = owner()->receiver_set();
+  auto& receiver_set = owner()->receiver_set();
   auto service = std::make_unique<
       MockService<HeapMojoUniqueReceiverSetWithContextObserverTest>>(this);
   auto receiver = mojo::PendingReceiver<sample::blink::Service>(
@@ -150,7 +150,7 @@
 // GC the HeapMojoUniqueReceiverSet without context observer and verify that the
 // receiver is no longer part of the set, and that the service was deleted.
 TEST_F(HeapMojoUniqueReceiverSetWithoutContextObserverTest, ResetsOnGC) {
-  auto receiver_set = owner()->receiver_set();
+  auto& receiver_set = owner()->receiver_set();
   auto service = std::make_unique<
       MockService<HeapMojoUniqueReceiverSetWithoutContextObserverTest>>(this);
   auto receiver = mojo::PendingReceiver<sample::blink::Service>(
diff --git a/third_party/blink/renderer/platform/scheduler/common/scheduling_policy.cc b/third_party/blink/renderer/platform/scheduler/common/scheduling_policy.cc
index ca7327c..386766e 100644
--- a/third_party/blink/renderer/platform/scheduler/common/scheduling_policy.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/scheduling_policy.cc
@@ -51,6 +51,8 @@
     case Feature::kRequestedStorageAccessGrant:
     case Feature::kWebNfc:
     case Feature::kWebFileSystem:
+    case Feature::kAppBanner:
+    case Feature::kPrinting:
       return true;
   }
 }
diff --git a/third_party/blink/web_tests/FlagExpectations/layout-ng-fragment-item b/third_party/blink/web_tests/FlagExpectations/layout-ng-fragment-item
index d182e33..98cfa0b 100644
--- a/third_party/blink/web_tests/FlagExpectations/layout-ng-fragment-item
+++ b/third_party/blink/web_tests/FlagExpectations/layout-ng-fragment-item
@@ -104,7 +104,7 @@
 crbug.com/626703 external/wpt/screen-orientation/onchange-event.html [ Timeout ]
 crbug.com/626703 external/wpt/screen-orientation/orientation-reading.html [ Timeout ]
 crbug.com/645988 external/wpt/uievents/order-of-events/focus-eventfocus-manual.html [ Crash Failure ]
-crbug.com/645988 external/wpt/uievents/order-of-events/focus-events/focus-manual.html [ Failure Timeout ]
+crbug.com/645988 external/wpt/uievents/order-of-events/focus-events/focus-manual.html [ Failure ]
 crbug.com/1002514 external/wpt/web-share/share-sharePromise-internal-slot.https.html [ Crash ]
 crbug.com/982194 external/wpt/webrtc/RTCPeerConnection-ondatachannel.html [ Failure Pass ]
 crbug.com/626703 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue/outline_properties.html [ Failure ]
@@ -181,7 +181,7 @@
 crbug.com/450493 http/tests/devtools/sources/debugger-ui/continue-to-location-markers-in-top-level-function.js [ Pass ]
 crbug.com/450493 http/tests/devtools/sources/debugger-ui/continue-to-location-markers.js [ Pass ]
 crbug.com/450493 http/tests/devtools/sources/debugger/debug-inlined-scripts.js [ Failure ]
-crbug.com/851363 http/tests/devtools/sxg/sxg-prefetch-fail.js [ Failure Pass ]
+crbug.com/851363 http/tests/devtools/sxg/sxg-prefetch-fail.js [ Pass ]
 crbug.com/851363 http/tests/devtools/sxg/sxg-prefetch.js [ Pass ]
 crbug.com/420008 crbug.com/916975 http/tests/devtools/tracing/timeline-misc/timeline-event-causes.js [ Crash Failure Pass Timeout ]
 crbug.com/982194 http/tests/input/discard-events-to-unstable-iframe.html [ Failure ]
@@ -275,7 +275,6 @@
 crbug.com/982194 external/wpt/css/css-fonts/font-variant-descriptor-01.html [ Failure ]
 crbug.com/982194 external/wpt/css/css-fonts/font-variant-position-01.html [ Pass ]
 crbug.com/982194 external/wpt/css/css-fonts/font-variant-position.html [ Failure ]
-crbug.com/982194 external/wpt/css/css-fonts/variations/font-descriptor-range-reversed.html [ Pass ]
 crbug.com/982194 external/wpt/css/css-grid/alignment/grid-baseline-align-cycles-001.html [ Failure ]
 crbug.com/982194 external/wpt/css/css-grid/alignment/grid-self-alignment-baseline-with-grid-001.html [ Failure ]
 crbug.com/982194 external/wpt/css/css-grid/alignment/grid-self-alignment-baseline-with-grid-002.html [ Failure ]
@@ -284,6 +283,7 @@
 crbug.com/982194 external/wpt/css/css-grid/animation/grid-template-columns-001.html [ Failure ]
 crbug.com/982194 external/wpt/css/css-grid/animation/grid-template-rows-001.html [ Failure ]
 crbug.com/982194 external/wpt/css/css-grid/grid-child-percent-basis-resize-1.html [ Failure ]
+crbug.com/982194 external/wpt/css/css-images/image-orientation/svg-image-orientation.html [ Pass ]
 crbug.com/982194 external/wpt/css/css-images/tiled-gradients.html [ Failure ]
 crbug.com/982194 external/wpt/css/css-intrinsic-size/intrinsic-size-015.html [ Crash Pass ]
 crbug.com/982194 external/wpt/css/css-lists/content-property/marker-text-matches-circle.html [ Failure ]
@@ -442,7 +442,6 @@
 crbug.com/982194 external/wpt/css/css-text/word-break/word-break-normal-my-000.html [ Failure ]
 crbug.com/982194 external/wpt/css/css-text/writing-system/writing-system-text-transform-001.html [ Failure ]
 crbug.com/982194 external/wpt/css/css-transforms/perspective-transforms-equivalence.html [ Failure ]
-crbug.com/982194 external/wpt/css/css-ui/appearance-textfield-001.html [ Pass ]
 crbug.com/982194 external/wpt/css/css-ui/box-sizing-014.html [ Failure ]
 crbug.com/982194 external/wpt/css/css-ui/box-sizing-019.html [ Failure ]
 crbug.com/982194 external/wpt/css/css-ui/box-sizing-024.html [ Failure ]
@@ -453,7 +452,6 @@
 crbug.com/982194 external/wpt/css/css-ui/text-overflow-015.html [ Failure ]
 crbug.com/982194 external/wpt/css/css-ui/text-overflow-021.html [ Failure ]
 crbug.com/982194 external/wpt/css/css-ui/text-overflow-026.html [ Failure ]
-crbug.com/982194 external/wpt/css/css-ui/webkit-appearance-textfield-001.html [ Pass ]
 crbug.com/982194 external/wpt/css/css-values/ch-unit-017.html [ Failure ]
 crbug.com/982194 external/wpt/css/css-will-change/will-change-abspos-cb-001.html [ Failure ]
 crbug.com/982194 external/wpt/css/css-will-change/will-change-abspos-cb-dynamic-001.html [ Failure ]
@@ -470,6 +468,7 @@
 crbug.com/982194 external/wpt/css/css-writing-modes/text-combine-upright-value-all-002.html [ Failure ]
 crbug.com/982194 external/wpt/css/css-writing-modes/text-combine-upright-value-all-003.html [ Failure ]
 crbug.com/982194 external/wpt/css/cssom-view/MediaQueryList-addListener-handleEvent.html [ Pass ]
+crbug.com/982194 external/wpt/css/cssom/CSSStyleSheet-constructable-disallow-import.tentative.html [ Pass ]
 crbug.com/982194 external/wpt/css/filter-effects/css-filters-animation-combined-001.html [ Failure ]
 crbug.com/982194 external/wpt/css/mediaqueries/viewport-script-dynamic.html [ Failure ]
 crbug.com/982194 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/align3/flex-abspos-staticpos-align-content-001.html [ Failure ]
@@ -625,7 +624,7 @@
 crbug.com/982194 external/wpt/forced-colors-mode/forced-colors-mode-19.html [ Failure ]
 crbug.com/982194 external/wpt/forced-colors-mode/forced-colors-mode-23.html [ Failure ]
 crbug.com/982194 external/wpt/forced-colors-mode/forced-colors-mode-26.tentative.html [ Pass ]
-crbug.com/982194 external/wpt/geolocation-API/PositionOptions.https.html [ Failure Pass ]
+crbug.com/982194 external/wpt/geolocation-API/PositionOptions.https.html [ Failure ]
 crbug.com/982194 external/wpt/html/cross-origin-opener-policy/coep-blob-popup.https.html [ Pass ]
 crbug.com/982194 external/wpt/html/rendering/non-replaced-elements/tables/table-border-1.html [ Failure ]
 crbug.com/982194 external/wpt/html/rendering/non-replaced-elements/tables/table-border-3q.html [ Failure ]
@@ -707,7 +706,7 @@
 crbug.com/982194 external/wpt/trusted-types/eval-csp-no-tt.tentative.html [ Failure ]
 crbug.com/982194 external/wpt/trusted-types/eval-no-csp-no-tt-default-policy.tentative.html [ Failure ]
 crbug.com/982194 external/wpt/trusted-types/eval-no-csp-no-tt.tentative.html [ Failure ]
-crbug.com/982194 external/wpt/webaudio/the-audio-api/the-audioworklet-interface/suspended-context-messageport.https.html [ Failure ]
+crbug.com/982194 external/wpt/webaudio/the-audio-api/the-audioworklet-interface/suspended-context-messageport.https.html [ Crash Failure ]
 crbug.com/982194 external/wpt/websockets/opening-handshake/005.html [ Pass ]
 crbug.com/982194 external/wpt/webvtt/rendering/cues-with-video/processing-model/2_cues_overlapping_completely_move_up.html [ Failure ]
 crbug.com/982194 external/wpt/webvtt/rendering/cues-with-video/processing-model/2_cues_overlapping_partially_move_down.html [ Failure ]
@@ -929,7 +928,7 @@
 crbug.com/982194 http/tests/devtools/indexeddb/database-refresh-view.js [ Pass ]
 crbug.com/982194 http/tests/devtools/network/network-eventsource.js [ Pass ]
 crbug.com/982194 http/tests/devtools/network/network-search.js [ Pass ]
-crbug.com/982194 http/tests/devtools/oopif/oopif-storage.js [ Failure Pass ]
+crbug.com/982194 http/tests/devtools/oopif/oopif-storage.js [ Pass ]
 crbug.com/982194 http/tests/devtools/resource-tree/resource-tree-frame-navigate.js [ Pass ]
 crbug.com/982194 http/tests/devtools/resource-tree/resource-tree-htmlimports.js [ Pass ]
 crbug.com/982194 http/tests/devtools/service-workers/user-agent-override.js [ Pass ]
@@ -948,7 +947,7 @@
 crbug.com/982194 jquery/manipulation.html [ Pass Timeout ]
 crbug.com/982194 jquery/offset.html [ Pass ]
 crbug.com/982194 jquery/traversing.html [ Pass ]
-crbug.com/982194 media/video-canvas-draw.html [ Crash Failure Pass ]
+crbug.com/982194 media/video-canvas-draw.html [ Failure Pass ]
 crbug.com/982194 virtual/android/url-bar/bottom-and-top-fixed-sticks-to-top.html [ Failure ]
 crbug.com/908347 virtual/audio-service/media/autoplay/webaudio-audio-context-resume.html [ Failure Pass ]
 crbug.com/942951 virtual/audio-service/media/controls/controls-layout-in-different-size.html [ Pass ]
diff --git a/third_party/blink/web_tests/NeverFixTests b/third_party/blink/web_tests/NeverFixTests
index b2a97de..09a8522 100644
--- a/third_party/blink/web_tests/NeverFixTests
+++ b/third_party/blink/web_tests/NeverFixTests
@@ -2119,3 +2119,6 @@
 
 # These tests require a preferred dark color-scheme and are only run as virtual tests
 external/wpt/css/css-color-adjust/rendering/dark-color-scheme/* [ Skip ]
+crbug.com/626703 [ Linux ] external/wpt/payment-request/dynamically-change-shipping-options-manual.https.html [ Skip ]
+crbug.com/626703 [ Mac ] external/wpt/payment-request/dynamically-change-shipping-options-manual.https.html [ Skip ]
+crbug.com/626703 [ Win ] external/wpt/payment-request/dynamically-change-shipping-options-manual.https.html [ Skip ]
diff --git a/third_party/blink/web_tests/css3/filters/effect-reference-delete-expected.html b/third_party/blink/web_tests/css3/filters/effect-reference-delete-expected.html
deleted file mode 100644
index 3eaa4b32..0000000
--- a/third_party/blink/web_tests/css3/filters/effect-reference-delete-expected.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<html>
-  <body>
-    <img src="resources/reference.png">
-  </body>
-</html>
-
diff --git a/third_party/blink/web_tests/css3/filters/effect-reference-delete.html b/third_party/blink/web_tests/css3/filters/effect-reference-delete.html
deleted file mode 100644
index fa77ccf..0000000
--- a/third_party/blink/web_tests/css3/filters/effect-reference-delete.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE html>
-<script src="../../resources/run-after-layout-and-paint.js"></script>
-<svg width="0" height="0">
-  <defs>
-    <filter id="MyFilter">
-      <feColorMatrix type="hueRotate" values="180"/>
-    </filter>
-  </defs>
-</svg>
-<img style="filter: url(#MyFilter);" src="resources/reference.png">
-<script>
-runAfterLayoutAndPaint(function() {
-  document.querySelector('svg').remove();
-}, true);
-</script>
diff --git a/third_party/blink/web_tests/css3/filters/effect-reference-merge-no-inputs-expected.html b/third_party/blink/web_tests/css3/filters/effect-reference-merge-no-inputs-expected.html
deleted file mode 100644
index f718ea6..0000000
--- a/third_party/blink/web_tests/css3/filters/effect-reference-merge-no-inputs-expected.html
+++ /dev/null
@@ -1,2 +0,0 @@
-<!DOCTYPE html>
-<div style="width: 100px; height: 100px; background-color: green"></div>
diff --git a/third_party/blink/web_tests/css3/filters/effect-reference-merge-no-inputs.html b/third_party/blink/web_tests/css3/filters/effect-reference-merge-no-inputs.html
deleted file mode 100644
index 8de182f3..0000000
--- a/third_party/blink/web_tests/css3/filters/effect-reference-merge-no-inputs.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<!DOCTYPE html>
-<style>
-#target {
-    width: 100px;
-    height: 100px;
-    background-color: green;
-    filter: url(#emptyMerge);
-}
-</style>
-<div id="target"></div>
-<svg height="0">
-  <filter id="emptyMerge">
-    <feColorMatrix values="0 1 0 0 0, 0 0 0 0 0, 0 0 0 0 0, 0 0 0 1 0" result="red"/>
-    <feMerge/>
-    <feComposite in2="SourceGraphic"/>
-  </filter>
-</svg>
diff --git a/third_party/blink/web_tests/css3/filters/effect-reference-rename-expected.html b/third_party/blink/web_tests/css3/filters/effect-reference-rename-expected.html
deleted file mode 100644
index e7928ba..0000000
--- a/third_party/blink/web_tests/css3/filters/effect-reference-rename-expected.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<html>
-  <body>
-    <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="0" height="0">
-      <defs>
-        <filter id="MyFilter">
-          <feColorMatrix type="hueRotate" values="180"/>
-        </filter>
-      </defs>
-    </svg><img style="filter: url(#MyFilter);" src="resources/reference.png">
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/css3/filters/effect-reference-rename.html b/third_party/blink/web_tests/css3/filters/effect-reference-rename.html
deleted file mode 100644
index 3ad63e54..0000000
--- a/third_party/blink/web_tests/css3/filters/effect-reference-rename.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<html>
-  <body>
-    <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="0" height="0">
-      <defs>
-        <filter id="NotMyFilter">
-          <feColorMatrix type="hueRotate" values="180"/>
-        </filter>
-      </defs>
-    </svg><img style="filter: url(#MyFilter);" src="resources/reference.png">
-  </body>
-</html>
-<script>
-document.getElementById("NotMyFilter").id = "MyFilter";
-</script>
diff --git a/third_party/blink/web_tests/css3/filters/filter-region-negative-transformed-child.html b/third_party/blink/web_tests/css3/filters/filter-region-negative-transformed-child.html
deleted file mode 100644
index d6b9862..0000000
--- a/third_party/blink/web_tests/css3/filters/filter-region-negative-transformed-child.html
+++ /dev/null
@@ -1,33 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0" version="1.1">
-  <defs>
-    <filter id="f1" color-interpolation-filters="sRGB">
-      <feColorMatrix type="matrix" values="-1 0 0 0 1  0 -1 0 0 1  0 0 -1 0 1  0 0 0 1 0"/>
-    </filter>
-  </defs>
-</svg>
-<style>
-.box {
-  width: 100px;
-  height: 100px;
-  position: absolute;
-}
-.green {
-  background-color: green;
-}
-.blue {
-  background-color: blue;
-}
-.above {
-  top: -100px;
-}
-.parent {
-  filter: url(#f1);
-  background-color: white;
-  position: relative;
-  top: 100px;
-}
-</style>
-<div class="parent">
-<div class="green box"></div>
-<div class="blue box above"></div>
-</div>
diff --git a/third_party/blink/web_tests/css3/filters/reference-filter-update-on-attribute-change.html b/third_party/blink/web_tests/css3/filters/reference-filter-update-on-attribute-change.html
deleted file mode 100644
index 2e703e4b..0000000
--- a/third_party/blink/web_tests/css3/filters/reference-filter-update-on-attribute-change.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<head>
-  <script>
-    function run() {
-      document.getElementById('color').setAttribute('values', '90');
-    }
- </script>
-</head>
-<body onload="run()">
-   <svg xmlns="http://www.w3.org/2000/svg" width="0" height="0" version="1.1">
-    <defs>
-      <filter id="MyFilter">
-        <fecolormatrix id="color" type="hueRotate"></fecolormatrix>
-      </filter>
-    </defs>
-  </svg>
-  <div style="filter: url(#MyFilter); filter: url(#MyFilter); width:100px; height:100px; background-color:red;"></div>
-</body>
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_7.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_7.json
index f36ba0c..9d420c8e 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_7.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_7.json
@@ -43,6 +43,12 @@
      {}
     ]
    ],
+   "css/css-flexbox/remove-out-of-flow-child-crash.html": [
+    [
+     "css/css-flexbox/remove-out-of-flow-child-crash.html",
+     {}
+    ]
+   ],
    "css/css-flexbox/zero-content-size-with-scrollbar-crash.html": [
     [
      "css/css-flexbox/zero-content-size-with-scrollbar-crash.html",
@@ -121,6 +127,12 @@
      {}
     ]
    ],
+   "css/css-sizing/min-content-negative-margin-crash.html": [
+    [
+     "css/css-sizing/min-content-negative-margin-crash.html",
+     {}
+    ]
+   ],
    "css/css-tables/visibility-collapse-colspan-crash.html": [
     [
      "css/css-tables/visibility-collapse-colspan-crash.html",
@@ -199,6 +211,12 @@
      {}
     ]
    ],
+   "html/rendering/the-details-element/empty-crash.html": [
+    [
+     "html/rendering/the-details-element/empty-crash.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/the-img-element/image-loading-lazy-subframe-detached-crash.html": [
     [
      "html/semantics/embedded-content/the-img-element/image-loading-lazy-subframe-detached-crash.html",
@@ -6717,6 +6735,12 @@
      {}
     ]
    ],
+   "payment-request/dynamically-change-shipping-options-manual.https.html": [
+    [
+     "payment-request/dynamically-change-shipping-options-manual.https.html",
+     {}
+    ]
+   ],
    "payment-request/payment-request-hasenrolledinstrument-method-manual.tentative.https.html": [
     [
      "payment-request/payment-request-hasenrolledinstrument-method-manual.tentative.https.html",
@@ -29895,6 +29919,18 @@
      {}
     ]
    ],
+   "css/CSS2/text/bidi-flag-emoji.html": [
+    [
+     "css/CSS2/text/bidi-flag-emoji.html",
+     [
+      [
+       "/css/CSS2/text/bidi-flag-emoji-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/CSS2/text/bidi-span-001.html": [
     [
      "css/CSS2/text/bidi-span-001.html",
@@ -42207,6 +42243,18 @@
      {}
     ]
    ],
+   "css/css-contain/contain-size-063.html": [
+    [
+     "css/css-contain/contain-size-063.html",
+     [
+      [
+       "/css/css-contain/reference/contain-size-063-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-contain/contain-size-baseline-001.html": [
     [
      "css/css-contain/contain-size-baseline-001.html",
@@ -49587,6 +49635,18 @@
      {}
     ]
    ],
+   "css/css-flexbox/overflow-auto-007.html": [
+    [
+     "css/css-flexbox/overflow-auto-007.html",
+     [
+      [
+       "/css/css-flexbox/reference/overflow-auto-007-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-flexbox/overflow-top-left.html": [
     [
      "css/css-flexbox/overflow-top-left.html",
@@ -49863,6 +49923,18 @@
      {}
     ]
    ],
+   "css/css-flexbox/svg-root-as-flex-item-001.html": [
+    [
+     "css/css-flexbox/svg-root-as-flex-item-001.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-flexbox/table-as-item-auto-min-width.html": [
     [
      "css/css-flexbox/table-as-item-auto-min-width.html",
@@ -108443,6 +108515,30 @@
      {}
     ]
    ],
+   "css/filter-effects/effect-reference-lighting-no-light.tentative.html": [
+    [
+     "css/filter-effects/effect-reference-lighting-no-light.tentative.html",
+     [
+      [
+       "/css/filter-effects/reference/effect-reference-lighting-no-light.tentative-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/filter-effects/effect-reference-rename-001.html": [
+    [
+     "css/filter-effects/effect-reference-rename-001.html",
+     [
+      [
+       "/css/filter-effects/reference/effect-reference-rename-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/filter-effects/empty-element-with-filter.html": [
     [
      "css/filter-effects/empty-element-with-filter.html",
@@ -108887,6 +108983,18 @@
      {}
     ]
    ],
+   "css/filter-effects/reference-filter-update-on-attribute-change-001.html": [
+    [
+     "css/filter-effects/reference-filter-update-on-attribute-change-001.html",
+     [
+      [
+       "/css/filter-effects/reference/reference-filter-update-on-attribute-change-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/filter-effects/svg-feflood-001.html": [
     [
      "css/filter-effects/svg-feflood-001.html",
@@ -123827,6 +123935,78 @@
      {}
     ]
    ],
+   "html/rendering/widgets/the-select-element/option-add-label.html": [
+    [
+     "html/rendering/widgets/the-select-element/option-add-label.html",
+     [
+      [
+       "/html/rendering/widgets/the-select-element/option-label-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "html/rendering/widgets/the-select-element/option-empty-label-to-empty-string.html": [
+    [
+     "html/rendering/widgets/the-select-element/option-empty-label-to-empty-string.html",
+     [
+      [
+       "/html/rendering/widgets/the-select-element/option-label-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "html/rendering/widgets/the-select-element/option-empty-label.html": [
+    [
+     "html/rendering/widgets/the-select-element/option-empty-label.html",
+     [
+      [
+       "/html/rendering/widgets/the-select-element/option-label-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "html/rendering/widgets/the-select-element/option-label-and-text.html": [
+    [
+     "html/rendering/widgets/the-select-element/option-label-and-text.html",
+     [
+      [
+       "/html/rendering/widgets/the-select-element/option-label-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "html/rendering/widgets/the-select-element/option-only-label.html": [
+    [
+     "html/rendering/widgets/the-select-element/option-only-label.html",
+     [
+      [
+       "/html/rendering/widgets/the-select-element/option-label-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "html/rendering/widgets/the-select-element/option-rm-label.html": [
+    [
+     "html/rendering/widgets/the-select-element/option-rm-label.html",
+     [
+      [
+       "/html/rendering/widgets/the-select-element/option-label-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "html/semantics/document-metadata/the-link-element/link-rel-attribute-ascii-case-insensitive.html": [
     [
      "html/semantics/document-metadata/the-link-element/link-rel-attribute-ascii-case-insensitive.html",
@@ -139853,6 +140033,9 @@
    "css/CSS2/text/OWNERS": [
     []
    ],
+   "css/CSS2/text/bidi-flag-emoji-ref.html": [
+    []
+   ],
    "css/CSS2/text/bidi-span-001-ref.html": [
     []
    ],
@@ -141842,6 +142025,9 @@
    "css/css-contain/reference/contain-size-062-ref.html": [
     []
    ],
+   "css/css-contain/reference/contain-size-063-ref.html": [
+    []
+   ],
    "css/css-contain/reference/contain-size-breaks-001-ref.html": [
     []
    ],
@@ -143000,6 +143186,9 @@
    "css/css-flexbox/reference/overflow-auto-005-ref.html": [
     []
    ],
+   "css/css-flexbox/reference/overflow-auto-007-ref.html": [
+    []
+   ],
    "css/css-flexbox/reference/percentage-size-subitems-001-ref.html": [
     []
    ],
@@ -159761,6 +159950,12 @@
    "css/filter-effects/reference/effect-reference-after-001-ref.html": [
     []
    ],
+   "css/filter-effects/reference/effect-reference-lighting-no-light.tentative-ref.html": [
+    []
+   ],
+   "css/filter-effects/reference/effect-reference-rename-001-ref.html": [
+    []
+   ],
    "css/filter-effects/reference/empty-element-with-filter-ref.html": [
     []
    ],
@@ -159785,6 +159980,9 @@
    "css/filter-effects/reference/green-blue-stripe-100x100.html": [
     []
    ],
+   "css/filter-effects/reference/reference-filter-update-on-attribute-change-001-ref.html": [
+    []
+   ],
    "css/filter-effects/reference/svg-feflood-ref.html": [
     []
    ],
@@ -162371,9 +162569,6 @@
    "dom/nodes/Document-createProcessingInstruction.js": [
     []
    ],
-   "dom/nodes/DocumentFragment-getElementById-expected.txt": [
-    []
-   ],
    "dom/nodes/Element-closest-expected.txt": [
     []
    ],
@@ -164039,9 +164234,6 @@
    "event-timing/META.yml": [
     []
    ],
-   "event-timing/idlharness.any-expected.txt": [
-    []
-   ],
    "event-timing/resources/crossiframe-childframe.html": [
     []
    ],
@@ -170924,6 +171116,9 @@
    "html/rendering/widgets/button-layout/propagate-text-decoration-ref.html": [
     []
    ],
+   "html/rendering/widgets/the-select-element/option-label-ref.html": [
+    []
+   ],
    "html/resources/common.js": [
     []
    ],
@@ -176747,6 +176942,12 @@
    "origin-policy/policies/op9 csp-valid-with-multi-item-array.json": [
     []
    ],
+   "origin-policy/policies/op97 utf-8-with-bom.json": [
+    []
+   ],
+   "origin-policy/policies/op98 utf-16le.json": [
+    []
+   ],
    "origin-policy/policies/op99 csp-valid-manifest-with-404.json": [
     []
    ],
@@ -220436,6 +220637,12 @@
      {}
     ]
    ],
+   "css/css-flexbox/relayout-image-load.html": [
+    [
+     "css/css-flexbox/relayout-image-load.html",
+     {}
+    ]
+   ],
    "css/css-flexbox/shrinking-column-flexbox.html": [
     [
      "css/css-flexbox/shrinking-column-flexbox.html",
@@ -252762,6 +252969,14 @@
      }
     ]
    ],
+   "event-timing/event-click-counts.html": [
+    [
+     "event-timing/event-click-counts.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
    "event-timing/idlharness.any.js": [
     [
      "event-timing/idlharness.any.html",
@@ -290383,6 +290598,18 @@
      {}
     ]
    ],
+   "origin-policy/bad-server/manifest-utf16le.https.html": [
+    [
+     "origin-policy/bad-server/manifest-utf16le.https.html",
+     {}
+    ]
+   ],
+   "origin-policy/bad-server/manifest-utf8-with-bom.https.html": [
+    [
+     "origin-policy/bad-server/manifest-utf8-with-bom.https.html",
+     {}
+    ]
+   ],
    "origin-policy/content-security/comma-in-policy.https.html": [
     [
      "origin-policy/content-security/comma-in-policy.https.html",
@@ -291162,9 +291389,9 @@
      {}
     ]
    ],
-   "payment-method-id/payment-request-ctor-pmi-handling.https.html": [
+   "payment-method-id/payment-request-ctor-pmi-handling.https.sub.html": [
     [
-     "payment-method-id/payment-request-ctor-pmi-handling.https.html",
+     "payment-method-id/payment-request-ctor-pmi-handling.https.sub.html",
      {}
     ]
    ],
@@ -291360,21 +291587,21 @@
      }
     ]
    ],
-   "payment-request/payment-request-constructor.https.html": [
+   "payment-request/payment-request-constructor.https.sub.html": [
     [
-     "payment-request/payment-request-constructor.https.html",
+     "payment-request/payment-request-constructor.https.sub.html",
      {}
     ]
    ],
-   "payment-request/payment-request-ctor-currency-code-checks.https.html": [
+   "payment-request/payment-request-ctor-currency-code-checks.https.sub.html": [
     [
-     "payment-request/payment-request-ctor-currency-code-checks.https.html",
+     "payment-request/payment-request-ctor-currency-code-checks.https.sub.html",
      {}
     ]
    ],
-   "payment-request/payment-request-ctor-pmi-handling.https.html": [
+   "payment-request/payment-request-ctor-pmi-handling.https.sub.html": [
     [
-     "payment-request/payment-request-ctor-pmi-handling.https.html",
+     "payment-request/payment-request-ctor-pmi-handling.https.sub.html",
      {}
     ]
    ],
@@ -343382,7 +343609,7 @@
    "support"
   ],
   ".well-known/origin-policy": [
-   "15355ce0d91b3ed43d9dfa110cc3f6c597812a74",
+   "d0de31e693cb7fa593c7b0147981646341ab7d34",
    "support"
   ],
   "2dcontext/2x2.png": [
@@ -351538,7 +351765,7 @@
    "support"
   ],
   "bluetooth/README.md": [
-   "dcf3d2832c33f72e8dce2356956baac1d83eafed",
+   "e7997c9fa26d86cb614bb5ad0dc5fdaa11d21f41",
    "support"
   ],
   "bluetooth/adapter/adapter-absent-getAvailability.https.window.js": [
@@ -370865,6 +371092,14 @@
    "53463b38f4154029f9fadf7c337119f9828f57b4",
    "support"
   ],
+  "css/CSS2/text/bidi-flag-emoji-ref.html": [
+   "84585a264fd30383a5b60839185b1151b08c6bd0",
+   "support"
+  ],
+  "css/CSS2/text/bidi-flag-emoji.html": [
+   "a184db265942723a7728030390cedf2eccaa15f2",
+   "reftest"
+  ],
   "css/CSS2/text/bidi-span-001-ref.html": [
    "594847b128522adae1b7b49dbe739b00012feb9b",
    "support"
@@ -381449,6 +381684,10 @@
    "60cb194242894b540aaa50c6990e7cbcb491e27e",
    "reftest"
   ],
+  "css/css-contain/contain-size-063.html": [
+   "31a6015cac35faa04b8f77d4388e429e2266ffdd",
+   "reftest"
+  ],
   "css/css-contain/contain-size-baseline-001.html": [
    "0ffed1b3b6a08831792b0a5ac40d1340c142c48d",
    "reftest"
@@ -381837,6 +382076,10 @@
    "dbfa77f6ac0dfdc03d2f8a8b0407a704617c73a7",
    "support"
   ],
+  "css/css-contain/reference/contain-size-063-ref.html": [
+   "9544ebcac23af0c2caaa279154878c10349990ae",
+   "support"
+  ],
   "css/css-contain/reference/contain-size-breaks-001-ref.html": [
    "b807ea5a1160a4d29e46b91ca283c45b3c2fdeb5",
    "support"
@@ -383814,7 +384057,7 @@
    "testharness"
   ],
   "css/css-flexbox/flex-one-sets-flex-basis-to-zero-px.html": [
-   "46b715f74fd62d08028afbeb2b0b31118e47e7ed",
+   "8fca136352ff7d9a838616d73f809da7cff44ba0",
    "testharness"
   ],
   "css/css-flexbox/flex-order-ref.html": [
@@ -386241,6 +386484,10 @@
    "be0f8f19abb0b675af648fbd54799ed60d6ab32f",
    "testharness"
   ],
+  "css/css-flexbox/overflow-auto-007.html": [
+   "1bb6230c3da33340605a31afb178236598472b60",
+   "reftest"
+  ],
   "css/css-flexbox/overflow-top-left-ref.html": [
    "48b2aa88158b6301c7c7df3d7af84d9d96192761",
    "support"
@@ -386677,6 +386924,10 @@
    "ace792e456c12f40e52ae50d51d05fd6a449a628",
    "support"
   ],
+  "css/css-flexbox/reference/overflow-auto-007-ref.html": [
+   "1cf9eea0e99bfe4a9bcc2999898315611d197f02",
+   "support"
+  ],
   "css/css-flexbox/reference/percentage-size-subitems-001-ref.html": [
    "b9883c5f2e7af712402ec27ed40f100d974669b6",
    "support"
@@ -386741,6 +386992,14 @@
    "0569d5143981259400bac7f5998e56338e617ef1",
    "testharness"
   ],
+  "css/css-flexbox/relayout-image-load.html": [
+   "30091c5681d54efb90440bc6049616bbefb9ad99",
+   "testharness"
+  ],
+  "css/css-flexbox/remove-out-of-flow-child-crash.html": [
+   "dfffdffd8d6fe2e65aa72aef94cb0d953fed21ca",
+   "crashtest"
+  ],
   "css/css-flexbox/scrollbars-auto-ref.html": [
    "590b533d8d25ac45dbeb1e7eab7cd02f3c1e8b5b",
    "support"
@@ -387017,6 +387276,10 @@
    "59843ae54b64f6ce4f7e616d4be491c911ea84cf",
    "support"
   ],
+  "css/css-flexbox/svg-root-as-flex-item-001.html": [
+   "d42cf652dede8aa72af6c78aa12324ae824c1655",
+   "reftest"
+  ],
   "css/css-flexbox/table-as-item-auto-min-width.html": [
    "66a77327f0f25e07db87e342ebb590358d045f7a",
    "reftest"
@@ -410893,6 +411156,10 @@
    "9a3361a5e2926885e355c837981c0f4b535dc512",
    "reftest"
   ],
+  "css/css-sizing/min-content-negative-margin-crash.html": [
+   "7a4dff81fa09cd69963466f03d2bb53715dc17db",
+   "crashtest"
+  ],
   "css/css-sizing/min-max-content-orthogonal-flow-crash-001.html": [
    "d2617f8aa2d1c966e394abb1d1617c012ea4648e",
    "testharness"
@@ -440973,6 +441240,14 @@
    "a6de2465027e99ff6239dd45524862465dde847f",
    "reftest"
   ],
+  "css/filter-effects/effect-reference-lighting-no-light.tentative.html": [
+   "beefd47a544d5c82b4b1d468ce99938e6d9924d9",
+   "reftest"
+  ],
+  "css/filter-effects/effect-reference-rename-001.html": [
+   "6c8374536f4cf748784b7a58fc158d230ea3557f",
+   "reftest"
+  ],
   "css/filter-effects/empty-element-with-filter.html": [
    "3e8fc7e164cde54a8ff81a241909c2f729f32afb",
    "reftest"
@@ -441305,6 +441580,10 @@
    "c39088842efb1d50335942cef5c20cd50e0c1e6b",
    "testharness"
   ],
+  "css/filter-effects/reference-filter-update-on-attribute-change-001.html": [
+   "cc5ac7c65d720804953df11f2b2cab268e383610",
+   "reftest"
+  ],
   "css/filter-effects/reference/backdrop-filters-grayscale-001-ref.html": [
    "eb403f16a0030aca22fefbf919daa987aaa2ee50",
    "support"
@@ -441333,6 +441612,14 @@
    "45192b13451fdfe2f00c17dbc84d30a770426e86",
    "support"
   ],
+  "css/filter-effects/reference/effect-reference-lighting-no-light.tentative-ref.html": [
+   "e863a6703b2acebbdb10a5eef342cbbd1b6b5bc9",
+   "support"
+  ],
+  "css/filter-effects/reference/effect-reference-rename-001-ref.html": [
+   "fe3beae2d4997a7603153c5c885f01c7ca656bcd",
+   "support"
+  ],
   "css/filter-effects/reference/empty-element-with-filter-ref.html": [
    "cf2c997f6c0d60cac9896c0b0014189cea7790bc",
    "support"
@@ -441365,6 +441652,10 @@
    "01546f115d112aa27495b3fd45347b22e30fe7ee",
    "support"
   ],
+  "css/filter-effects/reference/reference-filter-update-on-attribute-change-001-ref.html": [
+   "91326ef585e6910cd499ad2d6650f18fca486921",
+   "support"
+  ],
   "css/filter-effects/reference/svg-feflood-ref.html": [
    "5623b08ecd71b292e698ee249a79b59d0046300f",
    "support"
@@ -451233,10 +451524,6 @@
    "e97a7c483605cc111a429564fa193cc36eb8d07a",
    "testharness"
   ],
-  "dom/nodes/DocumentFragment-getElementById-expected.txt": [
-   "1046305df497f8b2b5c93f68a70920b0d1cc6325",
-   "support"
-  ],
   "dom/nodes/DocumentFragment-getElementById.html": [
    "ce0d302c12b5c4bd07ec8f4aee675b2060f4dc72",
    "testharness"
@@ -456237,9 +456524,9 @@
    "55e2becfcbcfa3feba1473ddcd17e15a30adbfc0",
    "testharness"
   ],
-  "event-timing/idlharness.any-expected.txt": [
-   "235a3974bfba1c14b02fbe9b00799f0813eb2151",
-   "support"
+  "event-timing/event-click-counts.html": [
+   "5c67ac8708271a2d26cdb5b74aaaa8629398b291",
+   "testharness"
   ],
   "event-timing/idlharness.any.js": [
    "5ee98548fb6f2209b8c4b5346830c0d723e68170",
@@ -457006,7 +457293,7 @@
    "testharness"
   ],
   "feature-policy/payment-allowed-by-feature-policy.https.sub.html": [
-   "ccf5f698b4124bbbaba0af6738164558fa1df3bf",
+   "ae77daa81517be8b79ad420ba0fb0416c6a501d3",
    "testharness"
   ],
   "feature-policy/payment-allowed-by-feature-policy.https.sub.html.headers": [
@@ -471677,6 +471964,10 @@
    "445b4e483d00c8aabfa76a946d8cb0871e479c7d",
    "reftest"
   ],
+  "html/rendering/the-details-element/empty-crash.html": [
+   "d409eff4a88c88011e7a8ffc48d1dc7e71462d7a",
+   "crashtest"
+  ],
   "html/rendering/the-details-element/single-summary.html": [
    "1f09e7e75f9126982a07902ae0693f9ea2fd5823",
    "support"
@@ -471777,6 +472068,34 @@
    "84aa5602ac1c8cdfb8f7d6e88f4270f72a4422c3",
    "testharness"
   ],
+  "html/rendering/widgets/the-select-element/option-add-label.html": [
+   "5110164c3115a087cffadaac9b7b26d677156fb7",
+   "reftest"
+  ],
+  "html/rendering/widgets/the-select-element/option-empty-label-to-empty-string.html": [
+   "c8aa4d20b298e8073e93c299feea0812500e979c",
+   "reftest"
+  ],
+  "html/rendering/widgets/the-select-element/option-empty-label.html": [
+   "a34c41d29905441bcffa5bba933ac488339c460d",
+   "reftest"
+  ],
+  "html/rendering/widgets/the-select-element/option-label-and-text.html": [
+   "152bfdcb6ab52a3c3db52f69e0f58a6e3181911d",
+   "reftest"
+  ],
+  "html/rendering/widgets/the-select-element/option-label-ref.html": [
+   "3dd07b8dc2b4778d7f2f2e69202d680902c7e838",
+   "support"
+  ],
+  "html/rendering/widgets/the-select-element/option-only-label.html": [
+   "5e3c06cd660954cb1e51ac31e199dc9c02d1cd7d",
+   "reftest"
+  ],
+  "html/rendering/widgets/the-select-element/option-rm-label.html": [
+   "a5272cf6f1f26d0a305d6cffd8844092869ac398",
+   "reftest"
+  ],
   "html/resources/common.js": [
    "273f3a47be6707f3722922e34bcb272889636003",
    "support"
@@ -475358,7 +475677,7 @@
    "support"
   ],
   "html/semantics/embedded-content/the-img-element/image-loading-lazy-slow-aspect-ratio.html": [
-   "611f49c0b1d50c8197194c3d2bb8521fa6ac636b",
+   "2d302970cab98fa13cd5653c025003286efb7b29",
    "reftest"
   ],
   "html/semantics/embedded-content/the-img-element/image-loading-lazy-slow-ref.html": [
@@ -475366,7 +475685,7 @@
    "support"
   ],
   "html/semantics/embedded-content/the-img-element/image-loading-lazy-slow.html": [
-   "13bb5953e1aa680fb6a9d7e450d2453e1774fde4",
+   "a972100528360511b93dcdc42fa0f596142ec2e2",
    "reftest"
   ],
   "html/semantics/embedded-content/the-img-element/image-loading-lazy-subframe-detached-crash.html": [
@@ -496921,6 +497240,14 @@
    "5231a4387646ae73bb97d116d91ecc854f9260ac",
    "testharness"
   ],
+  "origin-policy/bad-server/manifest-utf16le.https.html": [
+   "93d46d7e9aa054e1ecec72a69b4deb3be8eef028",
+   "testharness"
+  ],
+  "origin-policy/bad-server/manifest-utf8-with-bom.https.html": [
+   "5657b5dc914450172efb337fec452ec1c8979b59",
+   "testharness"
+  ],
   "origin-policy/bad-server/resources/subframe-with-bad-header.py": [
    "c35daa0c2be170d60db19bc2ae8ea24b25e77ef9",
    "support"
@@ -497086,7 +497413,7 @@
    "testharness"
   ],
   "origin-policy/policies/README.md": [
-   "b07be74035f2dee0f379f0a8c499cd392f81f96a",
+   "d45f8004bf43c75c284cecaf3b201772c530bf21",
    "support"
   ],
   "origin-policy/policies/op1 cspfp-comma-in-policy.json": [
@@ -497157,6 +497484,14 @@
    "edd743038db8d48a8f23ae903c8170205119dc2c",
    "support"
   ],
+  "origin-policy/policies/op97 utf-8-with-bom.json": [
+   "869a75e1e6a45e210ef38466a57d453ae0b4b46c",
+   "support"
+  ],
+  "origin-policy/policies/op98 utf-16le.json": [
+   "ef0be5b98bb2b238a4cea84cc786a4ea4ef35f53",
+   "support"
+  ],
   "origin-policy/policies/op99 csp-valid-manifest-with-404.json": [
    "d0870331b43baf3e5a53e53f14aaa1c6e628183e",
    "support"
@@ -497697,8 +498032,8 @@
    "3d1bb8ddda2b999858fba14ec9420f127fb5dd13",
    "support"
   ],
-  "payment-method-id/payment-request-ctor-pmi-handling.https.html": [
-   "4ef083ebb4f224363559387bb2f8ee8312fea6a4",
+  "payment-method-id/payment-request-ctor-pmi-handling.https.sub.html": [
+   "a615838f8bcef9837f216ee3467edbc7c9dc4d15",
    "testharness"
   ],
   "payment-request/META.yml": [
@@ -497722,7 +498057,7 @@
    "support"
   ],
   "payment-request/PaymentAddress/attributes-and-toJSON-method-manual.https.html": [
-   "898e1916ca55d600f2b1d106dc23f1804b952bda",
+   "8afca19f923d45a2d97a134ecc1c9a02bf4aea82",
    "manual"
   ],
   "payment-request/PaymentMethodChangeEvent/methodDetails-attribute.https.html": [
@@ -497774,7 +498109,7 @@
    "manual"
   ],
   "payment-request/PaymentValidationErrors/retry-shows-shippingAddress-member-manual.https.html": [
-   "dc9294534b664b925ec59d69292a71609c9fe1c8",
+   "94e6fa5105b20a7127292de57adcfb20f3b806e8",
    "manual"
   ],
   "payment-request/algorithms-manual.https.html": [
@@ -497861,8 +498196,12 @@
    "f4a9a721d07c91d31d7b5d36471a239e4e7abe0a",
    "testharness"
   ],
+  "payment-request/dynamically-change-shipping-options-manual.https.html": [
+   "0e6670a1b824524872b8317b4258196379214e46",
+   "manual"
+  ],
   "payment-request/historical.https.html": [
-   "639bd4004493da4632ce29ce77049982db4faebc",
+   "6663e631bfd2857dc63ff9854e8657893c71a7ed",
    "testharness"
   ],
   "payment-request/idlharness.https.window-expected.txt": [
@@ -497921,16 +498260,16 @@
    "9763615bdd186d0a8a656af8a89bfdf8bbfac186",
    "testharness"
   ],
-  "payment-request/payment-request-constructor.https.html": [
-   "43b9588397e5ded391b18cd119e21eba50aa2710",
+  "payment-request/payment-request-constructor.https.sub.html": [
+   "e9e5121f67cb26030b9e0310c44858ebaadaf603",
    "testharness"
   ],
-  "payment-request/payment-request-ctor-currency-code-checks.https.html": [
-   "8004ff43f838b88675bfa47766107c205f38ad21",
+  "payment-request/payment-request-ctor-currency-code-checks.https.sub.html": [
+   "b4ca2a0c40b39b3c922343a9a74341b69a338459",
    "testharness"
   ],
-  "payment-request/payment-request-ctor-pmi-handling.https.html": [
-   "4ef083ebb4f224363559387bb2f8ee8312fea6a4",
+  "payment-request/payment-request-ctor-pmi-handling.https.sub.html": [
+   "a615838f8bcef9837f216ee3467edbc7c9dc4d15",
    "testharness"
   ],
   "payment-request/payment-request-hasenrolledinstrument-method-manual.tentative.https.html": [
@@ -499402,7 +499741,7 @@
    "support"
   ],
   "preload/subresource-integrity.html": [
-   "52ec0f62bef04a618e650acfb75513a7c79683e2",
+   "7a35e3bc85eb454f847d1087eaf00cb73b891fb4",
    "testharness"
   ],
   "presentation-api/META.yml": [
@@ -506530,7 +506869,7 @@
    "support"
   ],
   "resources/sriharness.js": [
-   "f0d284e57b9411d9c6056080ba8749e8f5671b39",
+   "d57a1b38465d642dc32fae4bdc8406cdc6833235",
    "support"
   ],
   "resources/testdriver-actions.js": [
@@ -520618,7 +520957,7 @@
    "support"
   ],
   "tools/wpt/android.py": [
-   "51deb71e316538148e06b146bca7555fb7b046df",
+   "744e134d3826eaffeba6387713a2cb132ae1a9d7",
    "support"
   ],
   "tools/wpt/browser.py": [
@@ -525658,7 +525997,7 @@
    "testharness"
   ],
   "webaudio/the-audio-api/the-audioparam-interface/k-rate-panner-connections.html": [
-   "77b32c20d116a51bcef9efd2d83bf601917c4354",
+   "001cf63bd36dccea41112f865f6b0747f8168906",
    "testharness"
   ],
   "webaudio/the-audio-api/the-audioparam-interface/k-rate-panner.html": [
diff --git a/third_party/blink/web_tests/external/wpt/common/rendering-utils.js b/third_party/blink/web_tests/external/wpt/common/rendering-utils.js
new file mode 100644
index 0000000..46283bd
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/common/rendering-utils.js
@@ -0,0 +1,19 @@
+"use strict";
+
+/**
+ * Waits until we have at least one frame rendered, regardless of the engine.
+ *
+ * @returns {Promise}
+ */
+function waitForAtLeastOneFrame() {
+  return new Promise(resolve => {
+    // Different web engines work slightly different on this area but waiting
+    // for two requestAnimationFrames() to happen, one after another, should be
+    // sufficient to ensure at least one frame has been generated anywhere.
+    window.requestAnimationFrame(() => {
+      window.requestAnimationFrame(() => {
+        resolve();
+      });
+    });
+  });
+}
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/text/bidi-flag-emoji-ref.html b/third_party/blink/web_tests/external/wpt/css/CSS2/text/bidi-flag-emoji-ref.html
new file mode 100644
index 0000000..84585a26
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/CSS2/text/bidi-flag-emoji-ref.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<body>
+  <div>לום<span style="unicode-bidi: isolate">🇱🇮</span></div>
+</body>
+
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/text/bidi-flag-emoji.html b/third_party/blink/web_tests/external/wpt/css/CSS2/text/bidi-flag-emoji.html
new file mode 100644
index 0000000..a184db26
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/CSS2/text/bidi-flag-emoji.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Correct support of emoji flag following rtl run</title>
+<link rel="help" href="https://drafts.csswg.org/css2/visuren.html">
+<link rel="match" href="bidi-flag-emoji-ref.html">
+<body>
+  <div>לום🇱🇮</div>
+</body>
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/contain-size-063.html b/third_party/blink/web_tests/external/wpt/css/css-contain/contain-size-063.html
new file mode 100644
index 0000000..31a6015
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/contain-size-063.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>CSS Containment Test: 'contain: size' affects intrinsic size</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+<link rel="help" href="https://www.w3.org/TR/css-contain-1/#containment-size">
+<link rel="match" href="reference/contain-size-063-ref.html">
+<meta name="flags" content="">
+<meta name="asserts" content="the intrinsic size of a size-contained element is treated as 0 in various scenarios involving intrinsic sizing.">
+
+<style>
+.red {
+    background: red;
+}
+.abs {
+    position: absolute;
+}
+.float {
+    float: left;
+}
+.zero {
+    width: 0;
+}
+.contained {
+    contain: size;
+    color: transparent;
+}
+.grid {
+    display: grid;
+    grid: max-content auto / min-content auto;
+}
+table {
+    border-collapse: collapse;
+}
+td {
+    padding: 0;
+}
+</style>
+
+<p>Test passes if there is no red below.
+
+<!-- max content sized-->
+<div class="red abs"><div class="contained">Arbitrary content content<br>that takes up size.<br>Block Layout</div></div>
+
+<!-- max content sized-->
+<div class="red float"><div class="contained">Arbitrary content content<br>that takes up size.<br>Float</div></div>
+
+<!-- min content sized-->
+<div class=zero><div class="red float"><div class="contained">Arbitrary content content<br>that takes up size.<br>Float in narrow wrapper</div></div></div>
+
+<div class="grid red">
+    <div class="red"></div>
+    <div class="contained">Arbitrary content content<br>that takes up size.<br>Grid item giving the first row it's height</div>
+    <div class="contained">Arbitrary content content<br>that takes up size.<br>Grid item giving the first column its width</div>
+</div>
+
+<table class=red>
+    <tr>
+        <td class=red>
+        <td><div class="contained">Arbitrary content content<br>that takes up size.<br>content of a table cell giving the fist row it's height</div>
+    <tr>
+        <td><div class="contained">Arbitrary content content<br>that takes up size.<br>content of a table cell giving the first column it's width</div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/reference/contain-size-063-ref.html b/third_party/blink/web_tests/external/wpt/css/css-contain/reference/contain-size-063-ref.html
new file mode 100644
index 0000000..9544ebc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/reference/contain-size-063-ref.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>Test reference</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+
+<p>Test passes if there is no red below.
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/background-image-blur-repaint.html b/third_party/blink/web_tests/external/wpt/css/filter-effects/background-image-blur-repaint.html
index 7b3df263..4a3c00c 100644
--- a/third_party/blink/web_tests/external/wpt/css/filter-effects/background-image-blur-repaint.html
+++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/background-image-blur-repaint.html
@@ -10,6 +10,7 @@
 <meta name="assert" content="An element with background-image and a filter should be rendered correctly after other elements on the page change size. You should see a 50x50 green box over a blurred background."/>
 
 <script src="/common/reftest-wait.js"></script>
+<script src="/common/rendering-utils.js"></script>
 <script>
 function runTest() {
   function shrinkBox() {
@@ -18,13 +19,9 @@
     box.style.height = "50px";
   }
 
-  // Wait for two requestAnimationFrame() calls to make sure that at least one
-  // frame has been rendered before shrinking the box and taking the screenshot.
-  requestAnimationFrame(function() {
-    requestAnimationFrame(function() {
-      shrinkBox();
-      takeScreenshot();
-    });
+  waitForAtLeastOneFrame().then(function() {
+    shrinkBox();
+    takeScreenshot();
   });
 }
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/effect-reference-delete.html b/third_party/blink/web_tests/external/wpt/css/filter-effects/effect-reference-delete.html
new file mode 100644
index 0000000..314c9a7d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/effect-reference-delete.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>CSS Filters: reference to deleted SVG filter</title>
+<link rel="author" title="Stephen White" href="mailto:senorblanco@chromium.org">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#FilterProperty">
+<link rel="help" href="https://bugs.webkit.org/show_bug.cgi?id=90405">
+<link rel="match" href="reference/effect-reference-delete-ref.html">
+<meta name="assert" content="Check that a CSS filter no longer affects its target element after having deleted the SVG element referenced from the CSS filter."/>
+
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/rendering-utils.js"></script>
+
+<svg width="0" height="0">
+  <defs>
+    <filter id="MyFilter">
+      <feColorMatrix type="hueRotate" values="180"/>
+    </filter>
+  </defs>
+</svg>
+<img style="filter: url(#MyFilter);" src="support/color-palette.png">
+<script>
+waitForAtLeastOneFrame().then(function() {
+  document.querySelector('svg').remove();
+  takeScreenshot();
+});
+</script>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/effect-reference-merge-no-inputs.tentative.html b/third_party/blink/web_tests/external/wpt/css/filter-effects/effect-reference-merge-no-inputs.tentative.html
new file mode 100644
index 0000000..4fb67db6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/effect-reference-merge-no-inputs.tentative.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<title>CSS Filters: feMerge with no input feMergeNode</title>
+<link rel="author" title="Fredrik Söderquist" href="mailto:fs@opera.com">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#FilterProperty">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects/#feMergeElement">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects/#feCompositeElement">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=533457">
+<link rel="match" href="reference/effect-reference-merge-no-inputs.tentative-ref.html">
+<meta name="assert" content="Check that the result of an feMerge with no feMergeNode children is transparent black."/>
+
+<style>
+#target {
+  width: 100px;
+  height: 100px;
+  background-color: blue;
+  filter: url(#emptyMerge);
+}
+</style>
+<div id="target"></div>
+<svg height="0">
+  <filter id="emptyMerge">
+    <feColorMatrix values="0 0 0 0 0, 0 0 1 0 0, 0 0 0 0 0, 0 0 0 1 0" result="lime"/>
+    <feColorMatrix values="0 1 0 0 0, 0 0 0 0 0, 0 0 0 0 0, 0 0 0 1 0" result="red"/>
+    <feMerge/>
+    <feComposite in2="lime"/>
+  </filter>
+</svg>
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/effect-reference-rename-001.html b/third_party/blink/web_tests/external/wpt/css/filter-effects/effect-reference-rename-001.html
new file mode 100644
index 0000000..6c837453
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/effect-reference-rename-001.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<title>CSS Filters: reference to renamed SVG filter</title>
+<link rel="author" title="Stephen White" href="mailto:senorblanco@chromium.org">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#FilterProperty">
+<link rel="help" href="https://bugs.webkit.org/show_bug.cgi?id=90405">
+<link rel="match" href="reference/effect-reference-rename-001-ref.html">
+<meta name="assert" content="Check that a SVG filter, initially named differently than what an element expects, gets applied to such element once renamed with the expected value."/>
+
+<body>
+<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="0" height="0">
+  <defs>
+    <filter id="NotMyFilter">
+      <feColorMatrix type="hueRotate" values="180"/>
+    </filter>
+  </defs>
+</svg>
+<img style="filter: url(#MyFilter);" src="support/color-palette.png">
+<script>
+document.getElementById("NotMyFilter").id = "MyFilter";
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/filter-region-negative-positioned-child-001.html b/third_party/blink/web_tests/external/wpt/css/filter-effects/filter-region-negative-positioned-child-001.html
new file mode 100644
index 0000000..8f302ab
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/filter-region-negative-positioned-child-001.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<title>SVG Filters: CSS reference filters with negative positioned children</title>
+<link rel="help" href="https://drafts.fxtf.org/filter-effects/#FilterProperty">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects/#ColorInterpolationFiltersProperty">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects/#feColorMatrixElement">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=638091">
+<link rel="match" href="reference/filter-region-negative-positioned-child-001-ref.html">
+<meta name="assert" content="CSS reference filters with negative positioned children"/>
+<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0" version="1.1">
+  <defs>
+    <filter id="f1" color-interpolation-filters="sRGB">
+      <feColorMatrix type="matrix" values="-1 0 0 0 1  0 -1 0 0 1  0 0 -1 0 1  0 0 0 1 0"/>
+    </filter>
+  </defs>
+</svg>
+<style>
+.box {
+  width: 100px;
+  height: 100px;
+  position: absolute;
+}
+.green {
+  background-color: green;
+}
+.blue {
+  background-color: blue;
+}
+.above {
+  top: -100px;
+}
+.parent {
+  filter: url(#f1);
+  background-color: white;
+  position: relative;
+  top: 100px;
+}
+</style>
+<div class="parent">
+<div class="green box"></div>
+<div class="blue box above"></div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/reference-filter-update-on-attribute-change-001.html b/third_party/blink/web_tests/external/wpt/css/filter-effects/reference-filter-update-on-attribute-change-001.html
new file mode 100644
index 0000000..cc5ac7c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/reference-filter-update-on-attribute-change-001.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>SVG Filters: Invalidation of SVG filter attributes on HTML</title>
+<link rel="help" href="https://drafts.fxtf.org/filter-effects/#FilterProperty">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects/#feColorMatrixElement">
+<link rel="help" href="https://bugs.webkit.org/show_bug.cgi?id=105635">
+<link rel="match" href="reference/reference-filter-update-on-attribute-change-001-ref.html">
+<meta name="assert" content="Dynamically adding an attribute of a filter primitive"/>
+<head>
+  <script>
+    function run() {
+      document.getElementById('color').setAttribute('values', '90');
+    }
+ </script>
+</head>
+<body onload="run()">
+   <svg xmlns="http://www.w3.org/2000/svg" width="0" height="0" version="1.1">
+    <defs>
+      <filter id="MyFilter">
+        <fecolormatrix id="color" type="hueRotate"></fecolormatrix>
+      </filter>
+    </defs>
+  </svg>
+  <div style="filter: url(#MyFilter); width:100px; height:100px; background-color:red;"></div>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/reference/effect-reference-delete-ref.html b/third_party/blink/web_tests/external/wpt/css/filter-effects/reference/effect-reference-delete-ref.html
new file mode 100644
index 0000000..9187152
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/reference/effect-reference-delete-ref.html
@@ -0,0 +1,5 @@
+<html>
+  <body>
+    <img src="../support/color-palette.png">
+  </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/reference/effect-reference-merge-no-inputs.tentative-ref.html b/third_party/blink/web_tests/external/wpt/css/filter-effects/reference/effect-reference-merge-no-inputs.tentative-ref.html
new file mode 100644
index 0000000..5743e0c3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/reference/effect-reference-merge-no-inputs.tentative-ref.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<div style="width: 100px; height: 100px; background-color: lime"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/reference/effect-reference-rename-001-ref.html b/third_party/blink/web_tests/external/wpt/css/filter-effects/reference/effect-reference-rename-001-ref.html
new file mode 100644
index 0000000..fe3beae2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/reference/effect-reference-rename-001-ref.html
@@ -0,0 +1,12 @@
+<html>
+<body>
+<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="0" height="0">
+  <defs>
+    <filter id="MyFilter">
+      <feColorMatrix type="hueRotate" values="180"/>
+    </filter>
+  </defs>
+</svg>
+<img style="filter: url(#MyFilter);" src="../support/color-palette.png">
+</body>
+</html>
diff --git a/third_party/blink/web_tests/css3/filters/filter-region-negative-transformed-child-expected.html b/third_party/blink/web_tests/external/wpt/css/filter-effects/reference/filter-region-negative-positioned-child-001-ref.html
similarity index 96%
rename from third_party/blink/web_tests/css3/filters/filter-region-negative-transformed-child-expected.html
rename to third_party/blink/web_tests/external/wpt/css/filter-effects/reference/filter-region-negative-positioned-child-001-ref.html
index 686e747..c9da47b1 100644
--- a/third_party/blink/web_tests/css3/filters/filter-region-negative-transformed-child-expected.html
+++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/reference/filter-region-negative-positioned-child-001-ref.html
@@ -1,3 +1,4 @@
+<!DOCTYPE html>
 <svg xmlns="http://www.w3.org/2000/svg" width="0" height="0" version="1.1">
   <defs>
     <filter id="f1" color-interpolation-filters="sRGB">
diff --git a/third_party/blink/web_tests/css3/filters/reference-filter-update-on-attribute-change-expected.html b/third_party/blink/web_tests/external/wpt/css/filter-effects/reference/reference-filter-update-on-attribute-change-001-ref.html
similarity index 67%
rename from third_party/blink/web_tests/css3/filters/reference-filter-update-on-attribute-change-expected.html
rename to third_party/blink/web_tests/external/wpt/css/filter-effects/reference/reference-filter-update-on-attribute-change-001-ref.html
index 8d1ef59e..91326ef 100644
--- a/third_party/blink/web_tests/css3/filters/reference-filter-update-on-attribute-change-expected.html
+++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/reference/reference-filter-update-on-attribute-change-001-ref.html
@@ -1,3 +1,4 @@
+<!DOCTYPE html>
 <body>
    <svg xmlns="http://www.w3.org/2000/svg" width="0" height="0" version="1.1">
     <defs>
@@ -6,5 +7,5 @@
       </filter>
     </defs>
   </svg>
-  <div style="filter: url(#MyFilter); filter: url(#MyFilter); width:100px; height:100px; background-color:red;"></div>
+  <div style="filter: url(#MyFilter); width:100px; height:100px; background-color:red;"></div>
 </body>
diff --git a/third_party/blink/web_tests/external/wpt/dom/nodes/DocumentFragment-getElementById-expected.txt b/third_party/blink/web_tests/external/wpt/dom/nodes/DocumentFragment-getElementById-expected.txt
deleted file mode 100644
index 1046305..0000000
--- a/third_party/blink/web_tests/external/wpt/dom/nodes/DocumentFragment-getElementById-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-This is a testharness.js-based test.
-PASS The method must exist
-PASS It must return null when there are no matches
-PASS It must return the first element when there are matches
-FAIL Empty string ID values assert_equals: Even if there is an element with an empty-string ID attribute, it must not be returned expected null but got Element node <div id=""></div>
-PASS It must return the first element when there are matches, using a template
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/feature-policy/payment-allowed-by-feature-policy.https.sub.html b/third_party/blink/web_tests/external/wpt/feature-policy/payment-allowed-by-feature-policy.https.sub.html
index ccf5f69..ae77daa 100644
--- a/third_party/blink/web_tests/external/wpt/feature-policy/payment-allowed-by-feature-policy.https.sub.html
+++ b/third_party/blink/web_tests/external/wpt/feature-policy/payment-allowed-by-feature-policy.https.sub.html
@@ -11,7 +11,7 @@
   var header = 'Feature-Policy header {"payment" : ["*"]}';
 
   test(() => {
-    var supportedMethods = [ { supportedMethods: 'https://wpt.fyi/payment-request' } ];
+    var supportedMethods = [ { supportedMethods: 'https://{{domains[nonexistent]}}/payment-request' } ];
     var details = {
       total: { label: 'Test', amount: { currency: 'USD', value: '5.00' } }
     };
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/the-details-element/empty-crash.html b/third_party/blink/web_tests/external/wpt/html/rendering/the-details-element/empty-crash.html
new file mode 100644
index 0000000..d409eff
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/the-details-element/empty-crash.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<link rel="help" href="https://crbug.com/1068227">
+<style>
+body { display: flex; }
+details, summary { display: inherit; }
+</style>
+<details><summary>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/widgets/the-select-element/option-add-label.html b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/the-select-element/option-add-label.html
new file mode 100644
index 0000000..5110164
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/the-select-element/option-add-label.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>OPTION's label attribute in SELECT -- Adding a label</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/rendering.html#the-select-element-2">
+<link rel="match" href="option-label-ref.html">
+<meta name="assert" content="An option element is expected to be rendered by displaying the element's label.">
+
+<select>
+  <option>Element Text</option>
+</select>
+<br/>
+<select size="4">
+  <option>Element Text</option>
+</select>
+<script>
+let options = document.querySelectorAll("option");
+options[0].getBoundingClientRect(); // force layout.
+for (let option of options) {
+  option.setAttribute("label", "Label Text");
+}
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/widgets/the-select-element/option-empty-label-to-empty-string.html b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/the-select-element/option-empty-label-to-empty-string.html
new file mode 100644
index 0000000..c8aa4d20
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/the-select-element/option-empty-label-to-empty-string.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>OPTION's label attribute in SELECT -- Adding a label</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/rendering.html#the-select-element-2">
+<link rel="match" href="option-label-ref.html">
+<meta name="assert" content="An option element is expected to be rendered by displaying the element's label.">
+
+<select>
+  <option label="Element Text">Label Text</option>
+</select>
+<br/>
+<select size="4">
+  <option label="Element Text">Label Text</option>
+</select>
+<script>
+let options = document.querySelectorAll("option");
+options[0].getBoundingClientRect(); // force layout.
+for (let option of options) {
+  option.setAttribute("label", "");
+}
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/widgets/the-select-element/option-empty-label.html b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/the-select-element/option-empty-label.html
new file mode 100644
index 0000000..a34c41d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/the-select-element/option-empty-label.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>OPTION's label attribute in SELECT -- Empty label uses Element text</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/rendering.html#the-select-element-2">
+<link rel="match" href="option-label-ref.html">
+<meta name="assert" content="An option element is expected to be rendered by displaying the element's label.">
+
+<select>
+  <option label>Label Text</option>
+</select>
+<br/>
+<select size="4">
+  <option label>Label Text</option>
+</select>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/widgets/the-select-element/option-label-and-text.html b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/the-select-element/option-label-and-text.html
new file mode 100644
index 0000000..152bfdc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/the-select-element/option-label-and-text.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>OPTION's label attribute in SELECT - Prefers label over element text</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/rendering.html#the-select-element-2">
+<link rel="match" href="option-label-ref.html">
+<meta name="assert" content="An option element is expected to be rendered by displaying the element's label.">
+
+<select>
+  <option label="Label Text">Element Text</option>
+</select>
+<br/>
+<select size="4">
+  <option label="Label Text">Element Text</option>
+</select>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/widgets/the-select-element/option-label-ref.html b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/the-select-element/option-label-ref.html
new file mode 100644
index 0000000..3dd07b8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/the-select-element/option-label-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>OPTION's label attribute in SELECT (reference)</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/rendering.html#the-select-element-2">
+
+<select>
+  <option>Label Text</option>
+</select>
+<br/>
+<select size="4">
+  <option>Label Text</option>
+</select>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/widgets/the-select-element/option-only-label.html b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/the-select-element/option-only-label.html
new file mode 100644
index 0000000..5e3c06cd
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/the-select-element/option-only-label.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>OPTION's label attribute in SELECT -- Only a label</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/rendering.html#the-select-element-2">
+<link rel="match" href="option-label-ref.html">
+<meta name="assert" content="An option element is expected to be rendered by displaying the element's label.">
+
+<select>
+  <option label="Label Text"></option>
+</select>
+<br/>
+<select size="4">
+  <option label="Label Text"></option>
+</select>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/widgets/the-select-element/option-rm-label.html b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/the-select-element/option-rm-label.html
new file mode 100644
index 0000000..a5272cf6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/the-select-element/option-rm-label.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>OPTION's label attribute in SELECT -- Removing the label</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/rendering.html#the-select-element-2">
+<link rel="match" href="option-label-ref.html">
+<meta name="assert" content="An option element is expected to be rendered by displaying the element's label.">
+
+<select>
+  <option label="Bad Label Text">Label Text</option>
+</select>
+<br/>
+<select size="4">
+  <option label="Bad Label Text">Label Text</option>
+</select>
+<script>
+let options = document.querySelectorAll("option");
+options[0].getBoundingClientRect(); // force layout.
+for (let option of options) {
+  option.removeAttribute("label");
+}
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/image-loading-lazy-slow-aspect-ratio.html b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/image-loading-lazy-slow-aspect-ratio.html
index 611f49c0..2d302970 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/image-loading-lazy-slow-aspect-ratio.html
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/image-loading-lazy-slow-aspect-ratio.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html style="reftest-wait">
+<html class="reftest-wait">
   <link rel="match" href="image-loading-lazy-slow-aspect-ratio-ref.html">
   <link rel="author" title="Chris Harrelson" href="mailto:chrishtr@chromium.org">
   <link rel="help" href="https://html.spec.whatwg.org/multipage/#the-img-element">
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/image-loading-lazy-slow.html b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/image-loading-lazy-slow.html
index 13bb5953..a972100 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/image-loading-lazy-slow.html
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/image-loading-lazy-slow.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html style="reftest-wait">
+<html class="reftest-wait">
   <link rel="match" href="image-loading-lazy-slow-ref.html">
   <link rel="author" title="Chris Harrelson" href="mailto:chrishtr@chromium.org">
   <link rel="help" href="https://html.spec.whatwg.org/multipage/#the-img-element">
diff --git a/third_party/blink/web_tests/external/wpt/payment-method-id/payment-request-ctor-pmi-handling.https.html b/third_party/blink/web_tests/external/wpt/payment-method-id/payment-request-ctor-pmi-handling.https.sub.html
similarity index 85%
rename from third_party/blink/web_tests/external/wpt/payment-method-id/payment-request-ctor-pmi-handling.https.html
rename to third_party/blink/web_tests/external/wpt/payment-method-id/payment-request-ctor-pmi-handling.https.sub.html
index 4ef083e..a615838 100644
--- a/third_party/blink/web_tests/external/wpt/payment-method-id/payment-request-ctor-pmi-handling.https.html
+++ b/third_party/blink/web_tests/external/wpt/payment-method-id/payment-request-ctor-pmi-handling.https.sub.html
@@ -22,15 +22,15 @@
 test(() => {
   const validMethods = [
     "https://wpt",
-    "https://wpt.fyi/",
-    "https://wpt.fyi/payment",
-    "https://wpt.fyi/payment-request",
-    "https://wpt.fyi/payment-request?",
-    "https://wpt.fyi/payment-request?this=is",
-    "https://wpt.fyi/payment-request?this=is&totally",
-    "https://wpt.fyi:443/payment-request?this=is&totally",
-    "https://wpt.fyi:443/payment-request?this=is&totally#fine",
-    "https://:@wpt.fyi:443/payment-request?this=is&totally#👍",
+    "https://{{domains[nonexistent]}}/",
+    "https://{{domains[nonexistent]}}/payment",
+    "https://{{domains[nonexistent]}}/payment-request",
+    "https://{{domains[nonexistent]}}/payment-request?",
+    "https://{{domains[nonexistent]}}/payment-request?this=is",
+    "https://{{domains[nonexistent]}}/payment-request?this=is&totally",
+    "https://{{domains[nonexistent]}}:443/payment-request?this=is&totally",
+    "https://{{domains[nonexistent]}}:443/payment-request?this=is&totally#fine",
+    "https://:@{{domains[nonexistent]}}:443/payment-request?this=is&totally#👍",
     " \thttps://wpt\n ",
     "https://xn--c1yn36f",
     "https://點看",
@@ -129,7 +129,7 @@
     "https://username:password@example.com/pay",
     "http://username:password@example.com/pay",
     "http://foo.com:100000000/pay",
-    "not-https://wpt.fyi/payment-request",
+    "not-https://{{domains[nonexistent]}}/payment-request",
     "../realitive/url",
     "/absolute/../path?",
     "https://",
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/PaymentAddress/attributes-and-toJSON-method-manual.https.html b/third_party/blink/web_tests/external/wpt/payment-request/PaymentAddress/attributes-and-toJSON-method-manual.https.html
index 898e191..8afca19 100644
--- a/third_party/blink/web_tests/external/wpt/payment-request/PaymentAddress/attributes-and-toJSON-method-manual.https.html
+++ b/third_party/blink/web_tests/external/wpt/payment-request/PaymentAddress/attributes-and-toJSON-method-manual.https.html
@@ -68,6 +68,7 @@
     <button onclick="
     const expectedAddress = {
       country: 'AU',
+      regionCode: 'QLD',
       addressLine: '55 test st',
       city: 'Chapel Hill',
       dependentLocality: '',
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/PaymentValidationErrors/retry-shows-shippingAddress-member-manual.https.html b/third_party/blink/web_tests/external/wpt/payment-request/PaymentValidationErrors/retry-shows-shippingAddress-member-manual.https.html
index dc92945..94e6fa51 100644
--- a/third_party/blink/web_tests/external/wpt/payment-request/PaymentValidationErrors/retry-shows-shippingAddress-member-manual.https.html
+++ b/third_party/blink/web_tests/external/wpt/payment-request/PaymentValidationErrors/retry-shows-shippingAddress-member-manual.https.html
@@ -82,6 +82,11 @@
     </button>
   </li>
   <li>
+    <button onclick="retryShowsShippingAddressMember(this, { regionCode: 'REGIONCODE ERROR' });">
+      The payment sheet shows "REGIONCODE ERROR" for the shipping address' region code.
+    </button>
+  </li>
+  <li>
     <button onclick="retryShowsShippingAddressMember(this, { sortingCode: 'SORTINGCODE ERROR' });">
       The payment sheet shows "SORTINGCODE ERROR" for the shipping address' sorting code.
     </button>
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/dynamically-change-shipping-options-manual.https.html b/third_party/blink/web_tests/external/wpt/payment-request/dynamically-change-shipping-options-manual.https.html
new file mode 100644
index 0000000..0e6670a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/payment-request/dynamically-change-shipping-options-manual.https.html
@@ -0,0 +1,142 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<title>Test for PaymentRequest shippingOption dynamic updating</title>
+<link
+  rel="help"
+  href="https://w3c.github.io/payment-request/#shippingoption-attribute"
+/>
+<link
+  rel="help"
+  href="https://w3c.github.io/payment-request/#onshippingoptionchange-attribute"
+/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+  setup({ explicit_done: true, explicit_timeout: true });
+  const validMethod = Object.freeze({ supportedMethods: "basic-card" });
+  const applePayMethod = {
+    supportedMethods: "https://apple.com/apple-pay",
+    data: {
+      version: 3,
+      merchantIdentifier: "merchant.com.example",
+      countryCode: "US",
+      merchantCapabilities: ["supports3DS"],
+      supportedNetworks: ["visa"],
+    },
+  };
+  const validMethods = Object.freeze([validMethod, applePayMethod]);
+  const validAmount = Object.freeze({ currency: "USD", value: "5.00" });
+  const validTotal = Object.freeze({
+    label: "label",
+    amount: validAmount,
+  });
+  const validDetails = Object.freeze({ total: validTotal });
+
+  const initialValidShippingOption = Object.freeze({
+    id: "default-method",
+    label: "Default shipping method",
+    amount: validAmount,
+    selected: true,
+  });
+
+  const validDynamicShippingOption = Object.freeze({
+    id: "dynamically-added-id",
+    label: "Dynamically added shipping option",
+    amount: validAmount,
+    selected: false,
+  });
+
+  const requestShipping = Object.freeze({
+    requestShipping: true,
+  });
+
+  function testShippingOptionChanged() {
+    promise_test(async (t) => {
+      const detailsWithShippingOptions = {
+        ...validDetails,
+        shippingOptions: [initialValidShippingOption],
+      };
+      const request = new PaymentRequest(
+        validMethods,
+        detailsWithShippingOptions,
+        requestShipping
+      );
+      const shippingAddressChangeListener = new Promise((resolve) => {
+        request.addEventListener(
+          "shippingaddresschange",
+          (ev) => {
+            // resolve(request.shippingOption);
+            ev.updateWith({
+              shippingOptions: [
+                initialValidShippingOption,
+                validDynamicShippingOption,
+              ],
+            });
+            resolve();
+          },
+          { once: true }
+        );
+      });
+      const handlerPromise = new Promise((resolve) => {
+        request.onshippingoptionchange = () => {
+          resolve(request.shippingOption);
+        };
+      });
+      request.show().catch((err) => err);
+
+      const results = await Promise.all([
+        shippingAddressChangeListener,
+        handlerPromise,
+      ]);
+      assert_true(
+        results[1] === "dynamically-added-id",
+        "Expected dynamically-added-id as the shippingOption"
+      );
+      await request.abort();
+    });
+  }
+</script>
+
+<h2>PaymentRequest shippingOption attribute</h2>
+<p>
+  Click on each button in sequence from top to bottom without refreshing the
+  page. Each button (except the 'Done' button) will bring up the Payment Request
+  UI window.
+</p>
+<ol>
+  <li>
+    When the payment sheet is presented, view options for Shipping Method. There
+    should only be one: "Default shipping method"
+  </li>
+  <li>
+    Change your Shipping Address - either update your existing one by changing
+    something (name, address, etc), or select a different Shipping Address, or
+    add a new Shipping Address and select it.
+  </li>
+  <li>
+    Go back to Shipping Method, and there is now an option called "Dynamically
+    added shipping option". Select it
+  </li>
+  <li>
+    Click on the 'Done' button
+  </li>
+</ol>
+<ul>
+  <li>
+    <button onclick="testShippingOptionChanged()">
+      When the address is changed, shipping methods can be updated
+    </button>
+  </li>
+  <li>
+    <button onclick="done()">Done</button>
+  </li>
+</ul>
+<small>
+  If you find a buggy test, please
+  <a href="https://github.com/web-platform-tests/wpt/issues">file a bug</a> and
+  tag one of the
+  <a
+    href="https://github.com/web-platform-tests/wpt/blob/master/payment-request/META.yml"
+    >suggested reviewers</a
+  >.
+</small>
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/historical.https.html b/third_party/blink/web_tests/external/wpt/payment-request/historical.https.html
index 639bd40..6663e63 100644
--- a/third_party/blink/web_tests/external/wpt/payment-request/historical.https.html
+++ b/third_party/blink/web_tests/external/wpt/payment-request/historical.https.html
@@ -21,9 +21,6 @@
 
   // https://github.com/w3c/payment-request/pull/765
   ["languageCode", "PaymentAddress"],
-
-  // https://github.com/w3c/payment-request/pull/823
-  ["regionCode", "PaymentAddress"],
 ].forEach(([member, interf]) => {
   test(() => {
     assert_false(member in window[interf].prototype);
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-constructor.https.html b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-constructor.https.sub.html
similarity index 95%
rename from third_party/blink/web_tests/external/wpt/payment-request/payment-request-constructor.https.html
rename to third_party/blink/web_tests/external/wpt/payment-request/payment-request-constructor.https.sub.html
index 43b9588..e9e5121 100644
--- a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-constructor.https.html
+++ b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-constructor.https.sub.html
@@ -8,7 +8,7 @@
 <script>
 "use strict";
 const testMethod = Object.freeze({
-  supportedMethods: "https://wpt.fyi/payment-request",
+  supportedMethods: "https://{{domains[nonexistent]}}/payment-request",
 });
 const defaultMethods = Object.freeze([testMethod]);
 const defaultAmount = Object.freeze({
@@ -118,7 +118,7 @@
     try {
       const methods = [
         {
-          supportedMethods: "https://wpt.fyi/payment-request",
+          supportedMethods: "https://{{domains[nonexistent]}}/payment-request",
           data,
         },
       ];
@@ -140,7 +140,7 @@
   assert_throws_js(TypeError, () => {
     const methods = [
       {
-        supportedMethods: "https://wpt.fyi/payment-request",
+        supportedMethods: "https://{{domains[nonexistent]}}/payment-request",
         data: recursiveDictionary,
       },
     ];
@@ -149,7 +149,7 @@
   assert_throws_js(TypeError, () => {
     const methods = [
       {
-        supportedMethods: "https://wpt.fyi/payment-request",
+        supportedMethods: "https://{{domains[nonexistent]}}/payment-request",
         data: "a string",
       },
     ];
@@ -160,7 +160,7 @@
     () => {
       const methods = [
         {
-          supportedMethods: "https://wpt.fyi/payment-request",
+          supportedMethods: "https://{{domains[nonexistent]}}/payment-request",
           data: null,
         },
       ];
@@ -282,7 +282,7 @@
     new PaymentRequest(
       [
         {
-          supportedMethods: "https://wpt.fyi/payment-request",
+          supportedMethods: "https://{{domains[nonexistent]}}/payment-request",
         },
       ],
       {
@@ -533,7 +533,7 @@
   smokeTest();
   for (const invalidTotal of invalidTotalAmounts) {
     const invalidModifier = {
-      supportedMethods: "https://wpt.fyi/payment-request",
+      supportedMethods: "https://{{domains[nonexistent]}}/payment-request",
       total: {
         label: "",
         amount: {
@@ -559,7 +559,7 @@
   smokeTest();
   for (const invalidAmount of invalidAmounts) {
     const invalidModifier = {
-      supportedMethods: "https://wpt.fyi/payment-request",
+      supportedMethods: "https://{{domains[nonexistent]}}/payment-request",
       total: defaultTotal,
       additionalDisplayItems: [
         {
@@ -589,7 +589,7 @@
   const modifiedDetails = Object.assign({}, defaultDetails, {
     modifiers: [
       {
-        supportedMethods: "https://wpt.fyi/payment-request",
+        supportedMethods: "https://{{domains[nonexistent]}}/payment-request",
         data: ["some-data"],
       },
     ],
@@ -608,7 +608,7 @@
   const modifiedDetails = Object.assign({}, defaultDetails, {
     modifiers: [
       {
-        supportedMethods: "https://wpt.fyi/payment-request",
+        supportedMethods: "https://{{domains[nonexistent]}}/payment-request",
         data: {
           some: "data",
         },
@@ -631,7 +631,7 @@
   const modifiedDetails = Object.assign({}, defaultDetails, {
     modifiers: [
       {
-        supportedMethods: "https://wpt.fyi/payment-request",
+        supportedMethods: "https://{{domains[nonexistent]}}/payment-request",
         data: recursiveDictionary,
       },
     ],
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-ctor-currency-code-checks.https.html b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-ctor-currency-code-checks.https.sub.html
similarity index 96%
rename from third_party/blink/web_tests/external/wpt/payment-request/payment-request-ctor-currency-code-checks.https.html
rename to third_party/blink/web_tests/external/wpt/payment-request/payment-request-ctor-currency-code-checks.https.sub.html
index 8004ff4..b4ca2a0 100644
--- a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-ctor-currency-code-checks.https.html
+++ b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-ctor-currency-code-checks.https.sub.html
@@ -7,7 +7,7 @@
 <script>
 const defaultMethods = [
   Object.freeze({
-    supportedMethods: "https://wpt.fyi",
+    supportedMethods: "https://{{domains[nonexistent]}}",
   }),
 ];
 const defaultAmount = Object.freeze({
@@ -240,7 +240,7 @@
   assert_throws_js(RANGE_ERROR, smokeTest, "Expected smoke test to throw.");
   for (const validCurrency of wellFormedCurrencyCodes) {
     const modifier = {
-      supportedMethods: "https://wpt.fyi",
+      supportedMethods: "https://{{domains[nonexistent]}}",
       total: {
         label: "Total due",
         amount: { currency: validCurrency, value: "68.00" },
@@ -264,7 +264,7 @@
   assert_throws_js(RANGE_ERROR, smokeTest, "Expected smoke test to throw.");
   for (const invalidCurrency of invalidCurrencyCodes) {
     const modifier = {
-      supportedMethods: "https://wpt.fyi",
+      supportedMethods: "https://{{domains[nonexistent]}}",
       total: {
         label: "Total due",
         amount: { currency: invalidCurrency, value: "68.00" },
@@ -293,7 +293,7 @@
       amount: { currency: validCurrency, value: "3.00" },
     };
     const modifier = {
-      supportedMethods: "https://wpt.fyi",
+      supportedMethods: "https://{{domains[nonexistent]}}",
       total: defaultTotal,
       additionalDisplayItems: [additionalItem],
     };
@@ -319,7 +319,7 @@
       amount: { currency: invalidCurrency, value: "3.00" },
     };
     const modifier = {
-      supportedMethods: "https://wpt.fyi",
+      supportedMethods: "https://{{domains[nonexistent]}}",
       total: defaultTotal,
       additionalDisplayItems: [additionalItem],
     };
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-ctor-pmi-handling.https.html b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-ctor-pmi-handling.https.sub.html
similarity index 85%
rename from third_party/blink/web_tests/external/wpt/payment-request/payment-request-ctor-pmi-handling.https.html
rename to third_party/blink/web_tests/external/wpt/payment-request/payment-request-ctor-pmi-handling.https.sub.html
index 4ef083e..a615838 100644
--- a/third_party/blink/web_tests/external/wpt/payment-request/payment-request-ctor-pmi-handling.https.html
+++ b/third_party/blink/web_tests/external/wpt/payment-request/payment-request-ctor-pmi-handling.https.sub.html
@@ -22,15 +22,15 @@
 test(() => {
   const validMethods = [
     "https://wpt",
-    "https://wpt.fyi/",
-    "https://wpt.fyi/payment",
-    "https://wpt.fyi/payment-request",
-    "https://wpt.fyi/payment-request?",
-    "https://wpt.fyi/payment-request?this=is",
-    "https://wpt.fyi/payment-request?this=is&totally",
-    "https://wpt.fyi:443/payment-request?this=is&totally",
-    "https://wpt.fyi:443/payment-request?this=is&totally#fine",
-    "https://:@wpt.fyi:443/payment-request?this=is&totally#👍",
+    "https://{{domains[nonexistent]}}/",
+    "https://{{domains[nonexistent]}}/payment",
+    "https://{{domains[nonexistent]}}/payment-request",
+    "https://{{domains[nonexistent]}}/payment-request?",
+    "https://{{domains[nonexistent]}}/payment-request?this=is",
+    "https://{{domains[nonexistent]}}/payment-request?this=is&totally",
+    "https://{{domains[nonexistent]}}:443/payment-request?this=is&totally",
+    "https://{{domains[nonexistent]}}:443/payment-request?this=is&totally#fine",
+    "https://:@{{domains[nonexistent]}}:443/payment-request?this=is&totally#👍",
     " \thttps://wpt\n ",
     "https://xn--c1yn36f",
     "https://點看",
@@ -129,7 +129,7 @@
     "https://username:password@example.com/pay",
     "http://username:password@example.com/pay",
     "http://foo.com:100000000/pay",
-    "not-https://wpt.fyi/payment-request",
+    "not-https://{{domains[nonexistent]}}/payment-request",
     "../realitive/url",
     "/absolute/../path?",
     "https://",
diff --git a/third_party/blink/web_tests/external/wpt/preload/subresource-integrity.html b/third_party/blink/web_tests/external/wpt/preload/subresource-integrity.html
index 52ec0f6..7a35e3bc 100644
--- a/third_party/blink/web_tests/external/wpt/preload/subresource-integrity.html
+++ b/third_party/blink/web_tests/external/wpt/preload/subresource-integrity.html
@@ -6,6 +6,8 @@
 <script src="/resources/sriharness.js"></script>
 <script src="/common/utils.js"></script>
 <script src="/subresource-integrity/sri-test-helpers.sub.js"></script>
+<script src="./resources/preload_helper.js"></script>
+
 
 <div id="log"></div>
 
@@ -53,6 +55,7 @@
         true,                                                   /* preload_sri_success */
         true,                                                   /* subresource_sri_success */
         `Same-origin ${destination} with correct sha256 hash.`, /* name */
+        1,                                                      /* number_of_requests */
         destination,                                            /* destination */
         same_origin_prefix + destination + ext + `?${token()}`, /* resource_url (for preload + subresource) */
         {integrity: sha256},                                    /* link_attrs */
@@ -63,6 +66,7 @@
         true,
         true,
         `Same-origin ${destination} with correct sha384 hash.`,
+        1,
         destination,
         same_origin_prefix + destination + ext + `?${token()}`,
         {integrity: sha384},
@@ -73,6 +77,7 @@
         true,
         true,
         `Same-origin ${destination} with correct sha512 hash.`,
+        1,
         destination,
         same_origin_prefix + destination + ext + `?${token()}`,
         {integrity: sha512},
@@ -83,6 +88,7 @@
         true,
         true,
         `Same-origin ${destination} with empty integrity.`,
+        1,
         destination,
         same_origin_prefix + destination + ext + `?${token()}`,
         {},
@@ -93,6 +99,7 @@
         false,
         false,
         `Same-origin ${destination} with incorrect hash.`,
+        1,
         destination,
         same_origin_prefix + destination + ext + `?${token()}`,
         {integrity: "sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead"},
@@ -103,6 +110,7 @@
         true,
         true,
         `Same-origin ${destination} with multiple sha256 hashes, including correct.`,
+        1,
         destination,
         same_origin_prefix + destination + ext + `?${token()}`,
         {integrity: `${sha256} sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead`},
@@ -113,6 +121,7 @@
         true,
         true,
         `Same-origin ${destination} with multiple sha256 hashes, including unknown algorithm.`,
+        1,
         destination,
         same_origin_prefix + destination + ext + `?${token()}`,
         {integrity: `${sha256} foo666-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead`},
@@ -123,6 +132,7 @@
         true,
         true,
         `Same-origin ${destination} with sha256 mismatch, sha512 match`,
+        1,
         destination,
         same_origin_prefix + destination + ext + `?${token()}`,
         {integrity: `${sha512} sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead`},
@@ -133,6 +143,7 @@
         false,
         false,
         `Same-origin ${destination} with sha256 match, sha512 mismatch`,
+        1,
         destination,
         same_origin_prefix + destination + ext + `?${token()}`,
         {integrity: `sha512-deadbeefspbnUnwooKGNNCb39nvg+EW0O9hDScTXeo/9pVZztLSUYU3LNV6H0lZapo8bCJUpyPPLAzE9fDzpxg== ${sha256}`},
@@ -143,6 +154,7 @@
         true,
         true,
         `<crossorigin='anonymous'> ${destination} with correct hash, ACAO: *`,
+        1,
         destination,
         xorigin_prefix + destination + ext + `?${token()}` + anonymous,
         {integrity: sha256, crossOrigin: 'anonymous'},
@@ -153,6 +165,7 @@
         false,
         false,
         `<crossorigin='anonymous'> ${destination} with incorrect hash, ACAO: *`,
+        1,
         destination,
         xorigin_prefix + destination + ext + `?${token()}` + anonymous,
         {integrity: "sha256-sha256-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdead", crossOrigin: "anonymous"},
@@ -163,6 +176,7 @@
         true,
         true,
         `<crossorigin='use-credentials'> ${destination} with correct hash, CORS-eligible`,
+        1,
         destination,
         xorigin_prefix + destination + ext + `?${token()}` + use_credentials,
         {integrity: sha256, crossOrigin: "use-credentials"},
@@ -173,6 +187,7 @@
         false,
         false,
         `<crossorigin='use-credentials'> ${destination} with incorrect hash CORS-eligible`,
+        1,
         destination,
         xorigin_prefix + destination + ext + `?${token()}` + use_credentials,
         {integrity: "sha256-deadbeef2S+pTRZgiw3DWrhC6JLDlt2zRyGpwH7unU8=", crossOrigin: "use-credentials"},
@@ -183,6 +198,7 @@
         false,
         false,
         `<crossorigin='anonymous'> ${destination} with CORS-ineligible resource`,
+        0,
         destination,
         // not piping ACAO header makes this CORS-ineligible
         xorigin_prefix + destination + ext + `?${token()}`,
@@ -194,6 +210,7 @@
         false,
         false,
         `Cross-origin ${destination}, not CORS request, with correct hash`,
+        1,
         destination,
         xorigin_prefix + destination + ext + `?${token()}` + anonymous,
         {integrity: sha256},
@@ -204,6 +221,7 @@
         false,
         false,
         `Cross-origin ${destination}, not CORS request, with hash mismatch`,
+        1,
         destination,
         xorigin_prefix + destination + ext + `?${token()}` + anonymous,
         {integrity: "sha256-deadbeef01Y0yKSx3/UoIKtIY2UQ9+H8WGyyMuOWOC0="},
@@ -214,6 +232,7 @@
         true,
         true,
         `Cross-origin ${destination}, empty integrity`,
+        1,
         destination,
         xorigin_prefix + destination + ext + `?${token()}` + anonymous,
         {},
@@ -224,6 +243,7 @@
         true,
         true,
         `Same-origin ${destination} with correct hash, options.`,
+        1,
         destination,
         same_origin_prefix + destination + ext + `?${token()}`,
         {integrity: `${sha256}?foo=bar?spam=eggs`},
@@ -234,6 +254,7 @@
         true,
         true,
         `Same-origin ${destination} with unknown algorithm only.`,
+        1,
         destination,
         same_origin_prefix + destination + ext + `?${token()}`,
         {integrity: "foo666-8aBiAJl3ukQwSJ6eTs5wl6hGjnOtyXjcTRdAf89uIfY="},
@@ -248,6 +269,7 @@
         true,
         true,
         `Same-origin ${destination} with matching digest re-uses preload with matching digest.`,
+        1,
         destination,
         same_origin_prefix + destination + ext + `?${token()}`,
         {integrity: sha256},
@@ -258,6 +280,7 @@
         true,
         false,
         `Same-origin ${destination} with non-matching digest does not re-use preload with matching digest.`,
+        2,
         destination,
         same_origin_prefix + destination + ext + `?${token()}`,
         {integrity: sha256},
@@ -268,6 +291,7 @@
         false,
         true,
         `Same-origin ${destination} with matching digest does not re-use preload with non-matching digest.`,
+        2,
         destination,
         same_origin_prefix + destination + ext + `?${token()}`,
         {integrity: "sha256-deadbeefQ15RYHFvsYdWumweeFAw0hJDTFt9seErghA="},
@@ -278,6 +302,7 @@
         false,
         false,
         `Same-origin ${destination} with non-matching digest does not re-use preload with non-matching digest.`,
+        2,
         destination,
         same_origin_prefix + destination + ext + `?${token()}`,
         {integrity: "sha256-deadbeefQ15RYHFvsYdWumweeFAw0hJDTFt9seErghA="},
diff --git a/third_party/blink/web_tests/external/wpt/resources/sriharness.js b/third_party/blink/web_tests/external/wpt/resources/sriharness.js
index f0d284e..d57a1b3 100644
--- a/third_party/blink/web_tests/external/wpt/resources/sriharness.js
+++ b/third_party/blink/web_tests/external/wpt/resources/sriharness.js
@@ -71,9 +71,12 @@
   return element;
 }
 
+// When using SRIPreloadTest, also include /preload/resources/preload_helper.js
+// |number_of_requests| is used to ensure that preload requests are actually
+// reused as expected.
 const SRIPreloadTest = (preload_sri_success, subresource_sri_success, name,
-                        destination, resource_url, link_attrs,
-                        subresource_attrs) => {
+                        number_of_requests, destination, resource_url,
+                        link_attrs, subresource_attrs) => {
   const test = async_test(name);
   const link = document.createElement('link');
 
@@ -101,7 +104,10 @@
     { assert_unreached("Valid subresource fired error handler.") });
   const invalid_subresource_succeeded = test.step_func(() =>
     { assert_unreached("Invalid subresource load succeeded.") });
-  const subresource_pass = test.step_func(() => { test.done(); });
+  const subresource_pass = test.step_func(() => {
+    verifyNumberOfResourceTimingEntries(resource_url, number_of_requests);
+    test.done();
+  });
   const preload_pass = test.step_func(() => {
     const subresource_element = buildElementFromDestination(
       resource_url,
diff --git a/third_party/blink/web_tests/external/wpt/tools/wpt/android.py b/third_party/blink/web_tests/external/wpt/tools/wpt/android.py
index 51deb71..744e134d 100644
--- a/third_party/blink/web_tests/external/wpt/tools/wpt/android.py
+++ b/third_party/blink/web_tests/external/wpt/tools/wpt/android.py
@@ -89,8 +89,8 @@
 
     #TODO: Not sure what's really needed here
     packages = ["platform-tools",
-                "build-tools;28.0.3",
-                "platforms;android-28",
+                "build-tools;29.0.3",
+                "platforms;android-29",
                 "emulator"]
 
     # TODO: make this work non-internactively
diff --git a/third_party/blink/web_tests/http/tests/devtools/oopif/oopif-performance-monitor-expected.txt b/third_party/blink/web_tests/http/tests/devtools/oopif/oopif-performance-monitor-expected.txt
index c9a47ec9..8be85ea 100644
--- a/third_party/blink/web_tests/http/tests/devtools/oopif/oopif-performance-monitor-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/oopif/oopif-performance-monitor-expected.txt
@@ -3,6 +3,7 @@
 
 Metrics reported:
 AdSubframes
+ArrayBufferContents
 AudioHandlers
 ContextLifecycleStateObservers
 DetachedScriptStates
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/network/same-site-issue-blocked-cookie-not-secure-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/network/same-site-issue-blocked-cookie-not-secure-expected.txt
new file mode 100644
index 0000000..fa1ce5d
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/network/same-site-issue-blocked-cookie-not-secure-expected.txt
@@ -0,0 +1,31 @@
+Verifies that setting a cookie with SameSite=None and without Secure triggers an inspector issue.
+
+Inspector issue: {
+  "issue": {
+    "code": "SameSiteCookieIssue",
+    "details": {
+      "sameSiteCookieIssueDetails": {
+        "cookie": {
+          "name": "name",
+          "path": "/inspector-protocol/network/resources",
+          "domain": "cookie.test"
+        },
+        "cookieWarningReasons": [
+          "WarnSameSiteNoneInsecure"
+        ],
+        "cookieExclusionReasons": [
+          "ExcludeSameSiteNoneInsecure"
+        ],
+        "operation": "SetCookie",
+        "siteForCookies": "http://127.0.0.1/",
+        "cookieUrl": "https://cookie.test:8443/inspector-protocol/network/resources/set-cookie.php?cookie=name%3Dvalue%3B%20SameSite%3DNone",
+        "request": {
+          "requestId": "<request-id>",
+          "url": "https://cookie.test:8443/inspector-protocol/network/resources/set-cookie.php?cookie=name%3Dvalue%3B%20SameSite%3DNone"
+        }
+      }
+    }
+  }
+}
+
+
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/network/same-site-issue-blocked-cookie-not-secure.js b/third_party/blink/web_tests/http/tests/inspector-protocol/network/same-site-issue-blocked-cookie-not-secure.js
new file mode 100644
index 0000000..b03b8b4
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/network/same-site-issue-blocked-cookie-not-secure.js
@@ -0,0 +1,21 @@
+(async function(testRunner) {
+  const {page, session, dp} = await testRunner.startBlank(
+      `Verifies that setting a cookie with SameSite=None and without Secure triggers an inspector issue.\n`);
+
+  await dp.Network.enable();
+  await dp.Audits.enable();
+
+  const issuePromise = dp.Audits.onceIssueAdded();
+  const setCookieUrl = 'https://cookie.test:8443/inspector-protocol/network/resources/set-cookie.php?cookie='
+      + encodeURIComponent('name=value; SameSite=None');
+  await session.evaluate(`fetch('${setCookieUrl}', {method: 'POST', credentials: 'include'})`);
+  const issue = await issuePromise;
+  // Clear request id.
+  const replacer = (key, value) => {
+    if (key === "requestId") return "<request-id>";
+    return value;
+  };
+  testRunner.log(`Inspector issue: ${JSON.stringify(issue.params, replacer, 2)}\n`);
+
+  testRunner.completeTest();
+})
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/network/same-site-issue-warn-cookie-insecure-secure-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/network/same-site-issue-warn-cookie-insecure-secure-expected.txt
new file mode 100644
index 0000000..8660f957
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/network/same-site-issue-warn-cookie-insecure-secure-expected.txt
@@ -0,0 +1,29 @@
+Verifies that setting a cookie cross-scheme triggers an inspector issue.
+
+Inspector issue: {
+  "issue": {
+    "code": "SameSiteCookieIssue",
+    "details": {
+      "sameSiteCookieIssueDetails": {
+        "cookie": {
+          "name": "name",
+          "path": "/inspector-protocol/network/resources",
+          "domain": "cookie.test"
+        },
+        "cookieWarningReasons": [
+          "WarnSameSiteCrossSchemeSecureUrlLax"
+        ],
+        "cookieExclusionReasons": [],
+        "operation": "SetCookie",
+        "siteForCookies": "http://cookie.test/",
+        "cookieUrl": "https://cookie.test:8443/inspector-protocol/network/resources/set-cookie.php?cookie=name%3Dvalue%3B",
+        "request": {
+          "requestId": "<request-id>",
+          "url": "https://cookie.test:8443/inspector-protocol/network/resources/set-cookie.php?cookie=name%3Dvalue%3B"
+        }
+      }
+    }
+  }
+}
+
+
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/network/same-site-issue-warn-cookie-insecure-secure.js b/third_party/blink/web_tests/http/tests/inspector-protocol/network/same-site-issue-warn-cookie-insecure-secure.js
new file mode 100644
index 0000000..5054e821
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/network/same-site-issue-warn-cookie-insecure-secure.js
@@ -0,0 +1,23 @@
+(async function(testRunner) {
+  const {page, session, dp} = await testRunner.startBlank(
+      `Verifies that setting a cookie cross-scheme triggers an inspector issue.\n`);
+
+  await dp.Network.enable();
+  await dp.Audits.enable();
+
+  await session.navigate('http://cookie.test:8000/inspector-protocol/resources/empty.html');
+
+  const issuePromise = dp.Audits.onceIssueAdded();
+  const setCookieUrl = 'https://cookie.test:8443/inspector-protocol/network/resources/set-cookie.php?cookie='
+      + encodeURIComponent('name=value;');
+  await session.evaluate(`fetch('${setCookieUrl}', {method: 'POST', credentials: 'include'})`);
+  const issue = await issuePromise;
+  // Clear request id.
+  const replacer = (key, value) => {
+    if (key === "requestId") return "<request-id>";
+    return value;
+  };
+  testRunner.log(`Inspector issue: ${JSON.stringify(issue.params, replacer, 2)}\n`);
+
+  testRunner.completeTest();
+});
diff --git a/third_party/blink/web_tests/inspector-protocol/performance/perf-push-metrics-expected.txt b/third_party/blink/web_tests/inspector-protocol/performance/perf-push-metrics-expected.txt
index b596012..80d609e7 100644
--- a/third_party/blink/web_tests/inspector-protocol/performance/perf-push-metrics-expected.txt
+++ b/third_party/blink/web_tests/inspector-protocol/performance/perf-push-metrics-expected.txt
@@ -18,6 +18,7 @@
 	ResourceFetchers
 	AdSubframes
 	DetachedScriptStates
+	ArrayBufferContents
 	LayoutCount
 	RecalcStyleCount
 	LayoutDuration
@@ -52,6 +53,7 @@
 	ResourceFetchers
 	AdSubframes
 	DetachedScriptStates
+	ArrayBufferContents
 	LayoutCount
 	RecalcStyleCount
 	LayoutDuration
@@ -86,6 +88,7 @@
 	ResourceFetchers
 	AdSubframes
 	DetachedScriptStates
+	ArrayBufferContents
 	LayoutCount
 	RecalcStyleCount
 	LayoutDuration
diff --git a/third_party/blink/web_tests/platform/linux/virtual/text-antialias/international/bidi-LDB-2-CSS-expected.png b/third_party/blink/web_tests/platform/linux/virtual/text-antialias/international/bidi-LDB-2-CSS-expected.png
index 25bbe6e..c69a1f8 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/text-antialias/international/bidi-LDB-2-CSS-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/text-antialias/international/bidi-LDB-2-CSS-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/text-antialias/international/bidi-LDB-2-HTML-expected.png b/third_party/blink/web_tests/platform/linux/virtual/text-antialias/international/bidi-LDB-2-HTML-expected.png
index d5d36be..5282821 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/text-antialias/international/bidi-LDB-2-HTML-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/text-antialias/international/bidi-LDB-2-HTML-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/text-antialias/international/bidi-LDB-2-formatting-characters-expected.png b/third_party/blink/web_tests/platform/linux/virtual/text-antialias/international/bidi-LDB-2-formatting-characters-expected.png
index 305d11b..9899531e 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/text-antialias/international/bidi-LDB-2-formatting-characters-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/text-antialias/international/bidi-LDB-2-formatting-characters-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/text-antialias/international/bidi-LDB-2-CSS-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/text-antialias/international/bidi-LDB-2-CSS-expected.png
index 3e136c2..7530c4759 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/text-antialias/international/bidi-LDB-2-CSS-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/text-antialias/international/bidi-LDB-2-CSS-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/text-antialias/international/bidi-LDB-2-HTML-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/text-antialias/international/bidi-LDB-2-HTML-expected.png
index bae5831..7747532 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/text-antialias/international/bidi-LDB-2-HTML-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/text-antialias/international/bidi-LDB-2-HTML-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/text-antialias/international/bidi-LDB-2-formatting-characters-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/text-antialias/international/bidi-LDB-2-formatting-characters-expected.png
index 0db9e336..de5b9480 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/text-antialias/international/bidi-LDB-2-formatting-characters-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/text-antialias/international/bidi-LDB-2-formatting-characters-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/text-antialias/international/bidi-LDB-2-CSS-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/text-antialias/international/bidi-LDB-2-CSS-expected.png
index aa0e8da..d28cd1e 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/text-antialias/international/bidi-LDB-2-CSS-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/text-antialias/international/bidi-LDB-2-CSS-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/text-antialias/international/bidi-LDB-2-HTML-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/text-antialias/international/bidi-LDB-2-HTML-expected.png
index 0b193a0..f712a00 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/text-antialias/international/bidi-LDB-2-HTML-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/text-antialias/international/bidi-LDB-2-HTML-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/text-antialias/international/bidi-LDB-2-formatting-characters-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/text-antialias/international/bidi-LDB-2-formatting-characters-expected.png
index 64120058..b594d2ad9 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/text-antialias/international/bidi-LDB-2-formatting-characters-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/text-antialias/international/bidi-LDB-2-formatting-characters-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/text-antialias/international/bidi-LDB-2-CSS-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/text-antialias/international/bidi-LDB-2-CSS-expected.png
index fe6a0223..545030f 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/text-antialias/international/bidi-LDB-2-CSS-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/text-antialias/international/bidi-LDB-2-CSS-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/text-antialias/international/bidi-LDB-2-HTML-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/text-antialias/international/bidi-LDB-2-HTML-expected.png
index 4c1bccd9..2f21870 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/text-antialias/international/bidi-LDB-2-HTML-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/text-antialias/international/bidi-LDB-2-HTML-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/text-antialias/international/bidi-LDB-2-formatting-characters-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/text-antialias/international/bidi-LDB-2-formatting-characters-expected.png
index c5fe464..b34fc8b 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/text-antialias/international/bidi-LDB-2-formatting-characters-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/text-antialias/international/bidi-LDB-2-formatting-characters-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/text-antialias/international/bidi-LDB-2-CSS-expected.png b/third_party/blink/web_tests/platform/mac/virtual/text-antialias/international/bidi-LDB-2-CSS-expected.png
index 1e8f4e83..4b6c30f 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/text-antialias/international/bidi-LDB-2-CSS-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/text-antialias/international/bidi-LDB-2-CSS-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/text-antialias/international/bidi-LDB-2-HTML-expected.png b/third_party/blink/web_tests/platform/mac/virtual/text-antialias/international/bidi-LDB-2-HTML-expected.png
index c5f6fd10..be70073 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/text-antialias/international/bidi-LDB-2-HTML-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/text-antialias/international/bidi-LDB-2-HTML-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/text-antialias/international/bidi-LDB-2-formatting-characters-expected.png b/third_party/blink/web_tests/platform/mac/virtual/text-antialias/international/bidi-LDB-2-formatting-characters-expected.png
index 8f5149ec..baf77e6 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/text-antialias/international/bidi-LDB-2-formatting-characters-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/text-antialias/international/bidi-LDB-2-formatting-characters-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/text-antialias/international/bidi-LDB-2-CSS-expected.png b/third_party/blink/web_tests/platform/win/virtual/text-antialias/international/bidi-LDB-2-CSS-expected.png
index 25da14b..cdcc2d21 100644
--- a/third_party/blink/web_tests/platform/win/virtual/text-antialias/international/bidi-LDB-2-CSS-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/text-antialias/international/bidi-LDB-2-CSS-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/text-antialias/international/bidi-LDB-2-HTML-expected.png b/third_party/blink/web_tests/platform/win/virtual/text-antialias/international/bidi-LDB-2-HTML-expected.png
index 0d7492d6..4144403 100644
--- a/third_party/blink/web_tests/platform/win/virtual/text-antialias/international/bidi-LDB-2-HTML-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/text-antialias/international/bidi-LDB-2-HTML-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/text-antialias/international/bidi-LDB-2-formatting-characters-expected.png b/third_party/blink/web_tests/platform/win/virtual/text-antialias/international/bidi-LDB-2-formatting-characters-expected.png
index 1ae6342..be6744f7 100644
--- a/third_party/blink/web_tests/platform/win/virtual/text-antialias/international/bidi-LDB-2-formatting-characters-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/text-antialias/international/bidi-LDB-2-formatting-characters-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/text-antialias/international/bidi-LDB-2-CSS-expected.png b/third_party/blink/web_tests/platform/win7/virtual/text-antialias/international/bidi-LDB-2-CSS-expected.png
index 17daead..811745d 100644
--- a/third_party/blink/web_tests/platform/win7/virtual/text-antialias/international/bidi-LDB-2-CSS-expected.png
+++ b/third_party/blink/web_tests/platform/win7/virtual/text-antialias/international/bidi-LDB-2-CSS-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/text-antialias/international/bidi-LDB-2-HTML-expected.png b/third_party/blink/web_tests/platform/win7/virtual/text-antialias/international/bidi-LDB-2-HTML-expected.png
index 12d5078..344b6d56 100644
--- a/third_party/blink/web_tests/platform/win7/virtual/text-antialias/international/bidi-LDB-2-HTML-expected.png
+++ b/third_party/blink/web_tests/platform/win7/virtual/text-antialias/international/bidi-LDB-2-HTML-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/text-antialias/international/bidi-LDB-2-formatting-characters-expected.png b/third_party/blink/web_tests/platform/win7/virtual/text-antialias/international/bidi-LDB-2-formatting-characters-expected.png
index ec6e772..3c26a6a 100644
--- a/third_party/blink/web_tests/platform/win7/virtual/text-antialias/international/bidi-LDB-2-formatting-characters-expected.png
+++ b/third_party/blink/web_tests/platform/win7/virtual/text-antialias/international/bidi-LDB-2-formatting-characters-expected.png
Binary files differ
diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium
index 29a82688..1528ad70 100644
--- a/third_party/freetype/README.chromium
+++ b/third_party/freetype/README.chromium
@@ -1,7 +1,7 @@
 Name: FreeType
 URL: http://www.freetype.org/
-Version: VER-2-10-1-114-g7a019a63e
-Revision: 7a019a63ed9753772e758beec3cad7c0b74ee2aa
+Version: VER-2-10-1-115-g11beee855
+Revision: 11beee855e29757a07320fd60e85de2e8da4e037
 CPEPrefix: cpe:/a:freetype:freetype:2.10.1
 License: Custom license "inspired by the BSD, Artistic, and IJG (Independent
          JPEG Group) licenses"
diff --git a/tools/idl_parser/idl_parser.py b/tools/idl_parser/idl_parser.py
index f8e4d685..5dfacf3 100755
--- a/tools/idl_parser/idl_parser.py
+++ b/tools/idl_parser/idl_parser.py
@@ -918,7 +918,8 @@
 
     if len(p) == 6:
       cls = 'Sequence' if p[1] == 'sequence' else 'FrozenArray'
-      p[0] = self.BuildProduction(cls, p, 1, ListFromConcat(p[3], p[5]))
+      p[0] = self.BuildProduction(cls, p, 1, p[3])
+      p[0] = ListFromConcat(p[0], p[5])
 
   # Added StringType, OBJECT
   def p_PrimitiveType(self, p):
diff --git a/tools/idl_parser/test_parser/typedef_web.idl b/tools/idl_parser/test_parser/typedef_web.idl
index 13cf2033..df82cbb4 100644
--- a/tools/idl_parser/test_parser/typedef_web.idl
+++ b/tools/idl_parser/test_parser/typedef_web.idl
@@ -180,3 +180,13 @@
  *    PrimitiveType(double)
  */
 typedef double Date;
+
+/** TREE
+ *Typedef(StringSequenceOrNull)
+ *  Type()
+ *    NULLABLE: True
+ *    Sequence()
+ *      Type()
+ *        StringType(DOMString)
+ */
+typedef sequence<DOMString>? StringSequenceOrNull;
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 8083f90..a5c46ff 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -69267,6 +69267,8 @@
   <int value="39" label="WebFileSystem"/>
   <int value="40" label="OutstandingNetworkRequestFetch"/>
   <int value="41" label="OutstandingNetworkRequestXHR"/>
+  <int value="42" label="AppBanner"/>
+  <int value="43" label="Printing"/>
 </enum>
 
 <enum name="WebShareMethod">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index f6ec3a4..c3220515 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -149024,6 +149024,17 @@
   </summary>
 </histogram>
 
+<histogram name="Settings.PrivacyElementInteractions"
+    enum="SettingsPrivacyElementInteractions" expires_after="M86">
+  <owner>harrisonsean@chromium.org</owner>
+  <owner>msramek@chromium.org</owner>
+  <owner>sauski@chromium.org</owner>
+  <summary>
+    Which privacy related settings elements a user interacted with. Recorded
+    every time a user interacts with an element of interest.
+  </summary>
+</histogram>
+
 <histogram name="Settings.RegisterProfilePrefsTime" units="ms"
     expires_after="M80">
   <obsolete>
@@ -149517,6 +149528,10 @@
 
 <histogram name="SettingsPage.PrivacyElementInteractions"
     enum="SettingsPrivacyElementInteractions" expires_after="M84">
+  <obsolete>
+    Removed 04/2020. Replaced with Settings.PrivacyElementInteractions to stick
+    to naming conventions.
+  </obsolete>
   <owner>harrisonsean@chromium.org</owner>
   <owner>msramek@chromium.org</owner>
   <owner>sauski@chromium.org</owner>
@@ -175252,7 +175267,7 @@
 </histogram>
 
 <histogram name="WebApk.Install.AvailableSpace.Fail" units="MB"
-    expires_after="M82">
+    expires_after="2021-02-01">
   <owner>hanxi@chromium.org</owner>
   <owner>yfriedman@chromium.org</owner>
   <summary>
@@ -175299,7 +175314,7 @@
 </histogram>
 
 <histogram name="WebApk.Install.AvailableSpaceAfterFreeUpCache.Fail" units="MB"
-    expires_after="M82">
+    expires_after="2021-02-01">
   <owner>hanxi@chromium.org</owner>
   <owner>yfriedman@chromium.org</owner>
   <summary>
@@ -175313,7 +175328,7 @@
 
 <histogram
     name="WebApk.Install.AvailableSpaceAfterFreeUpUnimportantStorage.Fail"
-    units="MB" expires_after="M80">
+    units="MB" expires_after="2020-02-01">
   <obsolete>
     Removed in Chrome M69.
   </obsolete>
@@ -175331,6 +175346,9 @@
 
 <histogram name="WebApk.Install.ChromeCacheSize.Fail" units="MB"
     expires_after="M82">
+  <obsolete>
+    Removed 2020-04.
+  </obsolete>
   <owner>hanxi@chromium.org</owner>
   <owner>yfriedman@chromium.org</owner>
   <summary>
@@ -175369,7 +175387,7 @@
 </histogram>
 
 <histogram name="WebApk.Install.GooglePlayErrorCode"
-    enum="WebApkInstallGooglePlayErrorCode" expires_after="2020-08-30">
+    enum="WebApkInstallGooglePlayErrorCode" expires_after="2021-02-01">
   <owner>hanxi@chromium.org</owner>
   <owner>pkotwicz@chromium.org</owner>
   <owner>yfriedman@chromium.org</owner>
@@ -175480,6 +175498,9 @@
 
 <histogram name="WebApk.Install.SpaceStatus" enum="WebApkInstallSpaceStatus"
     expires_after="M81">
+  <obsolete>
+    Removed 2020-04.
+  </obsolete>
   <owner>hanxi@chromium.org</owner>
   <owner>yfriedman@chromium.org</owner>
   <summary>
@@ -175544,6 +175565,9 @@
 
 <histogram name="WebApk.Navigation.ChildTab.InScope" enum="BooleanInScope"
     expires_after="2020-10-04">
+  <obsolete>
+    Removed 2020-04.
+  </obsolete>
   <owner>hartmanng@chromium.org</owner>
   <owner>peconn@chromium.org</owner>
   <owner>pkotwicz@chromium.org</owner>
@@ -175555,7 +175579,7 @@
 </histogram>
 
 <histogram name="WebApk.Navigation.InScope" enum="Boolean"
-    expires_after="2020-04-01">
+    expires_after="2021-02-01">
   <owner>hartmanng@chromium.org</owner>
   <owner>pkotwicz@chromium.org</owner>
   <owner>yfriedman@chromium.org</owner>
@@ -175741,7 +175765,7 @@
 </histogram>
 
 <histogram name="WebApk.Update.GooglePlayUpdateResult"
-    enum="WebApkGooglePlayInstallResult" expires_after="M81">
+    enum="WebApkGooglePlayInstallResult" expires_after="2021-02-01">
   <owner>hanxi@chromium.org</owner>
   <owner>pkotwicz@chromium.org</owner>
   <owner>yfriedman@chromium.org</owner>
@@ -175752,7 +175776,7 @@
 </histogram>
 
 <histogram name="WebApk.Update.NumStaleUpdateRequestFiles" units="files"
-    expires_after="M81">
+    expires_after="2021-02-01">
   <owner>hanxi@chromium.org</owner>
   <owner>pkotwicz@chromium.org</owner>
   <owner>yfriedman@chromium.org</owner>
@@ -175764,7 +175788,7 @@
 </histogram>
 
 <histogram name="WebApk.Update.RequestQueued" enum="WebApkUpdateRequestQueued"
-    expires_after="M81">
+    expires_after="2021-02-01">
   <owner>hanxi@chromium.org</owner>
   <owner>pkotwicz@chromium.org</owner>
   <owner>yfriedman@chromium.org</owner>
@@ -175775,7 +175799,7 @@
 </histogram>
 
 <histogram name="WebApk.Update.RequestSent" enum="WebApkUpdateRequestSent"
-    expires_after="M81">
+    expires_after="2021-02-01">
   <owner>hanxi@chromium.org</owner>
   <owner>pkotwicz@chromium.org</owner>
   <owner>yfriedman@chromium.org</owner>
@@ -175786,7 +175810,7 @@
 </histogram>
 
 <histogram name="WebApk.WebApkService.BindSuccess" enum="BooleanSuccess"
-    expires_after="M81">
+    expires_after="2021-02-01">
   <owner>hanxi@chromium.org</owner>
   <owner>pkotwicz@chromium.org</owner>
   <owner>yfriedman@chromium.org</owner>
@@ -176054,6 +176078,9 @@
 
 <histogram name="Webapp.Splashscreen.Hides" enum="SplashHidesReason"
     expires_after="M80">
+  <obsolete>
+    Removed 2020-04.
+  </obsolete>
   <owner>pkotwicz@chromium.org</owner>
   <owner>hartmanng@chromium.org</owner>
   <summary>Records the signal that was used to hide the splashscreen.</summary>
@@ -197072,6 +197099,7 @@
 
 <histogram_suffixes name="ProcessMemoryAllocatorTiny2" separator=".">
   <suffix name="NumberOfAdSubframes" label=""/>
+  <suffix name="NumberOfArrayBufferContents" label=""/>
   <suffix name="NumberOfAudioHandler" label=""/>
   <suffix name="NumberOfContextLifecycleStateObserver" label=""/>
   <suffix name="NumberOfDetachedScriptStates" label=""/>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index 41728fe..0940c4a 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -6020,6 +6020,11 @@
       The number of ad subframes that the associated renderer owns.
     </summary>
   </metric>
+  <metric name="NumberOfArrayBufferContents">
+    <summary>
+      The number of arraybuffer contents that the associated renderer owns.
+    </summary>
+  </metric>
   <metric name="NumberOfCallsInDetachedWindowByClosing">
     <obsolete>
       Deprecated as of 01/2020.
diff --git a/tools/perf/core/perfetto_binary_roller/BUILD.gn b/tools/perf/core/perfetto_binary_roller/BUILD.gn
index efd3859..d834bd63 100644
--- a/tools/perf/core/perfetto_binary_roller/BUILD.gn
+++ b/tools/perf/core/perfetto_binary_roller/BUILD.gn
@@ -14,10 +14,17 @@
     "//tools/perf/core/",
     "//DEPS",
   ]
+
+  if (is_win) {
+    binary_name = "trace_processor_shell.exe"
+  } else {
+    binary_name = "trace_processor_shell"
+  }
+
   executable = "upload_trace_processor.py"
   wrapper_script = "$root_build_dir/upload_trace_processor"
   executable_args = [
     "--path",
-    "@WrappedPath(./trace_processor_shell)",
+    "@WrappedPath(./$binary_name)",
   ]
 }
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.cc b/ui/accessibility/platform/ax_platform_node_auralinux.cc
index c4a8398..d5931fc 100644
--- a/ui/accessibility/platform/ax_platform_node_auralinux.cc
+++ b/ui/accessibility/platform/ax_platform_node_auralinux.cc
@@ -177,20 +177,6 @@
 static GetRowHeaderCellsFunc g_atk_table_cell_get_row_header_cells;
 static GetRowColumnSpanFunc g_atk_table_cell_get_row_column_span;
 
-AXPlatformNodeAuraLinux* AtkObjectToAXPlatformNodeAuraLinux(
-    AtkObject* atk_object) {
-  if (!atk_object)
-    return nullptr;
-
-  if (IS_AX_PLATFORM_NODE_AURALINUX(atk_object)) {
-    AXPlatformNodeAuraLinuxObject* platform_object =
-        AX_PLATFORM_NODE_AURALINUX(atk_object);
-    return platform_object->m_object;
-  }
-
-  return nullptr;
-}
-
 // The ATK API often requires pointers to be used as out arguments, while
 // allowing for those pointers to be null if the caller is not interested in
 // the value. This function is a simpler helper to avoid continually checking
@@ -210,23 +196,23 @@
 
 AtkObject* FindAtkObjectParentFrame(AtkObject* atk_object) {
   AXPlatformNodeAuraLinux* node =
-      AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   while (node) {
     if (node->GetAtkRole() == ATK_ROLE_FRAME)
       return node->GetNativeViewAccessible();
-    node = AtkObjectToAXPlatformNodeAuraLinux(node->GetParent());
+    node = AXPlatformNodeAuraLinux::FromAtkObject(node->GetParent());
   }
   return nullptr;
 }
 
 AtkObject* FindAtkObjectToplevelParentDocument(AtkObject* atk_object) {
   AXPlatformNodeAuraLinux* node =
-      AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   AtkObject* toplevel_document = nullptr;
   while (node) {
     if (node->GetAtkRole() == ATK_ROLE_DOCUMENT_WEB)
       toplevel_document = node->GetNativeViewAccessible();
-    node = AtkObjectToAXPlatformNodeAuraLinux(node->GetParent());
+    node = AXPlatformNodeAuraLinux::FromAtkObject(node->GetParent());
   }
   return toplevel_document;
 }
@@ -237,7 +223,7 @@
     if (current_frame == frame)
       return true;
     AXPlatformNodeAuraLinux* frame_node =
-        AtkObjectToAXPlatformNodeAuraLinux(current_frame);
+        AXPlatformNodeAuraLinux::FromAtkObject(current_frame);
     current_frame = FindAtkObjectParentFrame(frame_node->GetParent());
   }
   return false;
@@ -345,7 +331,7 @@
     return gfx::Point(0, 0);
 
   AXPlatformNodeAuraLinux* node =
-      AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (node->GetAtkRole() == ATK_ROLE_FRAME) {
     int x, y;
     atk_component_get_extents(ATK_COMPONENT(atk_object), &x, &y, nullptr,
@@ -373,7 +359,7 @@
   if (!g_current_focused)
     return nullptr;
 
-  auto* node = AtkObjectToAXPlatformNodeAuraLinux(g_current_focused);
+  auto* node = AXPlatformNodeAuraLinux::FromAtkObject(g_current_focused);
   if (!node)
     return nullptr;
 
@@ -482,7 +468,8 @@
     *height = 0;
 
   AtkObject* atk_object = ATK_OBJECT(atk_component);
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return;
 
@@ -501,7 +488,8 @@
     *y = 0;
 
   AtkObject* atk_object = ATK_OBJECT(atk_component);
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return;
 
@@ -517,7 +505,8 @@
     *height = 0;
 
   AtkObject* atk_object = ATK_OBJECT(atk_component);
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return;
 
@@ -530,7 +519,8 @@
                                AtkCoordType coord_type) {
   g_return_val_if_fail(ATK_IS_COMPONENT(atk_component), nullptr);
   AtkObject* atk_object = ATK_OBJECT(atk_component);
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return nullptr;
 
@@ -543,7 +533,8 @@
 gboolean GrabFocus(AtkComponent* atk_component) {
   g_return_val_if_fail(ATK_IS_COMPONENT(atk_component), FALSE);
   AtkObject* atk_object = ATK_OBJECT(atk_component);
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return FALSE;
 
@@ -555,7 +546,7 @@
   g_return_val_if_fail(ATK_IS_COMPONENT(atk_component), FALSE);
 
   AXPlatformNodeAuraLinux* obj =
-      AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(atk_component));
+      AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(atk_component));
   if (!obj)
     return FALSE;
 
@@ -570,7 +561,7 @@
   g_return_val_if_fail(ATK_IS_COMPONENT(atk_component), FALSE);
 
   AXPlatformNodeAuraLinux* obj =
-      AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(atk_component));
+      AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(atk_component));
   if (!obj)
     return FALSE;
 
@@ -605,7 +596,8 @@
   g_return_val_if_fail(!index, FALSE);
 
   AtkObject* atk_object = ATK_OBJECT(atk_action);
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return FALSE;
 
@@ -616,7 +608,8 @@
   g_return_val_if_fail(ATK_IS_ACTION(atk_action), 0);
 
   AtkObject* atk_object = ATK_OBJECT(atk_action);
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return 0;
 
@@ -634,7 +627,8 @@
   g_return_val_if_fail(!index, nullptr);
 
   AtkObject* atk_object = ATK_OBJECT(atk_action);
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return nullptr;
 
@@ -646,7 +640,8 @@
   g_return_val_if_fail(!index, nullptr);
 
   AtkObject* atk_object = ATK_OBJECT(atk_action);
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return nullptr;
 
@@ -674,7 +669,8 @@
   g_return_val_if_fail(ATK_IS_DOCUMENT(atk_doc), nullptr);
 
   AtkObject* atk_object = ATK_OBJECT(atk_doc);
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return nullptr;
 
@@ -685,7 +681,8 @@
   g_return_val_if_fail(ATK_IS_DOCUMENT(atk_doc), 0);
 
   AtkObject* atk_object = ATK_OBJECT(atk_doc);
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return nullptr;
 
@@ -711,7 +708,8 @@
   g_return_if_fail(ATK_IMAGE(atk_img));
 
   AtkObject* atk_object = ATK_OBJECT(atk_img);
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return;
 
@@ -722,7 +720,8 @@
   g_return_val_if_fail(ATK_IMAGE(atk_img), nullptr);
 
   AtkObject* atk_object = ATK_OBJECT(atk_img);
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return nullptr;
 
@@ -734,7 +733,8 @@
   g_return_if_fail(ATK_IMAGE(atk_img));
 
   AtkObject* atk_object = ATK_OBJECT(atk_img);
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return;
 
@@ -758,7 +758,8 @@
   g_return_if_fail(ATK_IS_VALUE(atk_value));
 
   AtkObject* atk_object = ATK_OBJECT(atk_value);
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return;
 
@@ -770,7 +771,8 @@
   g_return_if_fail(ATK_IS_VALUE(atk_value));
 
   AtkObject* atk_object = ATK_OBJECT(atk_value);
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return;
 
@@ -782,7 +784,8 @@
   g_return_if_fail(ATK_IS_VALUE(atk_value));
 
   AtkObject* atk_object = ATK_OBJECT(atk_value);
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return;
 
@@ -794,7 +797,8 @@
   g_return_if_fail(ATK_IS_VALUE(atk_value));
 
   AtkObject* atk_object = ATK_OBJECT(atk_value);
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return;
 
@@ -806,7 +810,8 @@
   g_return_val_if_fail(ATK_IS_VALUE(atk_value), FALSE);
 
   AtkObject* atk_object = ATK_OBJECT(atk_value);
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return FALSE;
 
@@ -854,7 +859,8 @@
   g_return_val_if_fail(ATK_HYPERLINK_IMPL(atk_hyperlink_impl), 0);
 
   AtkObject* atk_object = ATK_OBJECT(atk_hyperlink_impl);
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return 0;
 
@@ -877,7 +883,7 @@
 
 AtkHyperlink* GetLink(AtkHypertext* hypertext, int index) {
   g_return_val_if_fail(ATK_HYPERTEXT(hypertext), 0);
-  auto* obj = AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(hypertext));
+  auto* obj = AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(hypertext));
   if (!obj)
     return nullptr;
 
@@ -897,14 +903,14 @@
 int GetNLinks(AtkHypertext* hypertext) {
   g_return_val_if_fail(ATK_HYPERTEXT(hypertext), 0);
   AXPlatformNodeAuraLinux* obj =
-      AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(hypertext));
+      AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(hypertext));
   return obj ? obj->GetAXHypertext().hyperlinks.size() : 0;
 }
 
 int GetLinkIndex(AtkHypertext* hypertext, int char_index) {
   g_return_val_if_fail(ATK_HYPERTEXT(hypertext), 0);
   AXPlatformNodeAuraLinux* obj =
-      AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(hypertext));
+      AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(hypertext));
   if (!obj)
     return -1;
 
@@ -931,7 +937,8 @@
   g_return_val_if_fail(ATK_IS_TEXT(atk_text), nullptr);
 
   AtkObject* atk_object = ATK_OBJECT(atk_text);
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return nullptr;
 
@@ -960,7 +967,8 @@
   g_return_val_if_fail(ATK_IS_TEXT(atk_text), 0);
 
   AtkObject* atk_object = ATK_OBJECT(atk_text);
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return 0;
 
@@ -971,7 +979,8 @@
   g_return_val_if_fail(ATK_IS_TEXT(atk_text), 0);
 
   AtkObject* atk_object = ATK_OBJECT(atk_text);
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return 0;
 
@@ -999,7 +1008,8 @@
   *end_offset = -1;
 
   AtkObject* atk_object = ATK_OBJECT(atk_text);
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return nullptr;
 
@@ -1023,7 +1033,8 @@
   g_return_val_if_fail(ATK_IS_TEXT(atk_text), nullptr);
 
   AtkObject* atk_object = ATK_OBJECT(atk_text);
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return nullptr;
 
@@ -1116,7 +1127,7 @@
   g_return_val_if_fail(ATK_IS_TEXT(atk_text), -1);
 
   AXPlatformNodeAuraLinux* obj =
-      AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(atk_text));
+      AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(atk_text));
   if (!obj)
     return -1;
   return obj->GetCaretOffset();
@@ -1126,7 +1137,7 @@
   g_return_val_if_fail(ATK_IS_TEXT(atk_text), FALSE);
 
   AXPlatformNodeAuraLinux* obj =
-      AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(atk_text));
+      AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(atk_text));
   if (!obj)
     return FALSE;
   if (!obj->SetCaretOffset(offset))
@@ -1145,7 +1156,7 @@
   g_return_val_if_fail(ATK_IS_TEXT(atk_text), 0);
 
   AXPlatformNodeAuraLinux* obj =
-      AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(atk_text));
+      AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(atk_text));
   if (!obj)
     return 0;
 
@@ -1167,7 +1178,7 @@
   g_return_val_if_fail(ATK_IS_TEXT(atk_text), nullptr);
 
   AXPlatformNodeAuraLinux* obj =
-      AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(atk_text));
+      AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(atk_text));
   if (!obj)
     return nullptr;
   if (selection_num != 0)
@@ -1183,7 +1194,7 @@
     return FALSE;
 
   AXPlatformNodeAuraLinux* obj =
-      AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(atk_text));
+      AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(atk_text));
   if (!obj)
     return FALSE;
 
@@ -1204,7 +1215,7 @@
     return FALSE;
 
   AXPlatformNodeAuraLinux* obj =
-      AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(atk_text));
+      AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(atk_text));
   if (!obj)
     return FALSE;
 
@@ -1270,7 +1281,7 @@
 
   gfx::Rect rect;
   AXPlatformNodeAuraLinux* obj =
-      AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(atk_text));
+      AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(atk_text));
   if (obj) {
     switch (coordinate_type) {
 #if defined(ATK_230)
@@ -1311,7 +1322,7 @@
 
   gfx::Rect rect;
   AXPlatformNodeAuraLinux* obj =
-      AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(atk_text));
+      AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(atk_text));
   if (obj) {
     switch (coordinate_type) {
 #if defined(ATK_230)
@@ -1349,7 +1360,8 @@
     return nullptr;
 
   AtkObject* atk_object = ATK_OBJECT(atk_text);
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return nullptr;
 
@@ -1361,7 +1373,8 @@
   g_return_val_if_fail(ATK_IS_TEXT(atk_text), nullptr);
 
   AtkObject* atk_object = ATK_OBJECT(atk_text);
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return nullptr;
   return ToAtkAttributeSet(obj->GetDefaultTextAttributes());
@@ -1375,7 +1388,7 @@
   g_return_val_if_fail(ATK_IS_TEXT(atk_text), FALSE);
 
   AXPlatformNodeAuraLinux* obj =
-      AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(atk_text));
+      AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(atk_text));
   if (!obj)
     return FALSE;
 
@@ -1391,7 +1404,7 @@
   g_return_val_if_fail(ATK_IS_TEXT(atk_text), FALSE);
 
   AXPlatformNodeAuraLinux* obj =
-      AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(atk_text));
+      AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(atk_text));
   if (!obj)
     return FALSE;
 
@@ -1449,14 +1462,14 @@
   g_return_val_if_fail(ATK_IS_SELECTION(selection), FALSE);
 
   AXPlatformNodeAuraLinux* obj =
-      AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(selection));
+      AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(selection));
   if (!obj)
     return FALSE;
   if (index < 0 || index >= obj->GetChildCount())
     return FALSE;
 
   AXPlatformNodeAuraLinux* child =
-      AtkObjectToAXPlatformNodeAuraLinux(obj->ChildAtIndex(index));
+      AXPlatformNodeAuraLinux::FromAtkObject(obj->ChildAtIndex(index));
   if (!child)
     return FALSE;
 
@@ -1476,7 +1489,7 @@
   g_return_val_if_fail(ATK_IS_SELECTION(selection), FALSE);
 
   AXPlatformNodeAuraLinux* obj =
-      AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(selection));
+      AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(selection));
   if (!obj)
     return FALSE;
 
@@ -1484,7 +1497,7 @@
   bool success = true;
   for (int i = 0; i < child_count; ++i) {
     AXPlatformNodeAuraLinux* child =
-        AtkObjectToAXPlatformNodeAuraLinux(obj->ChildAtIndex(i));
+        AXPlatformNodeAuraLinux::FromAtkObject(obj->ChildAtIndex(i));
     if (!child)
       continue;
 
@@ -1508,7 +1521,7 @@
   g_return_val_if_fail(ATK_IS_SELECTION(selection), nullptr);
 
   AXPlatformNodeAuraLinux* obj =
-      AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(selection));
+      AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(selection));
   if (!obj)
     return nullptr;
 
@@ -1517,7 +1530,7 @@
   for (int i = 0; i < child_count; ++i) {
     AtkObject* child = obj->ChildAtIndex(i);
     AXPlatformNodeAuraLinux* child_ax_node =
-        AtkObjectToAXPlatformNodeAuraLinux(child);
+        AXPlatformNodeAuraLinux::FromAtkObject(child);
     if (!child_ax_node)
       continue;
 
@@ -1535,7 +1548,7 @@
   g_return_val_if_fail(ATK_IS_SELECTION(selection), 0);
 
   AXPlatformNodeAuraLinux* obj =
-      AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(selection));
+      AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(selection));
   if (!obj)
     return 0;
 
@@ -1543,7 +1556,7 @@
   gint selected_count = 0;
   for (int i = 0; i < child_count; ++i) {
     AXPlatformNodeAuraLinux* child =
-        AtkObjectToAXPlatformNodeAuraLinux(obj->ChildAtIndex(i));
+        AXPlatformNodeAuraLinux::FromAtkObject(obj->ChildAtIndex(i));
     if (!child)
       continue;
 
@@ -1558,14 +1571,14 @@
   g_return_val_if_fail(ATK_IS_SELECTION(selection), FALSE);
 
   AXPlatformNodeAuraLinux* obj =
-      AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(selection));
+      AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(selection));
   if (!obj)
     return FALSE;
   if (index < 0 || index >= obj->GetChildCount())
     return FALSE;
 
   AXPlatformNodeAuraLinux* child =
-      AtkObjectToAXPlatformNodeAuraLinux(obj->ChildAtIndex(index));
+      AXPlatformNodeAuraLinux::FromAtkObject(obj->ChildAtIndex(index));
   return child && child->GetBoolAttribute(ax::mojom::BoolAttribute::kSelected);
 }
 
@@ -1574,14 +1587,14 @@
   g_return_val_if_fail(ATK_IS_SELECTION(selection), FALSE);
 
   AXPlatformNodeAuraLinux* obj =
-      AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(selection));
+      AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(selection));
   if (!obj)
     return FALSE;
 
   int child_count = obj->GetChildCount();
   for (int i = 0; i < child_count; ++i) {
     AXPlatformNodeAuraLinux* child =
-        AtkObjectToAXPlatformNodeAuraLinux(obj->ChildAtIndex(i));
+        AXPlatformNodeAuraLinux::FromAtkObject(obj->ChildAtIndex(i));
     if (!child)
       continue;
 
@@ -1606,7 +1619,7 @@
   g_return_val_if_fail(ATK_IS_SELECTION(selection), FALSE);
 
   AXPlatformNodeAuraLinux* obj =
-      AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(selection));
+      AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(selection));
   if (!obj)
     return FALSE;
 
@@ -1614,7 +1627,7 @@
   bool success = true;
   for (int i = 0; i < child_count; ++i) {
     AXPlatformNodeAuraLinux* child =
-        AtkObjectToAXPlatformNodeAuraLinux(obj->ChildAtIndex(i));
+        AXPlatformNodeAuraLinux::FromAtkObject(obj->ChildAtIndex(i));
     if (!child)
       continue;
 
@@ -1654,7 +1667,7 @@
 AtkObject* RefAt(AtkTable* table, gint row, gint column) {
   g_return_val_if_fail(ATK_IS_TABLE(table), nullptr);
 
-  if (auto* obj = AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(table))) {
+  if (auto* obj = AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(table))) {
     if (AXPlatformNodeBase* cell = obj->GetTableCell(row, column)) {
       if (AtkObject* atk_cell = cell->GetNativeViewAccessible()) {
         g_object_ref(atk_cell);
@@ -1669,7 +1682,7 @@
 gint GetIndexAt(AtkTable* table, gint row, gint column) {
   g_return_val_if_fail(ATK_IS_TABLE(table), -1);
 
-  if (auto* obj = AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(table))) {
+  if (auto* obj = AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(table))) {
     if (const AXPlatformNodeBase* cell = obj->GetTableCell(row, column)) {
       DCHECK(cell->GetTableCellIndex().has_value());
       return cell->GetTableCellIndex().value();
@@ -1682,7 +1695,7 @@
 gint GetColumnAtIndex(AtkTable* table, gint index) {
   g_return_val_if_fail(ATK_IS_TABLE(table), -1);
 
-  if (auto* obj = AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(table))) {
+  if (auto* obj = AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(table))) {
     if (const AXPlatformNodeBase* cell = obj->GetTableCell(index)) {
       DCHECK(cell->GetTableColumn().has_value());
       return cell->GetTableColumn().value();
@@ -1695,7 +1708,7 @@
 gint GetRowAtIndex(AtkTable* table, gint index) {
   g_return_val_if_fail(ATK_IS_TABLE(table), -1);
 
-  if (auto* obj = AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(table))) {
+  if (auto* obj = AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(table))) {
     if (const AXPlatformNodeBase* cell = obj->GetTableCell(index)) {
       DCHECK(cell->GetTableRow().has_value());
       return cell->GetTableRow().value();
@@ -1708,7 +1721,7 @@
 gint GetNColumns(AtkTable* table) {
   g_return_val_if_fail(ATK_IS_TABLE(table), 0);
 
-  if (auto* obj = AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(table))) {
+  if (auto* obj = AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(table))) {
     // If the object is not a table, we return 0.
     return obj->GetTableColumnCount().value_or(0);
   }
@@ -1719,7 +1732,7 @@
 gint GetNRows(AtkTable* table) {
   g_return_val_if_fail(ATK_IS_TABLE(table), 0);
 
-  if (auto* obj = AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(table))) {
+  if (auto* obj = AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(table))) {
     // If the object is not a table, we return 0.
     return obj->GetTableRowCount().value_or(0);
   }
@@ -1730,7 +1743,7 @@
 gint GetColumnExtentAt(AtkTable* table, gint row, gint column) {
   g_return_val_if_fail(ATK_IS_TABLE(table), 0);
 
-  if (auto* obj = AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(table))) {
+  if (auto* obj = AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(table))) {
     if (const AXPlatformNodeBase* cell = obj->GetTableCell(row, column)) {
       DCHECK(cell->GetTableColumnSpan().has_value());
       return cell->GetTableColumnSpan().value();
@@ -1743,7 +1756,7 @@
 gint GetRowExtentAt(AtkTable* table, gint row, gint column) {
   g_return_val_if_fail(ATK_IS_TABLE(table), 0);
 
-  if (auto* obj = AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(table))) {
+  if (auto* obj = AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(table))) {
     if (const AXPlatformNodeBase* cell = obj->GetTableCell(row, column)) {
       DCHECK(cell->GetTableRowSpan().has_value());
       return cell->GetTableRowSpan().value();
@@ -1756,7 +1769,7 @@
 AtkObject* GetColumnHeader(AtkTable* table, gint column) {
   g_return_val_if_fail(ATK_IS_TABLE(table), nullptr);
 
-  auto* obj = AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(table));
+  auto* obj = AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(table));
   if (!obj)
     return nullptr;
 
@@ -1779,7 +1792,7 @@
 AtkObject* GetRowHeader(AtkTable* table, gint row) {
   g_return_val_if_fail(ATK_IS_TABLE(table), nullptr);
 
-  auto* obj = AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(table));
+  auto* obj = AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(table));
   if (!obj)
     return nullptr;
 
@@ -1802,7 +1815,7 @@
 AtkObject* GetCaption(AtkTable* table) {
   g_return_val_if_fail(ATK_IS_TABLE(table), nullptr);
 
-  if (auto* obj = AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(table))) {
+  if (auto* obj = AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(table))) {
     if (auto* caption = obj->GetTableCaption())
       return caption->GetNativeViewAccessible();
   }
@@ -1813,7 +1826,7 @@
 const gchar* GetColumnDescription(AtkTable* table, gint column) {
   g_return_val_if_fail(ATK_IS_TABLE(table), nullptr);
 
-  auto* obj = AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(table));
+  auto* obj = AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(table));
   if (!obj)
     return nullptr;
 
@@ -1824,7 +1837,7 @@
 const gchar* GetRowDescription(AtkTable* table, gint row) {
   g_return_val_if_fail(ATK_IS_TABLE(table), nullptr);
 
-  auto* obj = AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(table));
+  auto* obj = AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(table));
   if (!obj)
     return nullptr;
 
@@ -1864,7 +1877,7 @@
       G_TYPE_CHECK_INSTANCE_TYPE((cell), AtkTableCellInterface::GetType()), 0);
 
   if (const AXPlatformNodeBase* obj =
-          AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(cell))) {
+          AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(cell))) {
     // If the object is not a cell, we return 0.
     return obj->GetTableColumnSpan().value_or(0);
   }
@@ -1880,7 +1893,7 @@
 
   GPtrArray* array = g_ptr_array_new_with_free_func(g_object_unref);
 
-  auto* obj = AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(cell));
+  auto* obj = AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(cell));
   if (!obj)
     return array;
 
@@ -1915,7 +1928,7 @@
       G_TYPE_CHECK_INSTANCE_TYPE((cell), AtkTableCellInterface::GetType()),
       FALSE);
 
-  if (auto* obj = AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(cell))) {
+  if (auto* obj = AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(cell))) {
     base::Optional<int> row_index = obj->GetTableRow();
     base::Optional<int> col_index = obj->GetTableColumn();
     if (!row_index || !col_index)
@@ -1934,7 +1947,7 @@
   g_return_val_if_fail(
       G_TYPE_CHECK_INSTANCE_TYPE((cell), AtkTableCellInterface::GetType()), 0);
 
-  if (auto* obj = AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(cell))) {
+  if (auto* obj = AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(cell))) {
     // If the object is not a cell, we return 0.
     return obj->GetTableRowSpan().value_or(0);
   }
@@ -1950,7 +1963,7 @@
 
   GPtrArray* array = g_ptr_array_new_with_free_func(g_object_unref);
 
-  auto* obj = AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(cell));
+  auto* obj = AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(cell));
   if (!obj)
     return array;
 
@@ -1985,7 +1998,7 @@
       G_TYPE_CHECK_INSTANCE_TYPE((cell), AtkTableCellInterface::GetType()),
       nullptr);
 
-  if (auto* obj = AtkObjectToAXPlatformNodeAuraLinux(ATK_OBJECT(cell))) {
+  if (auto* obj = AXPlatformNodeAuraLinux::FromAtkObject(ATK_OBJECT(cell))) {
     if (auto* table = obj->GetTable())
       return table->GetNativeViewAccessible();
   }
@@ -2018,7 +2031,8 @@
 const gchar* GetName(AtkObject* atk_object) {
   g_return_val_if_fail(ATK_IS_OBJECT(atk_object), nullptr);
 
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return nullptr;
 
@@ -2042,7 +2056,8 @@
 const gchar* GetDescription(AtkObject* atk_object) {
   g_return_val_if_fail(ATK_IS_OBJECT(atk_object), nullptr);
 
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return nullptr;
 
@@ -2058,7 +2073,8 @@
 gint GetNChildren(AtkObject* atk_object) {
   g_return_val_if_fail(ATK_IS_OBJECT(atk_object), 0);
 
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return 0;
 
@@ -2073,7 +2089,8 @@
 AtkObject* RefChild(AtkObject* atk_object, gint index) {
   g_return_val_if_fail(ATK_IS_OBJECT(atk_object), nullptr);
 
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return nullptr;
 
@@ -2094,11 +2111,12 @@
 gint GetIndexInParent(AtkObject* atk_object) {
   g_return_val_if_fail(ATK_IS_OBJECT(atk_object), -1);
 
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return -1;
 
-  return obj->GetIndexInParent();
+  return obj->GetIndexInParent().value_or(-1);
 }
 
 gint AtkGetIndexInParent(AtkObject* atk_object) {
@@ -2109,7 +2127,8 @@
 AtkObject* GetParent(AtkObject* atk_object) {
   g_return_val_if_fail(ATK_IS_OBJECT(atk_object), nullptr);
 
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return nullptr;
 
@@ -2124,7 +2143,8 @@
 AtkRelationSet* RefRelationSet(AtkObject* atk_object) {
   g_return_val_if_fail(ATK_IS_OBJECT(atk_object), nullptr);
 
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return atk_relation_set_new();
   return obj->GetAtkRelations();
@@ -2138,7 +2158,8 @@
 AtkAttributeSet* GetAttributes(AtkObject* atk_object) {
   g_return_val_if_fail(ATK_IS_OBJECT(atk_object), nullptr);
 
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return nullptr;
 
@@ -2153,7 +2174,8 @@
 AtkRole GetRole(AtkObject* atk_object) {
   g_return_val_if_fail(ATK_IS_OBJECT(atk_object), ATK_ROLE_INVALID);
 
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj)
     return ATK_ROLE_INVALID;
   return obj->GetAtkRole();
@@ -2171,7 +2193,8 @@
       ATK_OBJECT_CLASS(kAXPlatformNodeAuraLinuxParentClass)
           ->ref_state_set(atk_object);
 
-  AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object);
+  AXPlatformNodeAuraLinux* obj =
+      AXPlatformNodeAuraLinux::FromAtkObject(atk_object);
   if (!obj) {
     atk_state_set_add_state(atk_state_set, ATK_STATE_DEFUNCT);
   } else {
@@ -2429,14 +2452,14 @@
 
   AtkObject* parent_atk_object = GetParent();
   AXPlatformNodeAuraLinux* parent =
-      AtkObjectToAXPlatformNodeAuraLinux(parent_atk_object);
+      AXPlatformNodeAuraLinux::FromAtkObject(parent_atk_object);
   if (!parent)
     return;
 
   if (parent->GetDelegate()->IsWebContent())
     return;
 
-  AXPlatformNodeAuraLinux* frame = AtkObjectToAXPlatformNodeAuraLinux(
+  AXPlatformNodeAuraLinux* frame = AXPlatformNodeAuraLinux::FromAtkObject(
       FindAtkObjectParentFrame(parent_atk_object));
   if (!frame)
     return;
@@ -2449,7 +2472,7 @@
        *child_iterator_ptr != *GetDelegate()->ChildrenEnd();
        ++(*child_iterator_ptr)) {
     AtkObject* child = child_iterator_ptr->GetNativeViewAccessible();
-    auto* child_node = AtkObjectToAXPlatformNodeAuraLinux(child);
+    auto* child_node = AXPlatformNodeAuraLinux::FromAtkObject(child);
     if (!child_node)
       continue;
     if (!child_node->GetDelegate()->IsWebContent())
@@ -2510,7 +2533,7 @@
 // static
 AXPlatformNode* AXPlatformNode::FromNativeViewAccessible(
     gfx::NativeViewAccessible accessible) {
-  return AtkObjectToAXPlatformNodeAuraLinux(accessible);
+  return AXPlatformNodeAuraLinux::FromAtkObject(accessible);
 }
 
 //
@@ -2518,6 +2541,21 @@
 //
 
 // static
+AXPlatformNodeAuraLinux* AXPlatformNodeAuraLinux::FromAtkObject(
+    const AtkObject* atk_object) {
+  if (!atk_object)
+    return nullptr;
+
+  if (IS_AX_PLATFORM_NODE_AURALINUX(atk_object)) {
+    AXPlatformNodeAuraLinuxObject* platform_object =
+        AX_PLATFORM_NODE_AURALINUX(atk_object);
+    return platform_object->m_object;
+  }
+
+  return nullptr;
+}
+
+// static
 void AXPlatformNodeAuraLinux::SetApplication(AXPlatformNode* application) {
   g_root_application = application;
 }
@@ -3116,8 +3154,7 @@
     }
   }
 
-  if (auto* document_parent =
-          AtkObjectToAXPlatformNodeAuraLinux(document_parent_)) {
+  if (auto* document_parent = FromAtkObject(document_parent_)) {
     AtkObject* document = document_parent->FindFirstWebContentDocument();
     if (document) {
       atk_relation_set_add_relation_by_type(relation_set, ATK_RELATION_EMBEDS,
@@ -3236,7 +3273,7 @@
   // as a result of selection, a focus event will be emitted. We don't want to
   // emit duplicate notifications.
   {
-    auto* node = AtkObjectToAXPlatformNodeAuraLinux(descendant);
+    auto* node = FromAtkObject(descendant);
     if (node && node->SelectionAndFocusAreTheSame())
       return;
   }
@@ -3361,7 +3398,7 @@
 }
 
 void AXPlatformNodeAuraLinux::ResendFocusSignalsForCurrentlyFocusedNode() {
-  auto* frame = AtkObjectToAXPlatformNodeAuraLinux(g_active_top_level_frame);
+  auto* frame = FromAtkObject(g_active_top_level_frame);
   if (!frame)
     return;
 
@@ -3550,8 +3587,7 @@
   //
   // If the selection is changing on a collapsed select element, focus remains
   // on the select element and not the newly-selected descendant.
-  if (AXPlatformNodeBase* parent =
-          AtkObjectToAXPlatformNodeAuraLinux(GetParent())) {
+  if (AXPlatformNodeBase* parent = FromAtkObject(GetParent())) {
     if (parent->GetData().role == ax::mojom::Role::kMenuListPopup)
       return !parent->GetData().HasState(ax::mojom::State::kInvisible);
   }
@@ -3602,7 +3638,7 @@
     return *this;
   if (GetData().GetBoolAttribute(ax::mojom::BoolAttribute::kEditableRoot))
     return *this;
-  if (auto* parent = AtkObjectToAXPlatformNodeAuraLinux(GetParent()))
+  if (auto* parent = FromAtkObject(GetParent()))
     return parent->FindEditableRootOrDocument();
   return *this;
 }
@@ -3611,7 +3647,7 @@
     AXPlatformNodeAuraLinux* other) {
   if (this == other || other->IsDescendantOf(this))
     return this;
-  if (auto* parent = AtkObjectToAXPlatformNodeAuraLinux(GetParent()))
+  if (auto* parent = FromAtkObject(GetParent()))
     return parent->FindCommonAncestor(other);
   return nullptr;
 }
@@ -3627,7 +3663,7 @@
 
 void AXPlatformNodeAuraLinux::EmitSelectionChangedSignal(bool had_selection) {
   if (!EmitsAtkTextEvents()) {
-    if (auto* parent = AtkObjectToAXPlatformNodeAuraLinux(GetParent()))
+    if (auto* parent = FromAtkObject(GetParent()))
       parent->EmitSelectionChangedSignal(had_selection);
     return;
   }
@@ -3646,7 +3682,7 @@
 
 void AXPlatformNodeAuraLinux::EmitCaretChangedSignal() {
   if (!EmitsAtkTextEvents()) {
-    if (auto* parent = AtkObjectToAXPlatformNodeAuraLinux(GetParent()))
+    if (auto* parent = FromAtkObject(GetParent()))
       parent->EmitCaretChangedSignal();
     return;
   }
@@ -3770,8 +3806,7 @@
     return;
 
   // We always want to notify on the top frame.
-  AXPlatformNodeAuraLinux* window =
-      AtkObjectToAXPlatformNodeAuraLinux(g_active_top_level_frame);
+  AXPlatformNodeAuraLinux* window = FromAtkObject(g_active_top_level_frame);
   if (window)
     window->OnNameChanged();
 }
@@ -3787,7 +3822,7 @@
     return;
 
   g_signal_emit_by_name(GetParent(), "children-changed::add",
-                        GetIndexInParent(), atk_object);
+                        GetIndexInParent().value_or(-1), atk_object);
 }
 
 void AXPlatformNodeAuraLinux::OnSubtreeWillBeDeleted() {
@@ -3801,7 +3836,7 @@
     return;
 
   g_signal_emit_by_name(GetParent(), "children-changed::remove",
-                        GetIndexInParent(), atk_object);
+                        GetIndexInParent().value_or(-1), atk_object);
 }
 
 void AXPlatformNodeAuraLinux::OnParentChanged() {
@@ -3939,7 +3974,7 @@
 
 base::Optional<std::pair<int, int>>
 AXPlatformNodeAuraLinux::GetEmbeddedObjectIndices() {
-  auto* parent = AtkObjectToAXPlatformNodeAuraLinux(GetParent());
+  auto* parent = FromAtkObject(GetParent());
   if (!parent)
     return base::nullopt;
   return parent->GetEmbeddedObjectIndicesForId(GetUniqueId());
@@ -4170,7 +4205,7 @@
     return true;
   }
 
-  auto* parent = AtkObjectToAXPlatformNodeAuraLinux(GetParent());
+  auto* parent = FromAtkObject(GetParent());
   if (!parent)
     return false;
 
@@ -4180,8 +4215,7 @@
   for (auto child_iterator_ptr = parent->GetDelegate()->ChildrenBegin();
        *child_iterator_ptr != *parent->GetDelegate()->ChildrenEnd();
        ++(*child_iterator_ptr)) {
-    auto* child = AtkObjectToAXPlatformNodeAuraLinux(
-        child_iterator_ptr->GetNativeViewAccessible());
+    auto* child = FromAtkObject(child_iterator_ptr->GetNativeViewAccessible());
     if (!child || child == this)
       continue;
 
@@ -4223,8 +4257,7 @@
   // building the hypertext here.
   int current_offset = 0;
   for (int i = 0; i < child_count; ++i) {
-    auto* child =
-        AtkObjectToAXPlatformNodeAuraLinux(delegate_->ChildAtIndex(i));
+    auto* child = FromAtkObject(delegate_->ChildAtIndex(i));
     if (!child)
       continue;
 
@@ -4747,8 +4780,7 @@
   for (auto child_iterator_ptr = GetDelegate()->ChildrenBegin();
        *child_iterator_ptr != *GetDelegate()->ChildrenEnd();
        ++(*child_iterator_ptr)) {
-    auto* child = AtkObjectToAXPlatformNodeAuraLinux(
-        child_iterator_ptr->GetNativeViewAccessible());
+    auto* child = FromAtkObject(child_iterator_ptr->GetNativeViewAccessible());
     if (!child)
       continue;
 
@@ -4766,7 +4798,7 @@
 
 void AXPlatformNodeAuraLinux::ActivateFindInPageInParent(int start_offset,
                                                          int end_offset) {
-  auto* parent = AtkObjectToAXPlatformNodeAuraLinux(GetParent());
+  auto* parent = FromAtkObject(GetParent());
   if (!parent)
     return;
 
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.h b/ui/accessibility/platform/ax_platform_node_auralinux.h
index e8d1212f..f779f38 100644
--- a/ui/accessibility/platform/ax_platform_node_auralinux.h
+++ b/ui/accessibility/platform/ax_platform_node_auralinux.h
@@ -121,6 +121,8 @@
   AXPlatformNodeAuraLinux();
   ~AXPlatformNodeAuraLinux() override;
 
+  static AXPlatformNodeAuraLinux* FromAtkObject(const AtkObject*);
+
   // Set or get the root-level Application object that's the parent of all
   // top-level windows.
   static void SetApplication(AXPlatformNode* application);
diff --git a/ui/accessibility/platform/ax_platform_node_base.cc b/ui/accessibility/platform/ax_platform_node_base.cc
index ebff0e2..5fdc6e8 100644
--- a/ui/accessibility/platform/ax_platform_node_base.cc
+++ b/ui/accessibility/platform/ax_platform_node_base.cc
@@ -149,15 +149,16 @@
   return base::UTF8ToUTF16(name);
 }
 
-int AXPlatformNodeBase::GetIndexInParent() {
+base::Optional<int> AXPlatformNodeBase::GetIndexInParent() {
   AXPlatformNodeBase* parent = FromNativeViewAccessible(GetParent());
   if (!parent)
-    return 0;
+    return base::nullopt;
 
   int child_count = parent->GetChildCount();
   if (child_count == 0) {
-    // |child_count| could be 0 if the node is PlatformIsLeaf.
-    return 0;
+    // |child_count| could be 0 if the parent is IsLeaf.
+    DCHECK(parent->IsLeaf());
+    return base::nullopt;
   }
 
   // Ask the delegate for the index in parent, and return it if it's plausible.
@@ -176,7 +177,9 @@
     if (parent->ChildAtIndex(i) == current)
       return i;
   }
-  return -1;
+  NOTREACHED()
+      << "Unable to find the child in the list of its parent's children.";
+  return base::nullopt;
 }
 
 // AXPlatformNode overrides.
@@ -1429,12 +1432,8 @@
   // cross-tree traversal is necessary.
   if (child->IsTextOnlyObject()) {
     int32_t hypertext_offset = 0;
-    int32_t index_in_parent = child->GetIndexInParent();
-    DCHECK_GE(index_in_parent, 0);
-    DCHECK_LT(index_in_parent, static_cast<int32_t>(GetChildCount()));
-    for (uint32_t i = 0; i < static_cast<uint32_t>(index_in_parent); ++i) {
-      auto* sibling = static_cast<AXPlatformNodeBase*>(
-          FromNativeViewAccessible(ChildAtIndex(i)));
+    for (AXPlatformNodeBase* sibling = GetFirstChild(); sibling != child;
+         sibling = sibling->GetNextSibling()) {
       DCHECK(sibling);
       if (sibling->IsTextOnlyObject()) {
         hypertext_offset += (int32_t)sibling->GetHypertext().size();
@@ -1510,7 +1509,7 @@
   }
 
   AXPlatformNodeBase* common_parent = this;
-  int32_t index_in_common_parent = GetIndexInParent();
+  base::Optional<int> index_in_common_parent = GetIndexInParent();
   while (common_parent && !endpoint_object->IsDescendantOf(common_parent)) {
     index_in_common_parent = common_parent->GetIndexInParent();
     common_parent = static_cast<AXPlatformNodeBase*>(
@@ -1519,7 +1518,6 @@
   if (!common_parent)
     return -1;
 
-  DCHECK_GE(index_in_common_parent, 0);
   DCHECK(!(common_parent->IsTextOnlyObject()));
 
   // Case 2. Is the selection endpoint inside a descendant of this object?
@@ -1547,17 +1545,14 @@
   //
   // We can safely assume that the endpoint is in another part of the tree or
   // at common parent, and that this object is a descendant of common parent.
-  int32_t endpoint_index_in_common_parent = -1;
-  for (int i = 0; i < common_parent->GetDelegate()->GetChildCount(); ++i) {
-    auto* child = static_cast<AXPlatformNodeBase*>(FromNativeViewAccessible(
-        common_parent->GetDelegate()->ChildAtIndex(i)));
-    DCHECK(child);
+  base::Optional<int> endpoint_index_in_common_parent;
+  for (AXPlatformNodeBase* child = common_parent->GetFirstChild();
+       child != nullptr; child = child->GetNextSibling()) {
     if (endpoint_object->IsDescendantOf(child)) {
       endpoint_index_in_common_parent = child->GetIndexInParent();
       break;
     }
   }
-  DCHECK_GE(endpoint_index_in_common_parent, 0);
 
   if (endpoint_index_in_common_parent < index_in_common_parent)
     return 0;
diff --git a/ui/accessibility/platform/ax_platform_node_base.h b/ui/accessibility/platform/ax_platform_node_base.h
index b46cf48..4901fab 100644
--- a/ui/accessibility/platform/ax_platform_node_base.h
+++ b/ui/accessibility/platform/ax_platform_node_base.h
@@ -69,8 +69,9 @@
   std::string GetName() const;
   base::string16 GetNameAsString16() const;
 
-  // This returns 0 if there's no parent.
-  virtual int GetIndexInParent();
+  // This returns nullopt if there's no parent, it's unable to find the child in
+  // the list of its parent's children, or its parent doesn't have children.
+  virtual base::Optional<int> GetIndexInParent();
 
   // AXPlatformNode.
   void Destroy() override;
diff --git a/ui/accessibility/platform/ax_platform_node_mac.h b/ui/accessibility/platform/ax_platform_node_mac.h
index a5624cb7..920f0a0 100644
--- a/ui/accessibility/platform/ax_platform_node_mac.h
+++ b/ui/accessibility/platform/ax_platform_node_mac.h
@@ -27,7 +27,6 @@
 
   // AXPlatformNodeBase.
   void Destroy() override;
-  int GetIndexInParent() override;
 
  protected:
   void AddAttributeToList(const char* name,
diff --git a/ui/accessibility/platform/ax_platform_node_mac.mm b/ui/accessibility/platform/ax_platform_node_mac.mm
index 04541643..bd9e17f 100644
--- a/ui/accessibility/platform/ax_platform_node_mac.mm
+++ b/ui/accessibility/platform/ax_platform_node_mac.mm
@@ -1257,11 +1257,6 @@
                                [native_node_ AXWindow], false);
 }
 
-int AXPlatformNodeMac::GetIndexInParent() {
-  // TODO(dmazzoni): implement this.  http://crbug.com/396137
-  return -1;
-}
-
 bool IsNameExposedInAXValueForRole(ax::mojom::Role role) {
   switch (role) {
     case ax::mojom::Role::kListBoxOption:
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index eadcb74..25b630b 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -1370,10 +1370,11 @@
 IFACEMETHODIMP AXPlatformNodeWin::get_indexInParent(LONG* index_in_parent) {
   WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_INDEX_IN_PARENT);
   COM_OBJECT_VALIDATE_1_ARG(index_in_parent);
-  *index_in_parent = GetIndexInParent();
-  if (*index_in_parent < 0)
+  base::Optional<int> index = GetIndexInParent();
+  if (!index.has_value())
     return E_FAIL;
 
+  *index_in_parent = index.value();
   return S_OK;
 }
 
diff --git a/ui/accessibility/platform/ax_platform_node_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_win_unittest.cc
index 4a1df77..b635131b 100644
--- a/ui/accessibility/platform/ax_platform_node_win_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_win_unittest.cc
@@ -1149,8 +1149,7 @@
   ComPtr<IAccessible2> right_iaccessible2 = ToIAccessible2(right_iaccessible);
 
   LONG index;
-  EXPECT_EQ(S_OK, root_iaccessible2->get_indexInParent(&index));
-  EXPECT_EQ(0, index);
+  EXPECT_EQ(E_FAIL, root_iaccessible2->get_indexInParent(&index));
 
   EXPECT_EQ(S_OK, left_iaccessible2->get_indexInParent(&index));
   EXPECT_EQ(0, index);
diff --git a/ui/file_manager/file_manager/foreground/js/ui/breadcrumb.js b/ui/file_manager/file_manager/foreground/js/ui/breadcrumb.js
index 5c51f08..71c4c40f 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/breadcrumb.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/breadcrumb.js
@@ -289,6 +289,7 @@
 
     elider.hidden = parts.length <= 4;
     if (elider.hidden) {
+      this.shadowRoot.querySelector('cr-action-menu').innerHTML = '';
       elider.previousElementSibling.hidden = true;
       return;
     }
diff --git a/ui/file_manager/integration_tests/file_manager/toolbar.js b/ui/file_manager/integration_tests/file_manager/toolbar.js
index bd218325..963883a3 100644
--- a/ui/file_manager/integration_tests/file_manager/toolbar.js
+++ b/ui/file_manager/integration_tests/file_manager/toolbar.js
@@ -25,6 +25,34 @@
 };
 
 /**
+ * Tests Delete button keeps focus after closing confirmation
+ * dialog.
+ */
+testcase.toolbarDeleteButtonKeepFocus = async () => {
+  const entries = [ENTRIES.desktop];
+
+  // Open Files app.
+  const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS, entries, []);
+
+  // Select My Desktop Background.png
+  chrome.test.assertTrue(await remoteCall.callRemoteTestUtil(
+      'selectFile', appId, [ENTRIES.desktop.nameText]));
+
+  await remoteCall.simulateUiClick(appId, '#delete-button');
+
+  // Confirm that the confirmation dialog is shown.
+  await remoteCall.waitForElement(appId, '.cr-dialog-container.shown');
+
+  // Press cancel button.
+  await remoteCall.waitAndClickElement(appId, 'button.cr-dialog-cancel');
+
+  // Check focused element is Delete button.
+  const focusedElement =
+      await remoteCall.callRemoteTestUtil('getActiveElement', appId, []);
+  chrome.test.assertEq('delete-button', focusedElement.attributes['id']);
+};
+
+/**
  * Tests deleting an entry using the toolbar.
  */
 testcase.toolbarDeleteEntry = async () => {
diff --git a/ui/gl/BUILD.gn b/ui/gl/BUILD.gn
index 2c9aba9..9a56945 100644
--- a/ui/gl/BUILD.gn
+++ b/ui/gl/BUILD.gn
@@ -255,7 +255,7 @@
     ]
   }
 
-  if (use_x11) {
+  if (use_x11 || ozone_platform_x11) {
     sources += [
       "gl_surface_egl_x11.cc",
       "gl_surface_egl_x11.h",
@@ -604,6 +604,7 @@
 
   data_deps = [ "//third_party/mesa_headers" ]
 
+  # TODO(https://crbug.com/789065): this must be moved to Ozone.
   if (use_x11) {
     sources += [ "gl_context_glx_unittest.cc" ]
     deps += [ "//ui/gfx/x" ]
diff --git a/ui/gl/gl_surface_egl_x11.cc b/ui/gl/gl_surface_egl_x11.cc
index fbb53bf..33bee7bf 100644
--- a/ui/gl/gl_surface_egl_x11.cc
+++ b/ui/gl/gl_surface_egl_x11.cc
@@ -54,7 +54,7 @@
   // Query all child windows and store them. ANGLE creates a child window when
   // eglCreateWidnowSurface is called on X11 and expose events from this window
   // need to be received by this class.
-  Display* x11_display = GetNativeDisplay();
+  Display* x11_display = GetXNativeDisplay();
   Window root = 0;
   Window parent = 0;
   Window* children = nullptr;
@@ -92,8 +92,8 @@
   // views::DesktopWindowTreeHostX11::InitX11Window back to None for the
   // XWindow associated to this surface after the first SwapBuffers has
   // happened, to avoid showing a weird white background while resizing.
-  if (GetNativeDisplay() && !has_swapped_buffers_) {
-    XSetWindowBackgroundPixmap(GetNativeDisplay(), window_, 0);
+  if (GetXNativeDisplay() && !has_swapped_buffers_) {
+    XSetWindowBackgroundPixmap(GetXNativeDisplay(), window_, 0);
     has_swapped_buffers_ = true;
   }
   return result;
@@ -103,9 +103,13 @@
   Destroy();
 }
 
+Display* NativeViewGLSurfaceEGLX11::GetXNativeDisplay() const {
+  return reinterpret_cast<Display*>(GetNativeDisplay());
+}
+
 std::unique_ptr<gfx::VSyncProvider>
 NativeViewGLSurfaceEGLX11::CreateVsyncProviderInternal() {
-  return std::make_unique<XrandrIntervalOnlyVSyncProvider>(GetNativeDisplay());
+  return std::make_unique<XrandrIntervalOnlyVSyncProvider>(GetXNativeDisplay());
 }
 
 bool NativeViewGLSurfaceEGLX11::DispatchXEvent(XEvent* x_event) {
@@ -119,7 +123,7 @@
     return false;
 
   x_event->xexpose.window = window_;
-  Display* x11_display = GetNativeDisplay();
+  Display* x11_display = GetXNativeDisplay();
   XSendEvent(x11_display, window_, x11::False, ExposureMask, x_event);
   XFlush(x11_display);
   return true;
diff --git a/ui/gl/gl_surface_egl_x11.h b/ui/gl/gl_surface_egl_x11.h
index 925b35c..e951677 100644
--- a/ui/gl/gl_surface_egl_x11.h
+++ b/ui/gl/gl_surface_egl_x11.h
@@ -33,6 +33,8 @@
  protected:
   ~NativeViewGLSurfaceEGLX11() override;
 
+  Display* GetXNativeDisplay() const;
+
  private:
   // NativeViewGLSurfaceEGL overrides:
   std::unique_ptr<gfx::VSyncProvider> CreateVsyncProviderInternal() override;
diff --git a/ui/gl/gl_surface_egl_x11_gles2.cc b/ui/gl/gl_surface_egl_x11_gles2.cc
index c68a18f..13b67b5 100644
--- a/ui/gl/gl_surface_egl_x11_gles2.cc
+++ b/ui/gl/gl_surface_egl_x11_gles2.cc
@@ -17,7 +17,7 @@
     : NativeViewGLSurfaceEGLX11(0), parent_window_(window) {}
 
 bool NativeViewGLSurfaceEGLX11GLES2::InitializeNativeWindow() {
-  Display* x11_display = GetNativeDisplay();
+  Display* x11_display = GetXNativeDisplay();
   XWindowAttributes attributes;
   if (!XGetWindowAttributes(x11_display, parent_window_, &attributes)) {
     LOG(ERROR) << "XGetWindowAttributes failed for window " << parent_window_
@@ -49,7 +49,7 @@
   NativeViewGLSurfaceEGLX11::Destroy();
 
   if (window_) {
-    Display* x11_display = GetNativeDisplay();
+    Display* x11_display = GetXNativeDisplay();
     XDestroyWindow(x11_display, window_);
     window_ = 0;
     XFlush(x11_display);
@@ -61,7 +61,7 @@
     // Get a config compatible with the window
     DCHECK(window_);
     XWindowAttributes win_attribs;
-    if (!XGetWindowAttributes(GetNativeDisplay(), window_, &win_attribs)) {
+    if (!XGetWindowAttributes(GetXNativeDisplay(), window_, &win_attribs)) {
       return nullptr;
     }
 
@@ -130,18 +130,19 @@
   size_ = size;
 
   eglWaitGL();
-  XResizeWindow(GetNativeDisplay(), window_, size.width(), size.height());
+  XResizeWindow(GetXNativeDisplay(), window_, size.width(), size.height());
   eglWaitNative(EGL_CORE_NATIVE_ENGINE);
 
   return true;
 }
 
 bool NativeViewGLSurfaceEGLX11GLES2::DispatchXEvent(XEvent* xev) {
-  if (xev->type != Expose || xev->xexpose.window != window_)
+  if (xev->type != Expose ||
+      xev->xexpose.window != static_cast<Window>(window_))
     return false;
 
   xev->xexpose.window = parent_window_;
-  Display* x11_display = GetNativeDisplay();
+  Display* x11_display = GetXNativeDisplay();
   XSendEvent(x11_display, parent_window_, x11::False, ExposureMask, xev);
   XFlush(x11_display);
   return true;
diff --git a/ui/gl/gl_surface_egl_x11_gles2.h b/ui/gl/gl_surface_egl_x11_gles2.h
index 7039b34d..ac4f26c 100644
--- a/ui/gl/gl_surface_egl_x11_gles2.h
+++ b/ui/gl/gl_surface_egl_x11_gles2.h
@@ -30,9 +30,10 @@
               bool has_alpha) override;
   bool InitializeNativeWindow() override;
 
- private:
+ protected:
   ~NativeViewGLSurfaceEGLX11GLES2() override;
 
+ private:
   // XEventDispatcher:
   bool DispatchXEvent(XEvent* xev) override;
 
diff --git a/ui/message_center/views/notification_control_buttons_view.cc b/ui/message_center/views/notification_control_buttons_view.cc
index 1e4a726..8899c5e 100644
--- a/ui/message_center/views/notification_control_buttons_view.cc
+++ b/ui/message_center/views/notification_control_buttons_view.cc
@@ -28,8 +28,11 @@
     MessageView* message_view)
     : message_view_(message_view), icon_color_(gfx::kChromeIconGrey) {
   DCHECK(message_view);
-  SetLayoutManager(std::make_unique<views::BoxLayout>(
+  auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
       views::BoxLayout::Orientation::kHorizontal));
+  // Do not stretch buttons as that would stretch their focus indicator.
+  layout->set_cross_axis_alignment(
+      views::BoxLayout::CrossAxisAlignment::kStart);
 
   // Use layer to change the opacity.
   SetPaintToLayer();
diff --git a/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.cc b/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.cc
index 5d2a047..db78bcd 100644
--- a/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.cc
+++ b/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.cc
@@ -34,9 +34,13 @@
 
 WaylandBufferManagerConnector::WaylandBufferManagerConnector(
     WaylandBufferManagerHost* buffer_manager_host)
-    : buffer_manager_host_(buffer_manager_host) {}
+    : buffer_manager_host_(buffer_manager_host) {
+  DETACH_FROM_THREAD(io_thread_checker_);
+}
 
-WaylandBufferManagerConnector::~WaylandBufferManagerConnector() = default;
+WaylandBufferManagerConnector::~WaylandBufferManagerConnector() {
+  DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_);
+}
 
 void WaylandBufferManagerConnector::OnGpuProcessLaunched(
     int host_id,
@@ -45,7 +49,9 @@
     base::RepeatingCallback<void(IPC::Message*)> send_callback) {}
 
 void WaylandBufferManagerConnector::OnChannelDestroyed(int host_id) {
-  buffer_manager_host_->OnChannelDestroyed();
+  DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_);
+  if (host_id_ == host_id)
+    buffer_manager_host_->OnChannelDestroyed();
 }
 
 void WaylandBufferManagerConnector::OnMessageReceived(
@@ -60,27 +66,45 @@
     scoped_refptr<base::SingleThreadTaskRunner> io_runner,
     GpuHostBindInterfaceCallback binder,
     GpuHostTerminateCallback terminate_callback) {
-  terminate_callback_ = std::move(terminate_callback);
-  binder_ = std::move(binder);
+  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
 
+  binder_ = std::move(binder);
   io_runner_ = io_runner;
+
+  ui_runner->PostTask(
+      FROM_HERE,
+      base::BindOnce(&WaylandBufferManagerConnector::OnGpuServiceLaunchedOnUI,
+                     base::Unretained(this), host_id,
+                     std::move(terminate_callback)));
+}
+
+void WaylandBufferManagerConnector::OnGpuServiceLaunchedOnUI(
+    int host_id,
+    GpuHostTerminateCallback terminate_callback) {
+  DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_);
+
+  host_id_ = host_id;
+
   auto on_terminate_gpu_cb =
       base::BindOnce(&WaylandBufferManagerConnector::OnTerminateGpuProcess,
                      base::Unretained(this));
   buffer_manager_host_->SetTerminateGpuCallback(std::move(on_terminate_gpu_cb));
+  terminate_callback_ = std::move(terminate_callback);
 
-  base::PostTaskAndReplyWithResult(
-      ui_runner.get(), FROM_HERE,
-      base::BindOnce(&WaylandBufferManagerHost::BindInterface,
-                     base::Unretained(buffer_manager_host_)),
+  auto pending_remote = buffer_manager_host_->BindInterface();
+
+  io_runner_->PostTask(
+      FROM_HERE,
       base::BindOnce(
           &WaylandBufferManagerConnector::OnBufferManagerHostPtrBinded,
-          base::Unretained(this)));
+          base::Unretained(this), std::move(pending_remote)));
 }
 
 void WaylandBufferManagerConnector::OnBufferManagerHostPtrBinded(
     mojo::PendingRemote<ozone::mojom::WaylandBufferManagerHost>
         buffer_manager_host) const {
+  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
+
   mojo::Remote<ozone::mojom::WaylandBufferManagerGpu> buffer_manager_gpu_remote;
   auto receiver = buffer_manager_gpu_remote.BindNewPipeAndPassReceiver();
   BindInterfaceInGpuProcess(std::move(receiver), binder_);
@@ -98,6 +122,9 @@
 }
 
 void WaylandBufferManagerConnector::OnTerminateGpuProcess(std::string message) {
+  DCHECK_CALLED_ON_VALID_THREAD(ui_thread_checker_);
+
+  DCHECK(!terminate_callback_.is_null());
   io_runner_->PostTask(FROM_HERE, base::BindOnce(std::move(terminate_callback_),
                                                  std::move(message)));
 }
diff --git a/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.h b/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.h
index 24db6b7..c7f2108 100644
--- a/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.h
+++ b/ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.h
@@ -7,6 +7,7 @@
 
 #include "ui/ozone/public/gpu_platform_support_host.h"
 
+#include "base/threading/thread_checker.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "ui/ozone/public/mojom/wayland/wayland_buffer_manager.mojom.h"
 
@@ -39,6 +40,9 @@
       GpuHostTerminateCallback terminate_callback) override;
 
  private:
+  void OnGpuServiceLaunchedOnUI(int host_id,
+                                GpuHostTerminateCallback terminate_callback);
+
   void OnBufferManagerHostPtrBinded(
       mojo::PendingRemote<ozone::mojom::WaylandBufferManagerHost>
           buffer_manager_host) const;
@@ -54,6 +58,12 @@
 
   scoped_refptr<base::SingleThreadTaskRunner> io_runner_;
 
+  // Owned by the ui thread.
+  int host_id_ = -1;
+
+  THREAD_CHECKER(ui_thread_checker_);
+  THREAD_CHECKER(io_thread_checker_);
+
   DISALLOW_COPY_AND_ASSIGN(WaylandBufferManagerConnector);
 };
 
diff --git a/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc b/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc
index 79495b21..96c4099 100644
--- a/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc
+++ b/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc
@@ -639,7 +639,10 @@
 
 mojo::PendingRemote<ozone::mojom::WaylandBufferManagerHost>
 WaylandBufferManagerHost::BindInterface() {
-  DCHECK(!receiver_.is_bound());
+  // Allow to rebind the interface if it hasn't been destroyed yet.
+  if (receiver_.is_bound())
+    OnChannelDestroyed();
+
   mojo::PendingRemote<ozone::mojom::WaylandBufferManagerHost>
       buffer_manager_host;
   receiver_.Bind(buffer_manager_host.InitWithNewPipeAndPassReceiver());
diff --git a/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h b/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h
index 9049a3f..c0c6809c 100644
--- a/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h
+++ b/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h
@@ -85,7 +85,9 @@
   void SetTerminateGpuCallback(
       base::OnceCallback<void(std::string)> terminate_gpu_cb);
 
-  // Returns bound pointer to own mojo interface.
+  // Returns bound pointer to own mojo interface. If there were previous
+  // interface bindings, it will be unbound and the state of the
+  // |buffer_manager_| will be cleared.
   mojo::PendingRemote<ozone::mojom::WaylandBufferManagerHost> BindInterface();
 
   // Unbinds the interface and clears the state of the |buffer_manager_|. Used
diff --git a/ui/ozone/platform/x11/BUILD.gn b/ui/ozone/platform/x11/BUILD.gn
index 10b7bdb..de0a06e 100644
--- a/ui/ozone/platform/x11/BUILD.gn
+++ b/ui/ozone/platform/x11/BUILD.gn
@@ -16,12 +16,8 @@
     "gl_egl_utility_x11.h",
     "gl_ozone_glx.cc",
     "gl_ozone_glx.h",
-    "gl_surface_egl_ozone_x11.cc",
-    "gl_surface_egl_ozone_x11.h",
     "gl_surface_egl_readback_x11.cc",
     "gl_surface_egl_readback_x11.h",
-    "gl_surface_glx_ozone.cc",
-    "gl_surface_glx_ozone.h",
     "ozone_platform_x11.cc",
     "ozone_platform_x11.h",
     "x11_canvas_surface.cc",
diff --git a/ui/ozone/platform/x11/gl_ozone_glx.cc b/ui/ozone/platform/x11/gl_ozone_glx.cc
index 520c5223..5a6a63e 100644
--- a/ui/ozone/platform/x11/gl_ozone_glx.cc
+++ b/ui/ozone/platform/x11/gl_ozone_glx.cc
@@ -9,7 +9,7 @@
 #include "ui/gl/gl_context_glx.h"
 #include "ui/gl/gl_gl_api_implementation.h"
 #include "ui/gl/gl_glx_api_implementation.h"
-#include "ui/ozone/platform/x11/gl_surface_glx_ozone.h"
+#include "ui/gl/gl_surface_glx_x11.h"
 
 namespace ui {
 
@@ -97,7 +97,7 @@
 
 scoped_refptr<gl::GLSurface> GLOzoneGLX::CreateViewGLSurface(
     gfx::AcceleratedWidget window) {
-  return gl::InitializeGLSurface(new GLSurfaceGLXOzone(window));
+  return gl::InitializeGLSurface(new gl::GLSurfaceGLXX11(window));
 }
 
 scoped_refptr<gl::GLSurface> GLOzoneGLX::CreateSurfacelessViewGLSurface(
diff --git a/ui/ozone/platform/x11/gl_surface_egl_ozone_x11.cc b/ui/ozone/platform/x11/gl_surface_egl_ozone_x11.cc
deleted file mode 100644
index 71d50ff..0000000
--- a/ui/ozone/platform/x11/gl_surface_egl_ozone_x11.cc
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/ozone/platform/x11/gl_surface_egl_ozone_x11.h"
-
-#include "ui/gfx/x/x11.h"
-#include "ui/gfx/x/x11_types.h"
-#include "ui/gl/egl_util.h"
-
-namespace ui {
-
-GLSurfaceEGLOzoneX11::GLSurfaceEGLOzoneX11(EGLNativeWindowType window)
-    : NativeViewGLSurfaceEGL(window, nullptr) {}
-
-EGLConfig GLSurfaceEGLOzoneX11::GetConfig() {
-  // Try matching the window depth with an alpha channel, because we're worried
-  // the destination alpha width could constrain blending precision.
-  const int kBufferSizeOffset = 1;
-  const int kAlphaSizeOffset = 3;
-  EGLint config_attribs[] = {EGL_BUFFER_SIZE,
-                             ~0,  // To be replaced.
-                             EGL_ALPHA_SIZE,
-                             8,
-                             EGL_BLUE_SIZE,
-                             8,
-                             EGL_GREEN_SIZE,
-                             8,
-                             EGL_RED_SIZE,
-                             8,
-                             EGL_RENDERABLE_TYPE,
-                             EGL_OPENGL_ES2_BIT,
-                             EGL_SURFACE_TYPE,
-                             EGL_WINDOW_BIT,
-                             EGL_NONE};
-
-  // Get the depth of XWindow for surface.
-  XWindowAttributes win_attribs;
-  if (XGetWindowAttributes(gfx::GetXDisplay(), window_, &win_attribs)) {
-    config_attribs[kBufferSizeOffset] = win_attribs.depth;
-  }
-
-  EGLDisplay display = GetDisplay();
-
-  EGLConfig config;
-  EGLint num_configs;
-  if (!eglChooseConfig(display, config_attribs, &config, 1, &num_configs)) {
-    LOG(ERROR) << "eglChooseConfig failed with error "
-               << GetLastEGLErrorString();
-    return nullptr;
-  }
-
-  if (num_configs > 0) {
-    EGLint config_depth;
-    if (!eglGetConfigAttrib(display, config, EGL_BUFFER_SIZE, &config_depth)) {
-      LOG(ERROR) << "eglGetConfigAttrib failed with error "
-                 << GetLastEGLErrorString();
-      return nullptr;
-    }
-    if (config_depth == config_attribs[kBufferSizeOffset]) {
-      return config;
-    }
-  }
-
-  // Try without an alpha channel.
-  config_attribs[kAlphaSizeOffset] = 0;
-  if (!eglChooseConfig(display, config_attribs, &config, 1, &num_configs)) {
-    LOG(ERROR) << "eglChooseConfig failed with error "
-               << GetLastEGLErrorString();
-    return nullptr;
-  }
-
-  if (num_configs == 0) {
-    LOG(ERROR) << "No suitable EGL configs found.";
-    return nullptr;
-  }
-  return config;
-}
-
-bool GLSurfaceEGLOzoneX11::Resize(const gfx::Size& size,
-                                  float scale_factor,
-                                  const gfx::ColorSpace& color_space,
-                                  bool has_alpha) {
-  if (size == GetSize())
-    return true;
-
-  size_ = size;
-
-  eglWaitGL();
-  XResizeWindow(gfx::GetXDisplay(), window_, size.width(), size.height());
-  eglWaitNative(EGL_CORE_NATIVE_ENGINE);
-
-  return true;
-}
-
-GLSurfaceEGLOzoneX11::~GLSurfaceEGLOzoneX11() {
-  Destroy();
-}
-
-}  // namespace ui
diff --git a/ui/ozone/platform/x11/gl_surface_egl_ozone_x11.h b/ui/ozone/platform/x11/gl_surface_egl_ozone_x11.h
deleted file mode 100644
index eab987a..0000000
--- a/ui/ozone/platform/x11/gl_surface_egl_ozone_x11.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_OZONE_PLATFORM_X11_GL_SURFACE_EGL_OZONE_X11_H_
-#define UI_OZONE_PLATFORM_X11_GL_SURFACE_EGL_OZONE_X11_H_
-
-#include "base/macros.h"
-#include "ui/gfx/geometry/size.h"
-#include "ui/gl/gl_surface_egl.h"
-
-namespace ui {
-
-// GLSurface implementation for Ozone X11 EGL. This does not create a new
-// XWindow or observe XExpose events like GLSurfaceEGLX11 does.
-class GLSurfaceEGLOzoneX11 : public gl::NativeViewGLSurfaceEGL {
- public:
-  explicit GLSurfaceEGLOzoneX11(EGLNativeWindowType window);
-
-  // gl::NativeViewGLSurfaceEGL:
-  EGLConfig GetConfig() override;
-  bool Resize(const gfx::Size& size,
-              float scale_factor,
-              const gfx::ColorSpace& color_space,
-              bool has_alpha) override;
-
- private:
-  ~GLSurfaceEGLOzoneX11() override;
-
-  DISALLOW_COPY_AND_ASSIGN(GLSurfaceEGLOzoneX11);
-};
-
-}  // namespace ui
-
-#endif  // UI_OZONE_PLATFORM_X11_GL_SURFACE_EGL_OZONE_X11_H_
diff --git a/ui/ozone/platform/x11/gl_surface_glx_ozone.cc b/ui/ozone/platform/x11/gl_surface_glx_ozone.cc
deleted file mode 100644
index 172f62af..0000000
--- a/ui/ozone/platform/x11/gl_surface_glx_ozone.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/ozone/platform/x11/gl_surface_glx_ozone.h"
-
-#include "ui/gfx/x/x11.h"
-
-namespace ui {
-
-GLSurfaceGLXOzone::GLSurfaceGLXOzone(gfx::AcceleratedWidget window)
-    : NativeViewGLSurfaceGLX(window) {}
-
-GLSurfaceGLXOzone::~GLSurfaceGLXOzone() {
-  Destroy();
-}
-
-void GLSurfaceGLXOzone::RegisterEvents() {
-  auto* event_source = X11EventSource::GetInstance();
-  // Can be null in tests, when we don't care about Exposes.
-  if (event_source) {
-    XSelectInput(gfx::GetXDisplay(), window(), ExposureMask);
-    event_source->AddXEventDispatcher(this);
-  }
-}
-
-void GLSurfaceGLXOzone::UnregisterEvents() {
-  auto* event_source = X11EventSource::GetInstance();
-  if (event_source)
-    event_source->RemoveXEventDispatcher(this);
-}
-
-bool GLSurfaceGLXOzone::DispatchXEvent(XEvent* event) {
-  if (!CanHandleEvent(event))
-    return false;
-
-  ForwardExposeEvent(event);
-  return true;
-}
-
-}  // namespace ui
diff --git a/ui/ozone/platform/x11/gl_surface_glx_ozone.h b/ui/ozone/platform/x11/gl_surface_glx_ozone.h
deleted file mode 100644
index acf51a0..0000000
--- a/ui/ozone/platform/x11/gl_surface_glx_ozone.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_OZONE_PLATFORM_X11_GL_SURFACE_GLX_OZONE_H_
-#define UI_OZONE_PLATFORM_X11_GL_SURFACE_GLX_OZONE_H_
-
-#include "base/macros.h"
-#include "ui/events/platform/x11/x11_event_source.h"
-#include "ui/gl/gl_surface_glx.h"
-
-namespace ui {
-
-// Ozone specific implementation of GLX surface. Registers as a XEventDispatcher
-// to handle XEvents.
-class GLSurfaceGLXOzone : public gl::NativeViewGLSurfaceGLX,
-                          public XEventDispatcher {
- public:
-  explicit GLSurfaceGLXOzone(gfx::AcceleratedWidget window);
-
- protected:
-  ~GLSurfaceGLXOzone() override;
-
-  // NativeViewGLSurfaceGLX:
-  void RegisterEvents() override;
-  void UnregisterEvents() override;
-
-  // XEventDispatcher:
-  bool DispatchXEvent(XEvent* xevent) override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(GLSurfaceGLXOzone);
-};
-
-}  // namespace ui
-
-#endif  // UI_OZONE_PLATFORM_X11_GL_SURFACE_GLX_OZONE_H_
diff --git a/ui/ozone/platform/x11/x11_surface_factory.cc b/ui/ozone/platform/x11/x11_surface_factory.cc
index fa22890..a0daef0 100644
--- a/ui/ozone/platform/x11/x11_surface_factory.cc
+++ b/ui/ozone/platform/x11/x11_surface_factory.cc
@@ -10,10 +10,10 @@
 #include "ui/gfx/x/x11.h"
 #include "ui/gfx/x/x11_types.h"
 #include "ui/gl/gl_surface_egl.h"
+#include "ui/gl/gl_surface_egl_x11_gles2.h"
 #include "ui/ozone/common/egl_util.h"
 #include "ui/ozone/common/gl_ozone_egl.h"
 #include "ui/ozone/platform/x11/gl_ozone_glx.h"
-#include "ui/ozone/platform/x11/gl_surface_egl_ozone_x11.h"
 #include "ui/ozone/platform/x11/gl_surface_egl_readback_x11.h"
 #include "ui/ozone/platform/x11/x11_canvas_surface.h"
 
@@ -43,7 +43,7 @@
           base::MakeRefCounted<GLSurfaceEglReadbackX11>(window));
     } else {
       return gl::InitializeGLSurface(
-          base::MakeRefCounted<GLSurfaceEGLOzoneX11>(window));
+          base::MakeRefCounted<gl::NativeViewGLSurfaceEGLX11GLES2>(window));
     }
   }