diff --git a/.gn b/.gn
index 00cb71c..1c7897a 100644
--- a/.gn
+++ b/.gn
@@ -65,7 +65,7 @@
 no_check_targets = [
   "//extensions/browser:*",  # 20 errors
   "//extensions:*",  # 28 errors
-  "//headless:*",  # 167 errors
+  "//headless:*",  # 107 errors
   "//ppapi/proxy:ipc_sources",  # 13 errors
   "//ppapi/thunk:*",  # 1071 errors
   "//remoting/host/security_key:*",  # 10 errors
diff --git a/DEPS b/DEPS
index b6499a8..580fa9f 100644
--- a/DEPS
+++ b/DEPS
@@ -222,11 +222,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '224e3e257d06370581aed9e2450255a45c398362',
+  'skia_revision': '7729e0a97ec36a34207ca74c1dde8136c6b89724',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'e1e303b9c19734fe54a459cb18fd496fe4518db8',
+  'v8_revision': '2517643909a0743cdc0e6a487f1ca4e4f41e8bd6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -293,7 +293,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': '3345f09ed65020a999e108ea37d30b49c87e14ed',
+  'catapult_revision': '25ef034fbef738c4ff017d1ab1c42d7a6fad6a7f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -301,7 +301,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': 'dfc8e51395fb91b0a4726a7dd2e2492c049df698',
+  'devtools_frontend_revision': '517808797a7e612cc75202b0bcdd274b8d1f6b66',
   # 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.
@@ -341,7 +341,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': '2103fa629e98a30b2c5e93bcc002e40cbd3f6d5f',
+  'dawn_revision': 'f1c76f5dfe0669c2fb00a3a9b0a78f4b0788c465',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -385,11 +385,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'libcxxabi_revision':    'cb34896ebd62f93f708ff9aad26159cf11dde6f4',
+  'libcxxabi_revision':    '6803464b0f46df0a51862347d39e0791b59cf568',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'libunwind_revision':    'e7ac0f84fc2f2f8bd2ad151a7348e7120d77648a',
+  'libunwind_revision':    'a5feaf61658af4453e282142a76aeb6f9c045311',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -738,7 +738,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': '-umIXLPTAdxRy2iaK4QFSeOf4t7PAKglJP7ggvWhfRwC',
+          'version': '_WEcXceOuK2XsUUyrM5doOfE06y8TtpBiamn4PkQp1YC',
       },
     ],
     'condition': 'checkout_android',
@@ -954,7 +954,7 @@
   # Tools used when building Chrome for Chrome OS. This affects both the Simple
   # Chrome workflow, as well as the chromeos-chrome ebuild.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'bb2bbaee0f48a65f562b01bedb0b93ba1a07f7da',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '7a515fb8020d3dd83999cab59923a70b890d46b8',
       'condition': 'checkout_chromeos',
   },
 
@@ -1360,7 +1360,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'aecbd80f576686b67e29bdfae8c9c03bb9ce1996',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '51a1443c7cb98f1fd50e1bb87c183704b4f5c81b',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1553,7 +1553,7 @@
   'src/third_party/usrsctp/usrsctplib':
     Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + '1ade45cbadfd19298d2c47dc538962d4425ad2dd',
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@36456846a4affb738fc3f012cc8f1c8c86ef0595',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@bbd1a7b068ea2dfdda9910f1447147ff69e800cb',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'f67d7fa397e83060b76a1ec53579116a0bbdff7a',
@@ -1592,7 +1592,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'e2aeec9de7a742ae131b2f56fc22de6b17b8d0e1',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '76b0c2ce47347184fa051870234bd7698ab30f3e',
+    Var('webrtc_git') + '/src.git' + '@' + '51969310ef432a9c340bb091eea1f1553ca01587',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1683,7 +1683,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'zYE4hb3r66pj55eKLN8KCScYBEIB4-LivvEUMOr7XG0C',
+        'version': '4-IHCJ0juqQPEOL75uZN5C4bzT97E1hEJUh8masGfAEC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/WATCHLISTS b/WATCHLISTS
index 5ca9249d..b3eead39 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -2194,8 +2194,7 @@
     'blink_animation': ['alexis.menard@intel.com',
                         'gerchiko@microsoft.com',
                         'blink-reviews-animation@chromium.org'],
-    'blink_audio': ['hongchan@chromium.org',
-                    'rtoy@chromium.org'],
+    'blink_audio': ['hongchan@chromium.org'],
     'blink_battery_status': ['timvolodine@chromium.org'],
     'blink_bindings': ['blink-reviews-bindings@chromium.org', 'haraken@chromium.org'],
     'blink_bindings_serialization': ['jbroman+watch@chromium.org'],
@@ -2351,8 +2350,7 @@
                    'pmonette+watch@chromium.org'],
     'chrome_grc': ['chrome-grc-reviews@chromium.org'],
     'chrome_performance_manager': ['performance-manager-reviews@chromium.org'],
-    'chromecast': ['alokp+watch@chromium.org',
-                   'halliwell+watch@chromium.org',
+    'chromecast': ['halliwell+watch@chromium.org',
                    'lcwu+watch@chromium.org'],
     'chromecast_public': ['gfhuang+watch@chromium.org'],
     'chromedriver': ['mathias@chromium.org'],
@@ -2587,8 +2585,7 @@
     'media_gpu_cros': ['media-cros-reviews@chromium.org'],
     'media_gpu_vaapi': ['vaapi-reviews@chromium.org'],
     'media_gpu_win': ['media-win-reviews@chromium.org'],
-    'media_mojo': ['alokp+watch@chromium.org',
-                   'xhwang+watch@chromium.org'],
+    'media_mojo': ['xhwang+watch@chromium.org'],
     'media_recorder': ['emircan+watch+mediarecorder@chromium.org',
                        'mcasas+mediarecorder@chromium.org'],
     'media_remoting': ['erickung+watch@chromium.org',
diff --git a/android_webview/browser/component_updater/loader_policies/aw_apps_package_names_allowlist_component_loader_policy.h b/android_webview/browser/component_updater/loader_policies/aw_apps_package_names_allowlist_component_loader_policy.h
index ca0f3e0e..5c839a6 100644
--- a/android_webview/browser/component_updater/loader_policies/aw_apps_package_names_allowlist_component_loader_policy.h
+++ b/android_webview/browser/component_updater/loader_policies/aw_apps_package_names_allowlist_component_loader_policy.h
@@ -20,6 +20,7 @@
 
 namespace base {
 class DictionaryValue;
+class Time;
 class Version;
 }  // namespace base
 
diff --git a/ash/accessibility/accessibility_controller_impl.cc b/ash/accessibility/accessibility_controller_impl.cc
index b8a3065c6..4080621 100644
--- a/ash/accessibility/accessibility_controller_impl.cc
+++ b/ash/accessibility/accessibility_controller_impl.cc
@@ -1758,7 +1758,7 @@
   const base::DictionaryValue* key_codes_pref =
       active_user_prefs_->GetDictionary(pref_key);
   std::map<int, std::set<std::string>> key_codes;
-  for (const auto& v : key_codes_pref->DictItems()) {
+  for (const auto v : key_codes_pref->DictItems()) {
     int key_code;
     if (!base::StringToInt(v.first, &key_code)) {
       NOTREACHED();
diff --git a/ash/accessibility/ui/accessibility_layer.cc b/ash/accessibility/ui/accessibility_layer.cc
index 725c5689..64a6406 100644
--- a/ash/accessibility/ui/accessibility_layer.cc
+++ b/ash/accessibility/ui/accessibility_layer.cc
@@ -87,7 +87,7 @@
         display::Screen::GetScreen()->GetDisplayMatching(bounds);
     ui::Compositor* compositor = root_window->layer()->GetCompositor();
     if (compositor && !animation_observation_.IsObservingSource(compositor)) {
-      animation_observation_.Reset();
+      Reset();
       animation_observation_.Observe(compositor);
     }
   }
@@ -101,13 +101,23 @@
 }
 
 void AccessibilityLayer::OnAnimationStep(base::TimeTicks timestamp) {
-  if (delegate_->OnAnimationStep(timestamp))
-    animation_observation_.Reset();
+  if (!delegate_->OnAnimationStep(timestamp) ||
+      !animation_observation_.IsObserving()) {
+    return;
+  }
+
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&AccessibilityLayer::Reset, weak_factory_.GetWeakPtr()));
 }
 
 void AccessibilityLayer::OnCompositingShuttingDown(ui::Compositor* compositor) {
   if (compositor && animation_observation_.IsObservingSource(compositor))
-    animation_observation_.Reset();
+    Reset();
+}
+
+void AccessibilityLayer::Reset() {
+  animation_observation_.Reset();
 }
 
 }  // namespace ash
diff --git a/ash/accessibility/ui/accessibility_layer.h b/ash/accessibility/ui/accessibility_layer.h
index 8e84a2c..936457c 100644
--- a/ash/accessibility/ui/accessibility_layer.h
+++ b/ash/accessibility/ui/accessibility_layer.h
@@ -102,6 +102,9 @@
   void OnAnimationStep(base::TimeTicks timestamp) override;
   void OnCompositingShuttingDown(ui::Compositor* compositor) override;
 
+  // Reset internal observation and state.
+  void Reset();
+
   // The object that owns this layer.
   AccessibilityLayerDelegate* delegate_;
 
@@ -111,6 +114,8 @@
                           &ui::Compositor::RemoveAnimationObserver>
       animation_observation_{this};
 
+  base::WeakPtrFactory<AccessibilityLayer> weak_factory_{this};
+
   DISALLOW_COPY_AND_ASSIGN(AccessibilityLayer);
 };
 
diff --git a/ash/app_list/views/apps_container_view.cc b/ash/app_list/views/apps_container_view.cc
index 577d1eab..abb8d23 100644
--- a/ash/app_list/views/apps_container_view.cc
+++ b/ash/app_list/views/apps_container_view.cc
@@ -58,8 +58,8 @@
 // The opacity the apps container UI should have when shown on non apps page UI.
 constexpr float kNonAppsStateOpacity = 0.1;
 
-// The horizontal margin within the apps container for app list folder view.
-constexpr int kFolderHorizontalMargin = 8;
+// The margins within the apps container for app list folder view.
+constexpr int kFolderMargin = 8;
 
 }  // namespace
 
@@ -271,8 +271,8 @@
   // Set bounding box for the folder view - the folder may overlap with
   // suggestion chips, but not the search box.
   gfx::Rect folder_bounding_box = rect;
-  folder_bounding_box.set_y(chip_container_rect.y());
-  folder_bounding_box.Inset(kFolderHorizontalMargin, 0);
+  folder_bounding_box.Inset(kFolderMargin, chip_container_rect.y(),
+                            kFolderMargin, kFolderMargin);
   app_list_folder_view_->SetBoundingBox(folder_bounding_box);
 
   // Leave the same available bounds for the apps grid view in both
@@ -282,7 +282,6 @@
   rect.set_height(rect.height() -
                   GetExpectedSuggestionChipY(kAppListFullscreenProgressValue) -
                   chip_container_rect.height());
-
   const GridLayout grid_layout = CalculateGridLayout();
   apps_grid_view_->SetLayout(grid_layout.columns, grid_layout.rows);
 
diff --git a/ash/display/display_prefs.cc b/ash/display/display_prefs.cc
index b583b6e..4287a69 100644
--- a/ash/display/display_prefs.cc
+++ b/ash/display/display_prefs.cc
@@ -200,7 +200,7 @@
       GetDisplayManager()->layout_store();
 
   const base::Value* layouts = local_state->Get(prefs::kSecondaryDisplays);
-  for (const auto& it : layouts->DictItems()) {
+  for (const auto it : layouts->DictItems()) {
     std::unique_ptr<display::DisplayLayout> layout(new display::DisplayLayout);
     if (!display::JsonToDisplayLayout(it.second, layout.get())) {
       LOG(WARNING) << "Invalid preference value for " << it.first;
@@ -226,7 +226,7 @@
 
 void LoadDisplayProperties(PrefService* local_state) {
   const base::Value* properties = local_state->Get(prefs::kDisplayProperties);
-  for (const auto& it : properties->DictItems()) {
+  for (const auto it : properties->DictItems()) {
     const base::DictionaryValue* dict_value = nullptr;
     if (!it.second.GetAsDictionary(&dict_value) || dict_value == nullptr)
       continue;
@@ -300,7 +300,7 @@
   DCHECK(properties->is_dict());
 
   display::TouchDeviceManager::TouchAssociationMap touch_associations;
-  for (const auto& item : properties->DictItems()) {
+  for (const auto item : properties->DictItems()) {
     uint32_t identifier_raw;
     if (!base::StringToUint(item.first, &identifier_raw))
       continue;
@@ -309,7 +309,7 @@
         identifier, display::TouchDeviceManager::AssociationInfoMap());
     if (!item.second.is_dict())
       continue;
-    for (const auto& association_info_item : item.second.DictItems()) {
+    for (const auto association_info_item : item.second.DictItems()) {
       display::TouchDeviceManager::TouchAssociationInfo info;
       int64_t display_id;
       if (!base::StringToInt64(association_info_item.first, &display_id))
@@ -337,7 +337,7 @@
   const display::TouchDeviceIdentifier& fallback_identifier =
       display::TouchDeviceIdentifier::GetFallbackTouchDeviceIdentifier();
   properties = local_state->Get(prefs::kDisplayProperties);
-  for (const auto& it : properties->DictItems()) {
+  for (const auto it : properties->DictItems()) {
     const base::DictionaryValue* dict_value = nullptr;
     if (!it.second.GetAsDictionary(&dict_value) || dict_value == nullptr)
       continue;
@@ -366,7 +366,7 @@
   // Retrieve port association information.
   properties = local_state->Get(prefs::kDisplayTouchPortAssociations);
   display::TouchDeviceManager::PortAssociationMap port_associations;
-  for (const auto& item : properties->DictItems()) {
+  for (const auto item : properties->DictItems()) {
     // Retrieve the secondary id that identifies the port.
     uint32_t secondary_id_raw;
     if (!base::StringToUint(item.first, &secondary_id_raw))
diff --git a/ash/quick_pair/BUILD.gn b/ash/quick_pair/BUILD.gn
index 7eed7ab..7c23b87 100644
--- a/ash/quick_pair/BUILD.gn
+++ b/ash/quick_pair/BUILD.gn
@@ -12,6 +12,7 @@
     "//ash/quick_pair/common",
     "//ash/quick_pair/feature_status_tracker",
     "//ash/quick_pair/keyed_service",
+    "//ash/quick_pair/repository",
     "//ash/quick_pair/scanning",
     "//ash/quick_pair/ui",
   ]
diff --git a/ash/quick_pair/repository/BUILD.gn b/ash/quick_pair/repository/BUILD.gn
new file mode 100644
index 0000000..de88f01
--- /dev/null
+++ b/ash/quick_pair/repository/BUILD.gn
@@ -0,0 +1,23 @@
+# Copyright 2021 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("//build/config/chromeos/ui_mode.gni")
+
+assert(is_chromeos_ash,
+       "Quick Pair protocols (e.g. Fast Pair) are ash-chrome only")
+
+source_set("repository") {
+  sources = [
+    "fast_pair_device_metadata_service.cc",
+    "fast_pair_device_metadata_service.h",
+  ]
+
+  deps = [
+    "//ash/quick_pair/common",
+    "//ash/quick_pair/proto:fastpair_proto",
+    "//base",
+    "//device/bluetooth",
+    "//third_party/grpc:grpc++",
+  ]
+}
diff --git a/ash/quick_pair/repository/fast_pair_device_metadata_service.cc b/ash/quick_pair/repository/fast_pair_device_metadata_service.cc
new file mode 100644
index 0000000..0df7fe3
--- /dev/null
+++ b/ash/quick_pair/repository/fast_pair_device_metadata_service.cc
@@ -0,0 +1,51 @@
+// Copyright 2021 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 "ash/quick_pair/repository/fast_pair_device_metadata_service.h"
+
+#include "ash/quick_pair/common/logging.h"
+#include "device/bluetooth/bluetooth_device.h"
+
+namespace ash {
+namespace quick_pair {
+
+FastPairDeviceMetadataService::FastPairDeviceMetadataService() = default;
+FastPairDeviceMetadataService::~FastPairDeviceMetadataService() = default;
+
+void FastPairDeviceMetadataService::GetDeviceMetadata(
+    const std::string& hex_model_id,
+    base::OnceCallback<void(absl::optional<nearby::fastpair::Device>)>
+        callback) {
+  QP_LOG(INFO) << __func__;
+  std::move(callback).Run(absl::nullopt);
+}
+
+void FastPairDeviceMetadataService::IsValidModelId(
+    const std::string& hex_model_id,
+    base::OnceCallback<void(bool)> callback) {
+  QP_LOG(INFO) << __func__;
+  std::move(callback).Run(false);
+}
+
+void FastPairDeviceMetadataService::GetAssociatedAccountKey(
+    const std::string& address,
+    const std::string& account_key_filter,
+    base::OnceCallback<void(absl::optional<std::string>)> callback) {
+  QP_LOG(INFO) << __func__;
+  std::move(callback).Run(absl::nullopt);
+}
+
+void FastPairDeviceMetadataService::AssociateAccountKey(
+    const Device& device,
+    const std::string& account_key) {
+  QP_LOG(INFO) << __func__;
+}
+
+void FastPairDeviceMetadataService::DeleteAssociatedDevice(
+    const device::BluetoothDevice* device) {
+  QP_LOG(INFO) << __func__;
+}
+
+}  // namespace quick_pair
+}  // namespace ash
diff --git a/ash/quick_pair/repository/fast_pair_device_metadata_service.h b/ash/quick_pair/repository/fast_pair_device_metadata_service.h
new file mode 100644
index 0000000..b1c079f
--- /dev/null
+++ b/ash/quick_pair/repository/fast_pair_device_metadata_service.h
@@ -0,0 +1,62 @@
+// Copyright 2021 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 ASH_QUICK_PAIR_REPOSITORY_FAST_PAIR_DEVICE_METADATA_SERVICE_H_
+#define ASH_QUICK_PAIR_REPOSITORY_FAST_PAIR_DEVICE_METADATA_SERVICE_H_
+
+#include "ash/quick_pair/common/device.h"
+#include "ash/quick_pair/proto/fastpair.pb.h"
+#include "base/callback.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace device {
+class BluetoothDevice;
+}
+
+namespace ash {
+namespace quick_pair {
+
+// The entry point for the Repository component in the Quick Pair system,
+// responsible for connecting to back-end services.
+class FastPairDeviceMetadataService {
+ public:
+  FastPairDeviceMetadataService();
+  FastPairDeviceMetadataService(const FastPairDeviceMetadataService&) = delete;
+  FastPairDeviceMetadataService& operator=(
+      const FastPairDeviceMetadataService&) = delete;
+  virtual ~FastPairDeviceMetadataService();
+
+  // Returns the DeviceMetadata for a given |hex_model_id| to the provided
+  // |callback|, if available.
+  void GetDeviceMetadata(
+      const std::string& hex_model_id,
+      base::OnceCallback<void(absl::optional<nearby::fastpair::Device>)>
+          callback);
+
+  // Checks if the input |hex_model_id| is valid and notifies the requester
+  // through the provided |callback|.
+  void IsValidModelId(const std::string& hex_model_id,
+                      base::OnceCallback<void(bool)> callback);
+
+  // Looks up the key associated with either |address| or |account_key_filter|
+  // and returns it to the provided |callback|, if available.  If this
+  // information is available locally that will be returned immediately,
+  // otherwise this will request data from the footprints server.
+  void GetAssociatedAccountKey(
+      const std::string& address,
+      const std::string& account_key_filter,
+      base::OnceCallback<void(absl::optional<std::string>)> callback);
+
+  // Stores the given |account_key| for a |device| on the server.
+  void AssociateAccountKey(const Device& device,
+                           const std::string& account_key);
+
+  // Deletes the associated data for a given |device|.
+  void DeleteAssociatedDevice(const device::BluetoothDevice* device);
+};
+
+}  // namespace quick_pair
+}  // namespace ash
+
+#endif  // ASH_QUICK_PAIR_REPOSITORY_FAST_PAIR_DEVICE_METADATA_SERVICE_H_
diff --git a/ash/webui/scanning/resources/scan_preview.html b/ash/webui/scanning/resources/scan_preview.html
index 2856269..3d4f0a9 100644
--- a/ash/webui/scanning/resources/scan_preview.html
+++ b/ash/webui/scanning/resources/scan_preview.html
@@ -48,12 +48,17 @@
     max-height: calc(100vh - var(--panel-container-margin-top));
     outline: none;
     overflow-y: auto;
+    padding-top: 2px;
   }
 
   .preview:focus {
     box-shadow: 0 0 0 2px rgba(var(--google-blue-600-rgb), .4);
   }
 
+  .preview:hover {
+    box-shadow: none;
+  }
+
   .preview-item {
     border: 1px solid var(--google-grey-300);
     border-radius: 4px;
@@ -69,6 +74,10 @@
     width: calc(100% - 24px);
   }
 
+  .preview:hover .focused-scanned-image {
+    box-shadow: rgba(var(--google-blue-600-rgb), .4) 0 0 0 2px;
+  }
+
   paper-progress {
     border-radius: 4px;
     height: 4px;
diff --git a/ash/webui/scanning/resources/scan_preview.js b/ash/webui/scanning/resources/scan_preview.js
index 75a7c5d..7542679 100644
--- a/ash/webui/scanning/resources/scan_preview.js
+++ b/ash/webui/scanning/resources/scan_preview.js
@@ -7,6 +7,7 @@
 import './scanning_shared_css.js';
 import 'chrome://resources/polymer/v3_0/paper-progress/paper-progress.js';
 
+import {assert} from 'chrome://resources/js/assert.m.js';
 import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js';
 import {afterNextRender, html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
@@ -102,12 +103,19 @@
       type: Number,
       value: 1,
     },
+
+    /** @private {number} */
+    previousPageInView_: {
+      type: Number,
+      value: -1,
+    },
   },
 
   observers: [
     'setPreviewAriaLabel_(showScannedImages_, showCancelingProgress_,' +
         ' showHelperText_)',
     'setScanProgressTimer_(showScanProgress_, progressPercent)',
+    'setFocusedScannedImage_(objectUrls.length, currentPageInView_)',
   ],
 
   /** @override */
@@ -216,6 +224,8 @@
   onScannedImagesScroll_() {
     const imageHeight = this.$$('.scanned-image').height;
     const scrollTop = this.$$('#previewDiv').scrollTop - (imageHeight * .5);
+    assert(this.currentPageInView_ > 0);
+    this.previousPageInView_ = this.currentPageInView_;
 
     // This is a special case for the first page since there is no margin or
     // previous page above it.
@@ -226,5 +236,30 @@
 
     this.currentPageInView_ = 2 +
         Math.floor(scrollTop / (imageHeight + SCANNED_IMG_MARGIN_BOTTOM_PX));
+    assert(this.currentPageInView_ > 0);
+  },
+
+  /**
+   * Sets the CSS class for the current scanned image in view so the blue border
+   * will show on the correct page when hovered.
+   * @private
+   */
+  setFocusedScannedImage_() {
+    // Need to wait for the scanned images to render.
+    afterNextRender(this, () => {
+      const scannedImages =
+          this.$$('#scannedImages').getElementsByClassName('scanned-image');
+      if (scannedImages.length === 0) {
+        return;
+      }
+
+      if (this.previousPageInView_ > 0) {
+        scannedImages[this.previousPageInView_ - 1].classList.remove(
+            'focused-scanned-image');
+      }
+      assert(this.currentPageInView_ > 0);
+      scannedImages[this.currentPageInView_ - 1].classList.add(
+          'focused-scanned-image');
+    });
   },
 });
diff --git a/base/trace_event/trace_event_unittest.cc b/base/trace_event/trace_event_unittest.cc
index c43bce7..c6b1ddf5 100644
--- a/base/trace_event/trace_event_unittest.cc
+++ b/base/trace_event/trace_event_unittest.cc
@@ -325,7 +325,7 @@
 }
 
 bool IsStringInDict(const char* string_to_match, const Value* dict) {
-  for (const auto& pair : dict->DictItems()) {
+  for (const auto pair : dict->DictItems()) {
     if (pair.first.find(string_to_match) != std::string::npos)
       return true;
 
diff --git a/base/values_unittest.cc b/base/values_unittest.cc
index 73a5c45..29aa5ea 100644
--- a/base/values_unittest.cc
+++ b/base/values_unittest.cc
@@ -1677,27 +1677,21 @@
   ASSERT_TRUE(copy_bool);
   ASSERT_NE(copy_bool, bool_weak);
   ASSERT_TRUE(copy_bool->is_bool());
-  bool copy_bool_value = false;
-  ASSERT_TRUE(copy_bool->GetAsBoolean(&copy_bool_value));
-  ASSERT_TRUE(copy_bool_value);
+  ASSERT_TRUE(copy_bool->GetBool());
 
   Value* copy_int = nullptr;
   ASSERT_TRUE(copy_dict->Get("int", &copy_int));
   ASSERT_TRUE(copy_int);
   ASSERT_NE(copy_int, int_weak);
   ASSERT_TRUE(copy_int->is_int());
-  int copy_int_value = 0;
-  ASSERT_TRUE(copy_int->GetAsInteger(&copy_int_value));
-  ASSERT_EQ(42, copy_int_value);
+  ASSERT_EQ(42, copy_int->GetInt());
 
   Value* copy_double = nullptr;
   ASSERT_TRUE(copy_dict->Get("double", &copy_double));
   ASSERT_TRUE(copy_double);
   ASSERT_NE(copy_double, double_weak);
   ASSERT_TRUE(copy_double->is_double());
-  double copy_double_value = 0;
-  ASSERT_TRUE(copy_double->GetAsDouble(&copy_double_value));
-  ASSERT_EQ(3.14, copy_double_value);
+  ASSERT_EQ(3.14, copy_double->GetDouble());
 
   Value* copy_string = nullptr;
   ASSERT_TRUE(copy_dict->Get("string", &copy_string));
@@ -1743,17 +1737,15 @@
   ASSERT_TRUE(copy_list->Get(0, &copy_list_element_0));
   ASSERT_TRUE(copy_list_element_0);
   ASSERT_NE(copy_list_element_0, list_element_0_weak);
-  int copy_list_element_0_value;
-  ASSERT_TRUE(copy_list_element_0->GetAsInteger(&copy_list_element_0_value));
-  ASSERT_EQ(0, copy_list_element_0_value);
+  ASSERT_TRUE(copy_list_element_0->is_int());
+  ASSERT_EQ(0, copy_list_element_0->GetInt());
 
   Value* copy_list_element_1;
   ASSERT_TRUE(copy_list->Get(1, &copy_list_element_1));
   ASSERT_TRUE(copy_list_element_1);
   ASSERT_NE(copy_list_element_1, list_element_1_weak);
-  int copy_list_element_1_value;
-  ASSERT_TRUE(copy_list_element_1->GetAsInteger(&copy_list_element_1_value));
-  ASSERT_EQ(1, copy_list_element_1_value);
+  ASSERT_TRUE(copy_list_element_1->is_int());
+  ASSERT_EQ(1, copy_list_element_1->GetInt());
 
   copy_value = nullptr;
   ASSERT_TRUE(copy_dict->Get("dictionary", &copy_value));
diff --git a/build/config/mac/BUILD.gn b/build/config/mac/BUILD.gn
index 0919208e..8005ed5 100644
--- a/build/config/mac/BUILD.gn
+++ b/build/config/mac/BUILD.gn
@@ -117,7 +117,8 @@
 #
 # The symbolic link for $mac_sdk_path is set up by
 # //build/config/apple/sdk_info.py in //build/config/mac/mac_sdk.gni.
-if (use_system_xcode && use_goma && target_os == "mac") {
+if (use_system_xcode && use_goma && target_os == "mac" &&
+    current_toolchain == default_toolchain) {
   action("sdk_inputs") {
     script = "//build/noop.py"
     outputs = [
@@ -128,5 +129,8 @@
   }
 } else {
   group("sdk_inputs") {
+    if (current_toolchain != default_toolchain) {
+      public_deps = [ ":sdk_inputs($default_toolchain)" ]
+    }
   }
 }
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index aa378246..61e0a1e8 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-5.20210713.0.1
+5.20210713.1.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index aa378246..61e0a1e8 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-5.20210713.0.1
+5.20210713.1.1
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index f3383a4..93dc43ba 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -671,6 +671,7 @@
   "java/src/org/chromium/chrome/browser/incognito/IncognitoNotificationServiceImpl.java",
   "java/src/org/chromium/chrome/browser/incognito/IncognitoProfileDestroyer.java",
   "java/src/org/chromium/chrome/browser/incognito/IncognitoTabLauncher.java",
+  "java/src/org/chromium/chrome/browser/incognito/IncognitoTabPersistence.java",
   "java/src/org/chromium/chrome/browser/incognito/IncognitoTabSnapshotController.java",
   "java/src/org/chromium/chrome/browser/incognito/IncognitoUtils.java",
   "java/src/org/chromium/chrome/browser/infobar/AutofillCreditCardFillingInfoBar.java",
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceCoordinator.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceCoordinator.java
index baf7cad..97c1acf 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceCoordinator.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceCoordinator.java
@@ -59,12 +59,6 @@
          */
         FeedSurfaceCoordinator createFeedSurfaceCoordinator(boolean isInNightMode,
                 boolean isPlaceholderShown, @NewTabPageLaunchOrigin int launchOrigin);
-
-        /** Shows the Feeds surface. */
-        void showFeedSurface();
-
-        /** Hides the Feeds surface. */
-        void hideFeedSurface();
     }
 
     /**
@@ -107,20 +101,6 @@
                         isPlaceholderShown, bottomSheetController, scrollableContainerDelegate,
                         launchOrigin, feedLaunchReliabilityLoggingState);
             }
-
-            @Override
-            public void showFeedSurface() {
-                if (mExploreSurfaceFeedLifecycleManager != null) {
-                    mExploreSurfaceFeedLifecycleManager.showFeedSurface();
-                }
-            }
-
-            @Override
-            public void hideFeedSurface() {
-                if (mExploreSurfaceFeedLifecycleManager != null) {
-                    mExploreSurfaceFeedLifecycleManager.hideFeedSurface();
-                }
-            }
         };
     }
 
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceFeedLifecycleManager.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceFeedLifecycleManager.java
index e7b242c2..eb7471e 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceFeedLifecycleManager.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/ExploreSurfaceFeedLifecycleManager.java
@@ -55,12 +55,4 @@
         String state = mCoordinator.getSavedInstanceStateString();
         StartSurfaceUserData.getInstance().saveFeedInstanceState(state);
     }
-
-    public void showFeedSurface() {
-        super.show();
-    }
-
-    public void hideFeedSurface() {
-        super.hide();
-    }
-}
+}
\ No newline at end of file
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
index 682e35f..500be7b0 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
@@ -53,7 +53,6 @@
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.browser.tab.TabLaunchType;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelObserver;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
@@ -575,8 +574,6 @@
                         mFeedSurfaceController.createFeedSurfaceCoordinator(
                                 ColorUtils.inNightMode(mContext), shouldShowFeedPlaceholder(),
                                 mLaunchOrigin));
-            } else {
-                showFeedSurfaceCoordinator();
             }
             mTabModelSelector.addObserver(mTabModelSelectorObserver);
 
@@ -679,13 +676,7 @@
             }
             mPropertyModel.set(IS_SHOWING_OVERVIEW, false);
 
-            if (mTabModelSelector.getCurrentTab() == null
-                    || mTabModelSelector.getCurrentTab().getLaunchType()
-                            != TabLaunchType.FROM_START_SURFACE) {
-                destroyFeedSurfaceCoordinator();
-            } else {
-                hideFeedSurfaceCoordinator();
-            }
+            destroyFeedSurfaceCoordinator();
             if (mNormalTabModelObserver != null) {
                 if (mNormalTabModel != null) {
                     mNormalTabModel.removeObserver(mNormalTabModelObserver);
@@ -721,14 +712,6 @@
         mPropertyModel.set(FEED_SURFACE_COORDINATOR, null);
     }
 
-    private void hideFeedSurfaceCoordinator() {
-        if (mFeedSurfaceController != null) mFeedSurfaceController.hideFeedSurface();
-    }
-
-    private void showFeedSurfaceCoordinator() {
-        if (mFeedSurfaceController != null) mFeedSurfaceController.showFeedSurface();
-    }
-
     // TODO(crbug.com/982018): turn into onClickMoreTabs() and hide the OnClickListener signature
     // inside. Implements View.OnClickListener, which listens for the more tabs button.
     @Override
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutPerfTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutPerfTest.java
index 931f2691..8863735 100644
--- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutPerfTest.java
+++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutPerfTest.java
@@ -352,6 +352,7 @@
     @Test
     @EnormousTest
     @CommandLineFlags.Add({BASE_PARAMS})
+    @FlakyTest(message = "https://crbug.com/1225926")
     public void testGridToTabToOtherLive() throws InterruptedException {
         prepareTabs(2, mUrl);
         reportGridToTabPerf(true, false, "Grid-to-Tab to other live tab");
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutTest.java
index ce4a3f1..eefb377 100644
--- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutTest.java
+++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutTest.java
@@ -99,12 +99,12 @@
 import org.chromium.chrome.browser.flags.CachedFeatureFlags;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
-import org.chromium.chrome.browser.incognito.IncognitoUtils;
 import org.chromium.chrome.browser.night_mode.ChromeNightModeTestUtils;
 import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabLaunchType;
 import org.chromium.chrome.browser.tab.TabStateExtractor;
+import org.chromium.chrome.browser.tabmodel.IncognitoTabHostUtils;
 import org.chromium.chrome.browser.tabmodel.TabCreator;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabModelObserver;
@@ -2037,7 +2037,7 @@
         CriteriaHelper.pollUiThread(()
                                             -> newActivity.getCurrentTabModel().isIncognito(),
                 "New Activity current TabModel is not incognito");
-        TestThreadUtils.runOnUiThreadBlocking(IncognitoUtils::closeAllIncognitoTabs);
+        TestThreadUtils.runOnUiThreadBlocking(IncognitoTabHostUtils::closeAllIncognitoTabs);
 
         assertTrue("Deferred startup never completed", mActivityTestRule.waitForDeferredStartup());
 
diff --git a/chrome/android/features/start_surface/internal/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java b/chrome/android/features/start_surface/internal/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java
index 18f9954b..88d2047 100644
--- a/chrome/android/features/start_surface/internal/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java
+++ b/chrome/android/features/start_surface/internal/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java
@@ -8,7 +8,6 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -1081,18 +1080,10 @@
         mediator.hideOverview(true);
         mOverviewModeObserverCaptor.getValue().startedHiding();
         mOverviewModeObserverCaptor.getValue().finishedHiding();
-        verify(mFeedSurfaceController).hideFeedSurface();
-        assertThat(mPropertyModel.get(FEED_SURFACE_COORDINATOR), equalTo(mFeedSurfaceCoordinator));
+        assertNull(mPropertyModel.get(FEED_SURFACE_COORDINATOR));
 
-        FeedSurfaceCoordinator feedSurfaceCoordinator = mock(FeedSurfaceCoordinator.class);
-        assertNotEquals(mFeedSurfaceCoordinator, feedSurfaceCoordinator);
-        when(mFeedSurfaceController.createFeedSurfaceCoordinator(
-                     anyBoolean(), anyBoolean(), anyInt()))
-                .thenReturn(feedSurfaceCoordinator);
         mediator.setOverviewState(StartSurfaceState.SHOWING_PREVIOUS);
         mediator.showOverview(false);
-        verify(mFeedSurfaceController).showFeedSurface();
-        mainTabGridController.verify(mMainTabGridController).showOverview(eq(false));
         assertThat(mediator.getStartSurfaceState(), equalTo(StartSurfaceState.SHOWN_HOMEPAGE));
         assertThat(mPropertyModel.get(FEED_SURFACE_COORDINATOR), equalTo(mFeedSurfaceCoordinator));
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index bf0a39c1..e2cc4a0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -145,6 +145,7 @@
 import org.chromium.chrome.browser.tabmodel.ChromeTabCreator;
 import org.chromium.chrome.browser.tabmodel.IncognitoTabHost;
 import org.chromium.chrome.browser.tabmodel.IncognitoTabHostRegistry;
+import org.chromium.chrome.browser.tabmodel.IncognitoTabHostUtils;
 import org.chromium.chrome.browser.tabmodel.NextTabPolicy.NextTabPolicySupplier;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
@@ -798,7 +799,7 @@
 
             // Check for incognito tabs to handle the case where Chrome was swiped away in the
             // background.
-            if (!IncognitoUtils.doIncognitoTabsExist()) {
+            if (!IncognitoTabHostUtils.doIncognitoTabsExist()) {
                 IncognitoNotificationManager.dismissIncognitoNotification();
                 DownloadNotificationService.getInstance().cancelOffTheRecordDownloads();
             }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
index a8724d7..8f1c018 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
@@ -1567,6 +1567,19 @@
         }
     }
 
+    /**
+     * Whether bundle has any extra that indicates an incognito tab will be launched.
+     * @param extras A bundle that carries extras
+     * @return True if there is any incognito related extra, otherwise return false.
+     */
+    public static boolean hasAnyIncognitoExtra(@Nullable Bundle extras) {
+        if (extras == null) return false;
+        return IntentUtils.safeGetBoolean(extras, EXTRA_INCOGNITO_MODE, false)
+                || IntentUtils.safeGetBoolean(extras, EXTRA_OPEN_NEW_INCOGNITO_TAB, false)
+                || IntentUtils.safeGetBoolean(
+                        extras, EXTRA_INVOKED_FROM_LAUNCH_NEW_INCOGNITO_TAB, false);
+    }
+
     @NativeMethods
     interface Natives {
         boolean isCorsSafelistedHeader(String name, String value);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
index 1a80e58..c1125e7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
@@ -58,7 +58,6 @@
 import org.chromium.chrome.browser.browserservices.SessionHandler;
 import org.chromium.chrome.browser.device.DeviceClassManager;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
-import org.chromium.chrome.browser.incognito.IncognitoUtils;
 import org.chromium.chrome.browser.init.ChainedTasks;
 import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
 import org.chromium.chrome.browser.metrics.PageLoadMetrics;
@@ -495,7 +494,7 @@
             // creation in incognito mode not to have inconsistent modes between tab model and
             // hidden tab. (crbug.com/1190971)
             boolean canUseHiddenTab = mClientManager.getCanUseHiddenTab(session)
-                    && !IncognitoUtils.hasAnyIncognitoExtra(extras);
+                    && !IntentHandler.hasAnyIncognitoExtra(extras);
             startSpeculation(session, url, canUseHiddenTab, extras, uid);
         }
         preconnectUrls(otherLikelyBundles);
@@ -553,7 +552,7 @@
         // mayLaunchUrl should not be executed for Incognito CCT since all setup is created with
         // regular profile. If we need to enable mayLaunchUrl for off-the-record profiles, we need
         // to update the profile used. Please see crbug.com/1106757.
-        if (IncognitoUtils.hasAnyIncognitoExtra(extras)) return false;
+        if (IntentHandler.hasAnyIncognitoExtra(extras)) return false;
 
         final boolean lowConfidence =
                 (url == null || TextUtils.isEmpty(url.toString())) && otherLikelyBundles != null;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoNotificationPresenceController.java b/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoNotificationPresenceController.java
index da61835..d8b54bf6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoNotificationPresenceController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoNotificationPresenceController.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.incognito;
 
+import org.chromium.chrome.browser.tabmodel.IncognitoTabHostUtils;
 import org.chromium.chrome.browser.tabmodel.IncognitoTabModelObserver;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 
@@ -32,7 +33,7 @@
 
     @Override
     public void didBecomeEmpty() {
-        if (!IncognitoUtils.doIncognitoTabsExist()) {
+        if (!IncognitoTabHostUtils.doIncognitoTabsExist()) {
             IncognitoNotificationManager.dismissIncognitoNotification();
         }
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoNotificationServiceImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoNotificationServiceImpl.java
index cfdcd24..f249cc5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoNotificationServiceImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoNotificationServiceImpl.java
@@ -22,6 +22,7 @@
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.document.ChromeLauncherActivity;
 import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.tabmodel.IncognitoTabHostUtils;
 import org.chromium.chrome.browser.util.AndroidTaskUtils;
 import org.chromium.components.browser_ui.notifications.PendingIntentProvider;
 import org.chromium.content_public.browser.BrowserStartupController;
@@ -48,15 +49,15 @@
     @Override
     protected void onHandleIntent(Intent intent) {
         PostTask.runSynchronously(
-                UiThreadTaskTraits.DEFAULT, IncognitoUtils::closeAllIncognitoTabs);
+                UiThreadTaskTraits.DEFAULT, IncognitoTabHostUtils::closeAllIncognitoTabs);
 
-        boolean clearedIncognito = IncognitoUtils.deleteIncognitoStateFiles();
+        boolean clearedIncognito = IncognitoTabPersistence.deleteIncognitoStateFiles();
 
         // If we failed clearing all of the incognito tabs, then do not dismiss the notification.
         if (!clearedIncognito) return;
 
         PostTask.runSynchronously(UiThreadTaskTraits.DEFAULT, () -> {
-            if (IncognitoUtils.doIncognitoTabsExist()) {
+            if (IncognitoTabHostUtils.doIncognitoTabsExist()) {
                 assert false : "Not all incognito tabs closed as expected";
                 return;
             }
@@ -78,28 +79,6 @@
         });
     }
 
-    private void focusChromeIfNecessary() {
-        Set<Integer> visibleTaskIds = getTaskIdsForVisibleActivities();
-        int tabbedTaskId = -1;
-
-        for (Activity activity : ApplicationStatus.getRunningActivities()) {
-            if (activity instanceof ChromeTabbedActivity) {
-                tabbedTaskId = activity.getTaskId();
-                break;
-            }
-        }
-
-        // If the task containing the tabbed activity is visible, then do nothing as there is no
-        // snapshot that would need to be regenerated.
-        if (visibleTaskIds.contains(tabbedTaskId)) return;
-
-        Context context = ContextUtils.getApplicationContext();
-        Intent startIntent = new Intent(Intent.ACTION_MAIN);
-        startIntent.setPackage(context.getPackageName());
-        startIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        context.startActivity(startIntent);
-    }
-
     private void removeNonVisibleChromeTabbedRecentEntries() {
         Set<Integer> visibleTaskIds = getTaskIdsForVisibleActivities();
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoProfileDestroyer.java b/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoProfileDestroyer.java
index e9f3dde7..e3de455 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoProfileDestroyer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoProfileDestroyer.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.incognito;
 
 import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.tabmodel.IncognitoTabHostUtils;
 import org.chromium.chrome.browser.tabmodel.IncognitoTabModelObserver;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 
@@ -32,7 +33,8 @@
 
     @Override
     public void didBecomeEmpty() {
-        if (!IncognitoUtils.doIncognitoTabsExist() && !IncognitoUtils.isIncognitoTabModelActive()) {
+        if (!IncognitoTabHostUtils.doIncognitoTabsExist()
+                && !IncognitoTabHostUtils.isIncognitoTabModelActive()) {
             // Only delete the incognito profile if there are no incognito tabs open in any tab
             // model selector as the profile is shared between them.
             Profile profile = mTabModelSelector.getModel(true).getProfile();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoTabPersistence.java b/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoTabPersistence.java
new file mode 100644
index 0000000..fb65a56
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoTabPersistence.java
@@ -0,0 +1,38 @@
+// Copyright 2021 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.incognito;
+
+import android.util.Pair;
+
+import org.chromium.chrome.browser.tabpersistence.TabStateDirectory;
+import org.chromium.chrome.browser.tabpersistence.TabStateFileManager;
+
+import java.io.File;
+
+/**
+ * Manages tab state files for incognito tabs.
+ */
+public class IncognitoTabPersistence {
+    /**
+     * Deletes files with saved state of incognito tabs.
+     * @return whether successful.
+     */
+    static boolean deleteIncognitoStateFiles() {
+        File directory = TabStateDirectory.getOrCreateTabbedModeStateDirectory();
+        File[] tabStateFiles = directory.listFiles();
+        if (tabStateFiles == null) return true;
+
+        boolean deletionSuccessful = true;
+        for (File file : tabStateFiles) {
+            Pair<Integer, Boolean> tabInfo =
+                    TabStateFileManager.parseInfoFromFilename(file.getName());
+            boolean isIncognito = tabInfo != null && tabInfo.second;
+            if (isIncognito) {
+                deletionSuccessful &= file.delete();
+            }
+        }
+        return deletionSuccessful;
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoUtils.java
index 899d812e..42ccb4f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoUtils.java
@@ -8,30 +8,22 @@
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.content.Context;
-import android.os.Bundle;
-import android.util.Pair;
 
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.ApplicationStatus;
 import org.chromium.base.ContextUtils;
-import org.chromium.base.IntentUtils;
 import org.chromium.base.annotations.NativeMethods;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
-import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.customtabs.CustomTabIncognitoManager;
 import org.chromium.chrome.browser.profiles.OTRProfileID;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.profiles.ProfileKey;
-import org.chromium.chrome.browser.tabmodel.IncognitoTabHost;
-import org.chromium.chrome.browser.tabmodel.IncognitoTabHostRegistry;
-import org.chromium.chrome.browser.tabpersistence.TabStateDirectory;
-import org.chromium.chrome.browser.tabpersistence.TabStateFileManager;
+import org.chromium.chrome.browser.tabmodel.IncognitoTabHostUtils;
 import org.chromium.chrome.browser.util.AndroidTaskUtils;
 import org.chromium.ui.base.WindowAndroid;
 
-import java.io.File;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -83,7 +75,7 @@
         // any incognito tabs exist and the current tab model isn't incognito. If so, we should
         // destroy the incognito profile; otherwise it's not safe to do so yet.
         if (tabbedModeTaskIds.size() == 0) {
-            return !(doIncognitoTabsExist() || selectedTabModelIsIncognito);
+            return !(IncognitoTabHostUtils.doIncognitoTabsExist() || selectedTabModelIsIncognito);
         }
 
         // In this case, we have tabbed mode activities listed in recents that do not have an
@@ -94,60 +86,6 @@
     }
 
     /**
-     * Determine whether there are any incognito tabs.
-     */
-    public static boolean doIncognitoTabsExist() {
-        for (IncognitoTabHost host : IncognitoTabHostRegistry.getInstance().getHosts()) {
-            if (host.hasIncognitoTabs()) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Determine whether the incognito tab model is active.
-     */
-    public static boolean isIncognitoTabModelActive() {
-        for (IncognitoTabHost host : IncognitoTabHostRegistry.getInstance().getHosts()) {
-            if (host.isActiveModel()) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Closes all incognito tabs.
-     */
-    public static void closeAllIncognitoTabs() {
-        for (IncognitoTabHost host : IncognitoTabHostRegistry.getInstance().getHosts()) {
-            host.closeAllIncognitoTabs();
-        }
-    }
-
-    /**
-     * Deletes files with saved state of incognito tabs.
-     * @return whether successful.
-     */
-    public static boolean deleteIncognitoStateFiles() {
-        File directory = TabStateDirectory.getOrCreateTabbedModeStateDirectory();
-        File[] tabStateFiles = directory.listFiles();
-        if (tabStateFiles == null) return true;
-
-        boolean deletionSuccessful = true;
-        for (File file : tabStateFiles) {
-            Pair<Integer, Boolean> tabInfo =
-                    TabStateFileManager.parseInfoFromFilename(file.getName());
-            boolean isIncognito = tabInfo != null && tabInfo.second;
-            if (isIncognito) {
-                deletionSuccessful &= file.delete();
-            }
-        }
-        return deletionSuccessful;
-    }
-
-    /**
      * @return true if incognito mode is enabled.
      */
     public static boolean isIncognitoModeEnabled() {
@@ -165,20 +103,6 @@
     }
 
     /**
-     * Whether bundle has any extra that indicates an incognito tab will be launched.
-     * @param extras A bundle that carries extras
-     * @return True if there is any incognito related extra, otherwise return false.
-     */
-    public static boolean hasAnyIncognitoExtra(@Nullable Bundle extras) {
-        if (extras == null) return false;
-        return IntentUtils.safeGetBoolean(extras, IntentHandler.EXTRA_INCOGNITO_MODE, false)
-                || IntentUtils.safeGetBoolean(
-                        extras, IntentHandler.EXTRA_OPEN_NEW_INCOGNITO_TAB, false)
-                || IntentUtils.safeGetBoolean(
-                        extras, IntentHandler.EXTRA_INVOKED_FROM_LAUNCH_NEW_INCOGNITO_TAB, false);
-    }
-
-    /**
      * Returns either a regular profile or a (primary/non-primary) Incognito profile.
      *
      * <p>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
index f00d0a72..aefc7b2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
@@ -38,7 +38,6 @@
 import org.chromium.chrome.browser.LaunchIntentDispatcher;
 import org.chromium.chrome.browser.WarmupManager;
 import org.chromium.chrome.browser.firstrun.FirstRunFlowSequencer;
-import org.chromium.chrome.browser.incognito.IncognitoUtils;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.multiwindow.MultiWindowModeStateDispatcher;
 import org.chromium.chrome.browser.multiwindow.MultiWindowModeStateDispatcherImpl;
@@ -254,7 +253,7 @@
             String url = IntentHandler.getUrlFromIntent(intent);
             if (url == null) return;
             // Blocking pre-connect for all off-the-record profiles.
-            if (!IncognitoUtils.hasAnyIncognitoExtra(intent.getExtras())) {
+            if (!IntentHandler.hasAnyIncognitoExtra(intent.getExtras())) {
                 WarmupManager.getInstance().maybePreconnectUrlAndSubResources(
                         Profile.getLastUsedRegularProfile(), url);
             }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/previewtab/PreviewTabTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/previewtab/PreviewTabTest.java
index b03a530..751bb96e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/previewtab/PreviewTabTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/previewtab/PreviewTabTest.java
@@ -21,9 +21,9 @@
 import org.chromium.chrome.browser.compositor.bottombar.ephemeraltab.EphemeralTabCoordinator;
 import org.chromium.chrome.browser.contextualsearch.ContextualSearchManager;
 import org.chromium.chrome.browser.firstrun.DisableFirstRun;
-import org.chromium.chrome.browser.incognito.IncognitoUtils;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabbed_mode.TabbedRootUiCoordinator;
+import org.chromium.chrome.browser.tabmodel.IncognitoTabHostUtils;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.util.browser.contextmenu.ContextMenuUtils;
@@ -144,7 +144,7 @@
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             bottomSheet.expandSheet();
             endAnimations();
-            IncognitoUtils.closeAllIncognitoTabs();
+            IncognitoTabHostUtils.closeAllIncognitoTabs();
             endAnimations();
         });
         Assert.assertEquals(SheetState.HIDDEN, bottomSheet.getSheetState());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SyncConsentFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SyncConsentFragmentTest.java
index 43c8f30..272c3ad 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SyncConsentFragmentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SyncConsentFragmentTest.java
@@ -67,7 +67,7 @@
 import org.chromium.components.signin.ChildAccountStatus;
 import org.chromium.components.signin.base.CoreAccountInfo;
 import org.chromium.components.signin.metrics.SigninAccessPoint;
-import org.chromium.components.signin.test.util.FakeProfileDataSource;
+import org.chromium.components.signin.test.util.FakeAccountInfoService;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.ui.modaldialog.ModalDialogManager;
 import org.chromium.ui.modaldialog.ModalDialogManager.ModalDialogType;
@@ -112,7 +112,7 @@
 
     @Rule
     public final AccountManagerTestRule mAccountManagerTestRule =
-            new AccountManagerTestRule(new FakeProfileDataSource());
+            new AccountManagerTestRule(new FakeAccountInfoService());
 
     @Rule
     public final ChromeTabbedActivityTestRule mChromeActivityTestRule =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/test/smoke/ChromeBundleSmokeTest.java b/chrome/android/javatests/src/org/chromium/chrome/test/smoke/ChromeBundleSmokeTest.java
index c6bd6e2..ad40d5922 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/test/smoke/ChromeBundleSmokeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/test/smoke/ChromeBundleSmokeTest.java
@@ -7,7 +7,6 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.os.Build;
 import android.support.test.InstrumentationRegistry;
 
 import androidx.test.filters.SmallTest;
@@ -21,7 +20,6 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.test.BaseJUnit4ClassRunner;
-import org.chromium.base.test.util.DisableIf;
 import org.chromium.chrome.test.pagecontroller.rules.ChromeUiApplicationTestRule;
 import org.chromium.chrome.test.pagecontroller.rules.ChromeUiAutomatorTestRule;
 import org.chromium.chrome.test.pagecontroller.utils.IUi2Locator;
@@ -73,38 +71,22 @@
     }
 
     @Test
-    @DisableIf.Build(message = "Flaky on Android Marshmallow, see crbug.com/1178106",
-            sdk_is_greater_than = Build.VERSION_CODES.LOLLIPOP_MR1,
-            sdk_is_less_than = Build.VERSION_CODES.N)
-    public void
-    testModuleJavaCodeExecution() {
+    public void testModuleJavaCodeExecution() {
         runTestActivity(0); // Test case EXECUTE_JAVA.
     }
 
     @Test
-    @DisableIf.Build(message = "Flaky on Android Marshmallow, see crbug.com/1178106",
-            sdk_is_greater_than = Build.VERSION_CODES.LOLLIPOP_MR1,
-            sdk_is_less_than = Build.VERSION_CODES.N)
-    public void
-    testModuleNativeCodeExecution() {
+    public void testModuleNativeCodeExecution() {
         runTestActivity(1); // Test case EXECUTE_NATIVE.
     }
 
     @Test
-    @DisableIf.Build(message = "Flaky on Android Marshmallow, see crbug.com/1178106",
-            sdk_is_greater_than = Build.VERSION_CODES.LOLLIPOP_MR1,
-            sdk_is_less_than = Build.VERSION_CODES.N)
-    public void
-    testModuleJavaResourceLoading() {
+    public void testModuleJavaResourceLoading() {
         runTestActivity(2); // Test case LOAD_JAVA_RESOURCE.
     }
 
     @Test
-    @DisableIf.Build(message = "Flaky on Android Marshmallow, see crbug.com/1178106",
-            sdk_is_greater_than = Build.VERSION_CODES.LOLLIPOP_MR1,
-            sdk_is_less_than = Build.VERSION_CODES.N)
-    public void
-    testModuleNativeResourceLoading() {
+    public void testModuleNativeResourceLoading() {
         runTestActivity(3); // Test case LOAD_NATIVE_RESOURCE.
     }
 }
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 225ad70..261769d5 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -3539,9 +3539,15 @@
   <message name="IDS_ARC_OOBE_TERMS_HEADING" desc="Heading of the Arc Terms OOBE dialog.">
     Google Play apps and services
   </message>
+  <message name="IDS_ARC_OOBE_TERMS_HEADING_CHILD" desc="Heading of the Arc Terms OOBE dialog, when a child account is in use.">
+    Review Google Play apps and services
+  </message>
   <message name="IDS_ARC_OOBE_TERMS_DESCRIPTION" desc="Description of the Arc Terms OOBE dialog.">
     Use Google Play to install Android apps
   </message>
+  <message name="IDS_ARC_OOBE_TERMS_DESCRIPTION_CHILD" desc="Description of the Arc Terms OOBE dialog, when a child account is in use.">
+    With your permission, your child can use Google Play to install apps
+  </message>
   <message name="IDS_ARC_OOBE_TERMS_LOADING" desc="Loading message of the Arc Terms OOBE dialog.">
     Loading...
   </message>
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_OOBE_TERMS_DESCRIPTION_CHILD.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_ARC_OOBE_TERMS_DESCRIPTION_CHILD.png.sha1
new file mode 100644
index 0000000..911f482f
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_ARC_OOBE_TERMS_DESCRIPTION_CHILD.png.sha1
@@ -0,0 +1 @@
+b144c1fbf4f55db93b3b8dbb2eb9f137aca464d6
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ARC_OOBE_TERMS_HEADING_CHILD.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_ARC_OOBE_TERMS_HEADING_CHILD.png.sha1
new file mode 100644
index 0000000..911f482f
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_ARC_OOBE_TERMS_HEADING_CHILD.png.sha1
@@ -0,0 +1 @@
+b144c1fbf4f55db93b3b8dbb2eb9f137aca464d6
\ No newline at end of file
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 024321c..e2874e6 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -272,7 +272,7 @@
   <message name="IDS_SETTINGS_AUTOFILL_ADDRESSES_EMAIL" desc="This is the label for the field that lets a user modify the email address that will be used when auto-filling forms on the web.">
     Email
   </message>
-  <message name="IDS_SETTINGS_AUTOFILL_ADDRESS_HONORIFIC_LABEL" desc="This is the label for the field that lets the user modify their honorific for an address. A honorific is an optional, title like Mr, Dr, etc, which can accompany one's name.">
+  <message name="IDS_SETTINGS_AUTOFILL_ADDRESS_HONORIFIC_LABEL" desc="This is the label for the field that lets the user modify the title that will be used when auto-filling forms on the web. A 'Title' field in a web form could be a prefix like Ms., Mx., or Dr. or a position held, like Captain or Rabbi." meaning="Honorific">
     Title
   </message>
   <message name="IDS_SETTINGS_AUTOFILL_CREDIT_CARD_TYPE_COLUMN_LABEL" desc="Label for the column containing the type of credit card that is saved. The type is in the format: `Visa ****1234`.">
diff --git a/chrome/app/vector_icons/BUILD.gn b/chrome/app/vector_icons/BUILD.gn
index be2d68c..9418ca1 100644
--- a/chrome/app/vector_icons/BUILD.gn
+++ b/chrome/app/vector_icons/BUILD.gn
@@ -61,7 +61,6 @@
     "incognito_profile.icon",
     "input.icon",
     "key.icon",
-    "key_crossed.icon",
     "keyboard_arrow_down.icon",
     "keyboard_arrow_right.icon",
     "keyboard_arrow_up.icon",
diff --git a/chrome/app/vector_icons/key_crossed.icon b/chrome/app/vector_icons/key_crossed.icon
deleted file mode 100644
index 8733381..0000000
--- a/chrome/app/vector_icons/key_crossed.icon
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2021 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.
-
-CANVAS_DIMENSIONS, 32,
-CIRCLE, 16, 16, 16,
-MOVE_TO, 17.42f, 12,
-H_LINE_TO, 30,
-R_V_LINE_TO, 5,
-R_H_LINE_TO, -2,
-R_V_LINE_TO, 5,
-R_H_LINE_TO, -4,
-R_V_LINE_TO, -5,
-R_H_LINE_TO, -6.25f,
-CUBIC_TO, 16.86f, 20.45f, 13.73f, 23, 10, 23,
-R_CUBIC_TO, -4.42f, 0, -8, -3.58f, -8, -8,
-R_CUBIC_TO, 0, -4.42f, 3.58f, -8, 8, -8,
-R_CUBIC_TO, 3.36f, 0, 6.23f, 2.07f, 7.42f, 5,
-CLOSE,
-MOVE_TO, 10, 18,
-R_CUBIC_TO, 1.66f, 0, 3, -1.34f, 3, -3,
-R_CUBIC_TO, 0, -1.66f, -1.34f, -3, -3, -3,
-R_CUBIC_TO, -1.66f, 0, -3, 1.34f, -3, 3,
-R_CUBIC_TO, 0, 1.66f, 1.34f, 3, 3, 3,
-CLOSE,
-LINE_TO, 24.78f, 28.18f,
-LINE_TO, 26.46f, 26.5f,
-LINE_TO, 5.52f, 5.52f,
-LINE_TO, 3.82f, 7.22f,
-CLOSE
-
-CANVAS_DIMENSIONS, 16,
-CIRCLE, 8, 8, 8,
-MOVE_TO, 8.41f, 6,
-CUBIC_TO, 7.89f, 4.44f, 6.48f, 3.33f, 4.82f, 3.33f,
-CUBIC_TO, 2.71f, 3.33f, 1, 5.12f, 1, 7.33f,
-CUBIC_TO, 1, 9.54f, 2.71f, 11.33f, 4.82f, 11.33f,
-CUBIC_TO, 6.48f, 11.33f, 7.89f, 10.22f, 8.41f, 8.66f,
-LINE_TO, 11.18f, 8.66f,
-LINE_TO, 11.18f, 11.33f,
-LINE_TO, 13.73f, 11.33f,
-LINE_TO, 13.73f, 8.66f,
-LINE_TO, 15, 8.66f,
-LINE_TO, 15, 6,
-LINE_TO, 8.41f, 6,
-CLOSE,
-MOVE_TO, 4.82f, 8.67f,
-CUBIC_TO, 4.12f, 8.67f, 3.55f, 8.08f, 3.55f, 7.34f,
-CUBIC_TO, 3.55f, 6.6f, 4.12f, 6.01f, 4.82f, 6.01f,
-CUBIC_TO, 5.52f, 6.01f, 6.09f, 6.6f, 6.09f, 7.34f,
-CUBIC_TO, 6.09f, 8.08f, 5.52f, 8.67f, 4.82f, 8.67f,
-CLOSE,
-LINE_TO, 12.39f, 14.09f,
-LINE_TO, 13.23f, 13.25f,
-LINE_TO, 2.76f, 2.76f,
-LINE_TO, 1.91f, 3.61f,
-CLOSE
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 6a53ea8..67b4993 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3451,6 +3451,9 @@
      FEATURE_WITH_PARAMS_VALUE_TYPE(content_creation::kWebNotesStylizeEnabled,
                                     kWebNoteStylizeVariations,
                                     "WebNotesStylize")},
+    {"sharing-hub-link-toggle", flag_descriptions::kSharingHubLinkToggleName,
+     flag_descriptions::kSharingHubLinkToggleDescription, kOsAndroid,
+     FEATURE_VALUE_TYPE(chrome::android::kSharingHubLinkToggle)},
 #endif  // OS_ANDROID
     {"in-product-help-demo-mode-choice",
      flag_descriptions::kInProductHelpDemoModeChoiceName,
@@ -7449,10 +7452,6 @@
      FEATURE_VALUE_TYPE(ash::features::kBorealisDiskManagement)},
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-    {"https-only-mode-setting", flag_descriptions::kHttpsOnlyModeName,
-     flag_descriptions::kHttpsOnlyModeDescription, kOsDesktop | kOsAndroid,
-     FEATURE_VALUE_TYPE(features::kHttpsOnlyMode)},
-
 #if defined(OS_ANDROID)
     {"dynamic-color-android", flag_descriptions::kDynamicColorAndroidName,
      flag_descriptions::kDynamicColorAndroidDescription, kOsAndroid,
diff --git a/chrome/browser/ash/customization/customization_document.cc b/chrome/browser/ash/customization/customization_document.cc
index a01cce4..bea9e25 100644
--- a/chrome/browser/ash/customization/customization_document.cc
+++ b/chrome/browser/ash/customization/customization_document.cc
@@ -51,6 +51,7 @@
 #include "net/base/load_flags.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_status_code.h"
+#include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/simple_url_loader.h"
 
diff --git a/chrome/browser/ash/dbus/ash_dbus_helper.cc b/chrome/browser/ash/dbus/ash_dbus_helper.cc
index 10f744ed..a81de804 100644
--- a/chrome/browser/ash/dbus/ash_dbus_helper.cc
+++ b/chrome/browser/ash/dbus/ash_dbus_helper.cc
@@ -89,7 +89,7 @@
   chromeos::SystemSaltGetter::Initialize();
 
   // Initialize DBusThreadManager for the browser.
-  chromeos::DBusThreadManager::Initialize(DBusThreadManager::kAll);
+  chromeos::DBusThreadManager::Initialize();
 
   // Initialize Chrome dbus clients.
   dbus::Bus* bus = chromeos::DBusThreadManager::Get()->GetSystemBus();
diff --git a/chrome/browser/ash/dbus/dlp_files_policy_service_provider.cc b/chrome/browser/ash/dbus/dlp_files_policy_service_provider.cc
index 6da1a91..dfd9d0e55 100644
--- a/chrome/browser/ash/dbus/dlp_files_policy_service_provider.cc
+++ b/chrome/browser/ash/dbus/dlp_files_policy_service_provider.cc
@@ -120,9 +120,10 @@
   policy::DlpRulesManager* dlp_rules_manager =
       policy::DlpRulesManagerFactory::GetForPrimaryProfile();
   if (dlp_rules_manager) {
-    policy::DlpRulesManager::Level level = dlp_rules_manager->IsRestricted(
-        GURL(request.source_url()),
-        policy::DlpRulesManager::Restriction::kFiles);
+    policy::DlpRulesManager::Level level =
+        dlp_rules_manager->IsRestrictedByAnyRule(
+            GURL(request.source_url()),
+            policy::DlpRulesManager::Restriction::kFiles);
     if (level == policy::DlpRulesManager::Level::kBlock)
       restricted = true;
   }
diff --git a/chrome/browser/ash/login/session/user_session_manager.cc b/chrome/browser/ash/login/session/user_session_manager.cc
index 936dba00..bcfa22d3 100644
--- a/chrome/browser/ash/login/session/user_session_manager.cc
+++ b/chrome/browser/ash/login/session/user_session_manager.cc
@@ -620,6 +620,10 @@
     // TODO(nkostylev): Fix this hack by improving Authenticator dependencies.
     authenticator_->SetConsumer(consumer);
   }
+
+  for (auto& observer : authenticator_observer_list_) {
+    observer.OnAuthAttemptStarted();
+  }
   return authenticator_;
 }
 
@@ -966,6 +970,16 @@
   session_state_observer_list_.RemoveObserver(observer);
 }
 
+void UserSessionManager::AddUserAuthenticatorObserver(
+    ash::UserAuthenticatorObserver* observer) {
+  authenticator_observer_list_.AddObserver(observer);
+}
+
+void UserSessionManager::RemoveUserAuthenticatorObserver(
+    ash::UserAuthenticatorObserver* observer) {
+  authenticator_observer_list_.RemoveObserver(observer);
+}
+
 void UserSessionManager::OnSessionRestoreStateChanged(
     Profile* user_profile,
     OAuth2LoginManager::SessionRestoreState state) {
diff --git a/chrome/browser/ash/login/session/user_session_manager.h b/chrome/browser/ash/login/session/user_session_manager.h
index 9fdcc5b..816045d 100644
--- a/chrome/browser/ash/login/session/user_session_manager.h
+++ b/chrome/browser/ash/login/session/user_session_manager.h
@@ -92,6 +92,12 @@
   virtual ~UserSessionStateObserver();
 };
 
+class UserAuthenticatorObserver : public base::CheckedObserver {
+ public:
+  // Called when authentication is started.
+  virtual void OnAuthAttemptStarted() {}
+};
+
 // UserSessionManager is responsible for starting user session which includes:
 // * load and initialize Profile (including custom Profile preferences),
 // * mark user as logged in and notify observers,
@@ -276,6 +282,10 @@
   void AddSessionStateObserver(ash::UserSessionStateObserver* observer);
   void RemoveSessionStateObserver(ash::UserSessionStateObserver* observer);
 
+  void AddUserAuthenticatorObserver(ash::UserAuthenticatorObserver* observer);
+  void RemoveUserAuthenticatorObserver(
+      ash::UserAuthenticatorObserver* observer);
+
   void ActiveUserChanged(user_manager::User* active_user) override;
 
   // Returns default IME state for user session.
@@ -588,6 +598,9 @@
   base::ObserverList<ash::UserSessionStateObserver>::Unchecked
       session_state_observer_list_;
 
+  base::ObserverList<ash::UserAuthenticatorObserver>
+      authenticator_observer_list_;
+
   // Set of user_id for those users that we should restore authentication
   // session when notified about online state change.
   SigninSessionRestoreStateSet pending_signin_restore_sessions_;
diff --git a/chrome/browser/ash/policy/dlp/dlp_rules_manager.h b/chrome/browser/ash/policy/dlp/dlp_rules_manager.h
index 7bbfb9a..e782018 100644
--- a/chrome/browser/ash/policy/dlp/dlp_rules_manager.h
+++ b/chrome/browser/ash/policy/dlp/dlp_rules_manager.h
@@ -72,6 +72,12 @@
   virtual Level IsRestricted(const GURL& source,
                              Restriction restriction) const = 0;
 
+  // Returns the highest possible restriction enforcement level for
+  // 'restriction' given that data comes from 'source' and the destination might
+  // be any. ALLOW level rules are ignored.
+  virtual Level IsRestrictedByAnyRule(const GURL& source,
+                                      Restriction restriction) const = 0;
+
   // Returns the enforcement level for `restriction` given that data comes
   // from `source` and requested to be shared to `destination`. ALLOW is
   // returned if there is no matching rule. Requires `restriction` to be
diff --git a/chrome/browser/ash/policy/dlp/dlp_rules_manager_impl.cc b/chrome/browser/ash/policy/dlp/dlp_rules_manager_impl.cc
index 5df9ec9..59a26b01 100644
--- a/chrome/browser/ash/policy/dlp/dlp_rules_manager_impl.cc
+++ b/chrome/browser/ash/policy/dlp/dlp_rules_manager_impl.cc
@@ -143,8 +143,8 @@
     const DlpRulesManager::Restriction restriction,
     const std::map<RuleId, T>& selected_rules,
     const std::map<DlpRulesManager::Restriction,
-                   std::map<RuleId, DlpRulesManager::Level>>&
-        restrictions_map) {
+                   std::map<RuleId, DlpRulesManager::Level>>& restrictions_map,
+    const bool ignore_allow = false) {
   auto restriction_it = restrictions_map.find(restriction);
   if (restriction_it == restrictions_map.end())
     return std::make_pair(DlpRulesManager::Level::kAllow, absl::nullopt);
@@ -160,6 +160,10 @@
     if (restriction_rule_itr == restriction_rules.end()) {
       continue;
     }
+    if (ignore_allow &&
+        restriction_rule_itr->second == DlpRulesManager::Level::kAllow) {
+      continue;
+    }
     if (restriction_rule_itr->second > max_level.first) {
       max_level.first = restriction_rule_itr->second;
       max_level.second = rule_pair.second;
@@ -219,6 +223,19 @@
       .first;
 }
 
+DlpRulesManager::Level DlpRulesManagerImpl::IsRestrictedByAnyRule(
+    const GURL& source,
+    Restriction restriction) const {
+  DCHECK(src_url_matcher_);
+
+  const RulesConditionsMap src_rules_map = MatchUrlAndGetRulesMapping(
+      source, src_url_matcher_.get(), src_url_rules_mapping_);
+
+  return GetMaxJoinRestrictionLevel(restriction, src_rules_map,
+                                    restrictions_map_, /*ignore_allow=*/true)
+      .first;
+}
+
 DlpRulesManager::Level DlpRulesManagerImpl::IsRestrictedDestination(
     const GURL& source,
     const GURL& destination,
diff --git a/chrome/browser/ash/policy/dlp/dlp_rules_manager_impl.h b/chrome/browser/ash/policy/dlp/dlp_rules_manager_impl.h
index add659bc..b49b3ed 100644
--- a/chrome/browser/ash/policy/dlp/dlp_rules_manager_impl.h
+++ b/chrome/browser/ash/policy/dlp/dlp_rules_manager_impl.h
@@ -34,6 +34,8 @@
   // DlpRulesManager:
   Level IsRestricted(const GURL& source,
                      Restriction restriction) const override;
+  Level IsRestrictedByAnyRule(const GURL& source,
+                              Restriction restriction) const override;
   Level IsRestrictedDestination(
       const GURL& source,
       const GURL& destination,
diff --git a/chrome/browser/ash/policy/dlp/dlp_rules_manager_impl_unittest.cc b/chrome/browser/ash/policy/dlp/dlp_rules_manager_impl_unittest.cc
index 629218f..74bed70 100644
--- a/chrome/browser/ash/policy/dlp/dlp_rules_manager_impl_unittest.cc
+++ b/chrome/browser/ash/policy/dlp/dlp_rules_manager_impl_unittest.cc
@@ -148,6 +148,9 @@
   EXPECT_EQ(DlpRulesManager::Level::kBlock,
             dlp_rules_manager_.IsRestricted(
                 GURL(kExampleUrl), DlpRulesManager::Restriction::kScreenshot));
+  EXPECT_EQ(DlpRulesManager::Level::kBlock,
+            dlp_rules_manager_.IsRestrictedByAnyRule(
+                GURL(kExampleUrl), DlpRulesManager::Restriction::kClipboard));
   histogram_tester_.ExpectUniqueSample(
       GetDlpHistogramPrefix() + dlp::kDlpPolicyPresentUMA, true, 1);
   histogram_tester_.ExpectBucketCount("Enterprise.Dlp.RestrictionConfigured",
diff --git a/chrome/browser/ash/policy/dlp/mock_dlp_rules_manager.h b/chrome/browser/ash/policy/dlp/mock_dlp_rules_manager.h
index f0ed747..a1da57d 100644
--- a/chrome/browser/ash/policy/dlp/mock_dlp_rules_manager.h
+++ b/chrome/browser/ash/policy/dlp/mock_dlp_rules_manager.h
@@ -18,6 +18,9 @@
   MOCK_CONST_METHOD2(IsRestricted,
                      Level(const GURL& source, Restriction restriction));
 
+  MOCK_CONST_METHOD2(IsRestrictedByAnyRule,
+                     Level(const GURL& source, Restriction restriction));
+
   MOCK_CONST_METHOD5(IsRestrictedDestination,
                      Level(const GURL& source,
                            const GURL& destination,
diff --git a/chrome/browser/browser_switcher/browser_switcher_prefs.h b/chrome/browser/browser_switcher/browser_switcher_prefs.h
index 8ac4729..c6ce08b 100644
--- a/chrome/browser/browser_switcher/browser_switcher_prefs.h
+++ b/chrome/browser/browser_switcher/browser_switcher_prefs.h
@@ -42,8 +42,8 @@
 // values in policy_templates.json.
 enum class ParsingMode {
   kDefault = 0,
-  kStrict = 1,
-  kMaxValue = kStrict,  // Always keep up-to-date.
+  kIESiteListMode = 1,
+  kMaxValue = kIESiteListMode,  // Always keep up-to-date.
 };
 
 // Contains the current state of the prefs related to LBS. For sensitive prefs,
diff --git a/chrome/browser/browser_switcher/browser_switcher_sitelist.cc b/chrome/browser/browser_switcher/browser_switcher_sitelist.cc
index 81dced4b..a2b0ec2 100644
--- a/chrome/browser/browser_switcher/browser_switcher_sitelist.cc
+++ b/chrome/browser/browser_switcher/browser_switcher_sitelist.cc
@@ -36,16 +36,35 @@
   base::StringPiece spec_without_port;
 };
 
-// Returns true if |input| contains |token|, ignoring case for ASCII
-// characters.
-bool StringContainsInsensitiveASCII(base::StringPiece input,
-                                    base::StringPiece token) {
-  const char* found =
-      std::search(input.begin(), input.end(), token.begin(), token.end(),
-                  [](char a, char b) {
-                    return base::ToLowerASCII(a) == base::ToLowerASCII(b);
-                  });
-  return found != input.end();
+// Find the position of |token| inside |input|, if present. Ignore case for
+// ASCII characters.
+//
+// If |token| is not in |input|, return a pointer to the null-byte at the end
+// of |input|.
+const char* StringFindInsensitiveASCII(base::StringPiece input,
+                                       base::StringPiece token) {
+  return std::search(input.begin(), input.end(), token.begin(), token.end(),
+                     [](char a, char b) {
+                       return base::ToLowerASCII(a) == base::ToLowerASCII(b);
+                     });
+}
+
+// Find the position of |token| inside |input|, much like StringPiece::find().
+// Search case-sensitively if |case_sensitive_ascii| is true, or
+// case-insensitively otherwise.
+//
+// Returns StringPiece::npos if not found.
+size_t StringFind(base::StringPiece input,
+                  base::StringPiece token,
+                  bool case_sensitive_ascii) {
+  if (case_sensitive_ascii) {
+    return input.find(token);
+  } else {
+    const char* pos = StringFindInsensitiveASCII(input, token);
+    if (pos == input.end())
+      return base::StringPiece::npos;
+    return pos - input.data();
+  }
 }
 
 // Case-insensitively compare the hostname of |host_and_port| with the hostname
@@ -100,15 +119,16 @@
     return true;
   }
   if (pattern.find('/') != base::StringPiece::npos) {
-    // Check prefix using the normalized URL. Case sensitive, but with
-    // case-insensitive scheme/hostname.
-    size_t pos = url.spec.find(pattern);
+    // Check that the prefix is valid. The URL's hostname/scheme have already
+    // been case-normalized, so that part of the URL is always case-insensitive.
+    bool case_sensitive = parsing_mode == ParsingMode::kDefault;
+    size_t pos = StringFind(url.spec, pattern, case_sensitive);
     if (pos != base::StringPiece::npos &&
         IsValidPrefix(base::StringPiece(url.spec.data(), pos))) {
       return true;
     }
     if (!url.spec_without_port.empty()) {
-      pos = url.spec_without_port.find(pattern);
+      pos = StringFind(url.spec_without_port, pattern, case_sensitive);
       return pos != base::StringPiece::npos &&
              IsValidPrefix(
                  base::StringPiece(url.spec_without_port.data(), pos));
@@ -118,12 +138,14 @@
 
   // Compare hosts and ports, case-insensitive.
   switch (parsing_mode) {
-    case ParsingMode::kStrict:
+    case ParsingMode::kIESiteListMode:
       return MatchesHostNameAtEnd(url.host_and_port, pattern);
 
-    case ParsingMode::kDefault:
+    case ParsingMode::kDefault: {
       // Simple substring search.
-      return StringContainsInsensitiveASCII(url.host_and_port, pattern);
+      const char* it = StringFindInsensitiveASCII(url.host_and_port, pattern);
+      return it != url.host_and_port.end();
+    }
 
     default:
       // This should've been caught in
diff --git a/chrome/browser/browser_switcher/browser_switcher_sitelist_unittest.cc b/chrome/browser/browser_switcher/browser_switcher_sitelist_unittest.cc
index 511e747..7f9fa63 100644
--- a/chrome/browser/browser_switcher/browser_switcher_sitelist_unittest.cc
+++ b/chrome/browser/browser_switcher/browser_switcher_sitelist_unittest.cc
@@ -134,7 +134,7 @@
 
   // For backwards compatibility, this should also match, even if it's not the
   // same host.
-  EXPECT_EQ(parsing_mode() != ParsingMode::kStrict,
+  EXPECT_EQ(parsing_mode() != ParsingMode::kIESiteListMode,
             ShouldSwitch(GURL("https://notexample.com/")));
 }
 
@@ -159,7 +159,8 @@
   EXPECT_TRUE(ShouldSwitch(GURL("http://example.com/foobar?query=param")));
   EXPECT_FALSE(ShouldSwitch(GURL("http://example.com/")));
   EXPECT_FALSE(ShouldSwitch(GURL("https://example.com/foobar")));
-  EXPECT_FALSE(ShouldSwitch(GURL("HTTP://EXAMPLE.COM/FOOBAR")));
+  EXPECT_EQ(parsing_mode() == ParsingMode::kIESiteListMode,
+            ShouldSwitch(GURL("HTTP://EXAMPLE.COM/FOOBAR")));
   EXPECT_FALSE(ShouldSwitch(GURL("http://subdomain.example.com/")));
   EXPECT_FALSE(ShouldSwitch(GURL("http://google.com/")));
 }
@@ -220,11 +221,11 @@
   // A hostname rule (no "/") can match at the beginning of the hostname, not
   // just at the end.
   Initialize({"10.", "subdomain"}, {});
-  EXPECT_EQ(parsing_mode() == ParsingMode::kStrict
+  EXPECT_EQ(parsing_mode() == ParsingMode::kIESiteListMode
                 ? Decision(kStay, kDefault, "")
                 : Decision(kGo, kSitelist, "10."),
             GetDecision(GURL("http://10.0.0.1/")));
-  EXPECT_EQ(parsing_mode() == ParsingMode::kStrict
+  EXPECT_EQ(parsing_mode() == ParsingMode::kIESiteListMode
                 ? Decision(kStay, kDefault, "")
                 : Decision(kGo, kSitelist, "subdomain"),
             GetDecision(GURL("http://subdomain.example.com/")));
@@ -330,7 +331,7 @@
 INSTANTIATE_TEST_SUITE_P(ParsingMode,
                          BrowserSwitcherSitelistTest,
                          testing::Values(ParsingMode::kDefault,
-                                         ParsingMode::kStrict,
+                                         ParsingMode::kIESiteListMode,
                                          // 999 should behave like kDefault
                                          static_cast<ParsingMode>(999)));
 
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
index 31404dc0..070745d3 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -888,9 +888,13 @@
             .get();
 
     if (password_store) {
-      password_store->RemoveStatisticsByOriginAndTime(
-          nullable_filter, delete_begin_, delete_end_,
-          CreateTaskCompletionClosure(TracingDataType::kPasswordsStatistics));
+      password_manager::SmartBubbleStatsStore* stats_store =
+          password_store->GetSmartBubbleStatsStore();
+      if (stats_store) {
+        stats_store->RemoveStatisticsByOriginAndTime(
+            nullable_filter, delete_begin_, delete_end_,
+            CreateTaskCompletionClosure(TracingDataType::kPasswordsStatistics));
+      }
       password_store->RemoveFieldInfoByTime(
           delete_begin_, delete_end_,
           CreateTaskCompletionClosure(TracingDataType::kFieldInfo));
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
index 0f388a1..562fa0b 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -1166,6 +1166,30 @@
     return completion_observer.failed_data_types();
   }
 
+  void ExpectRemoveLoginsByURLAndTime(
+      password_manager::MockPasswordStore* store) {
+    EXPECT_CALL(*store, RemoveLoginsByURLAndTime)
+        .WillOnce(
+            testing::WithArgs<3, 4>([](auto callback, auto sync_callback) {
+              std::move(callback).Run();
+              if (sync_callback)
+                std::move(sync_callback).Run(false);
+            }));
+  }
+
+  void ExpectRemoveLoginsByURLAndTimeWithFilter(
+      password_manager::MockPasswordStore* store,
+      base::RepeatingCallback<bool(const GURL&)> filter) {
+    EXPECT_CALL(*store, RemoveLoginsByURLAndTime(ProbablySameFilter(filter), _,
+                                                 _, _, _))
+        .WillOnce(
+            testing::WithArgs<3, 4>([](auto callback, auto sync_callback) {
+              std::move(callback).Run();
+              if (sync_callback)
+                std::move(sync_callback).Run(false);
+            }));
+  }
+
   void BlockUntilOriginDataRemoved(
       const base::Time& delete_begin,
       const base::Time& delete_end,
@@ -1418,7 +1442,7 @@
   // Expect that passwords will be deleted, as they do not depend
   // on |prefs::kAllowDeletingBrowserHistory|.
   RemovePasswordsTester tester(GetProfile());
-  EXPECT_CALL(*tester.profile_store(), RemoveLoginsByURLAndTimeImpl(_, _, _));
+  ExpectRemoveLoginsByURLAndTime(tester.profile_store());
 
   uint64_t removal_mask =
       constants::DATA_TYPE_HISTORY | constants::DATA_TYPE_PASSWORDS;
@@ -1991,12 +2015,8 @@
 
 TEST_F(ChromeBrowsingDataRemoverDelegateTest, RemovePasswordsByTimeOnly) {
   RemovePasswordsTester tester(GetProfile());
-  base::RepeatingCallback<bool(const GURL&)> filter =
-      BrowsingDataFilterBuilder::BuildNoopFilter();
 
-  EXPECT_CALL(*tester.profile_store(),
-              RemoveLoginsByURLAndTimeImpl(ProbablySameFilter(filter), _, _))
-      .WillOnce(Return(password_manager::PasswordStoreChangeList()));
+  ExpectRemoveLoginsByURLAndTime(tester.profile_store());
 
   BlockUntilBrowsingDataRemoved(base::Time(), base::Time::Max(),
                                 constants::DATA_TYPE_PASSWORDS, false);
@@ -2012,9 +2032,7 @@
   builder->AddRegisterableDomain(kTestRegisterableDomain1);
   base::RepeatingCallback<bool(const GURL&)> filter = builder->BuildUrlFilter();
 
-  EXPECT_CALL(*tester.profile_store(),
-              RemoveLoginsByURLAndTimeImpl(ProbablySameFilter(filter), _, _))
-      .WillOnce(Return(password_manager::PasswordStoreChangeList()));
+  ExpectRemoveLoginsByURLAndTimeWithFilter(tester.profile_store(), filter);
   BlockUntilOriginDataRemoved(base::Time(), base::Time::Max(),
                               constants::DATA_TYPE_PASSWORDS,
                               std::move(builder));
@@ -2040,8 +2058,7 @@
   base::RepeatingCallback<bool(const GURL&)> empty_filter =
       BrowsingDataFilterBuilder::BuildNoopFilter();
 
-  EXPECT_CALL(*tester.profile_store(), RemoveLoginsByURLAndTimeImpl(_, _, _))
-      .WillOnce(Return(password_manager::PasswordStoreChangeList()));
+  ExpectRemoveLoginsByURLAndTime(tester.profile_store());
   EXPECT_CALL(*tester.profile_store(),
               DisableAutoSignInForOriginsImpl(ProbablySameFilter(empty_filter)))
       .WillOnce(Return(password_manager::PasswordStoreChangeList()));
@@ -3081,12 +3098,9 @@
        RemovePasswordsByTimeOnly_WithAccountStore) {
   RemovePasswordsTester tester(GetProfile());
 
-  EXPECT_CALL(*tester.profile_store(), RemoveLoginsByURLAndTimeImpl(_, _, _))
-      .WillOnce(Return(password_manager::PasswordStoreChangeList()));
-
+  ExpectRemoveLoginsByURLAndTime(tester.profile_store());
   // Only DATA_TYPE_PASSWORDS is cleared. Accounts passwords are not affected.
-  EXPECT_CALL(*tester.account_store(), RemoveLoginsByURLAndTimeImpl(_, _, _))
-      .Times(0);
+  EXPECT_CALL(*tester.account_store(), RemoveLoginsByURLAndTime).Times(0);
 
   BlockUntilBrowsingDataRemoved(base::Time(), base::Time::Max(),
                                 constants::DATA_TYPE_PASSWORDS, false);
@@ -3096,11 +3110,8 @@
        RemoveAccountPasswordsByTimeOnly_WithAccountStore) {
   RemovePasswordsTester tester(GetProfile());
 
-  EXPECT_CALL(*tester.profile_store(), RemoveLoginsByURLAndTimeImpl(_, _, _))
-      .Times(0);
-
-  EXPECT_CALL(*tester.account_store(), RemoveLoginsByURLAndTimeImpl(_, _, _))
-      .WillOnce(Return(password_manager::PasswordStoreChangeList()));
+  EXPECT_CALL(*tester.profile_store(), RemoveLoginsByURLAndTime).Times(0);
+  ExpectRemoveLoginsByURLAndTime(tester.account_store());
   // For the account store, the remover delegate also waits until all the
   // deletions have propagated to the Sync server. Pretend that happens
   // immediately.
@@ -3115,19 +3126,13 @@
        RemoveAccountPasswordsByTimeOnly_WithAccountStore_Failure) {
   RemovePasswordsTester tester(GetProfile());
 
-  EXPECT_CALL(*tester.profile_store(), RemoveLoginsByURLAndTimeImpl(_, _, _))
-      .Times(0);
-
-  EXPECT_CALL(*tester.account_store(), RemoveLoginsByURLAndTimeImpl(_, _, _))
-      .WillOnce(Return(password_manager::PasswordStoreChangeList()));
+  EXPECT_CALL(*tester.profile_store(), RemoveLoginsByURLAndTime).Times(0);
+  ExpectRemoveLoginsByURLAndTime(tester.account_store());
   // For the account store, the remover delegate also waits until all the
   // deletions have propagated to the Sync server. In this test, that never
   // happens.
   EXPECT_CALL(*tester.account_metadata_store(), HasUnsyncedDeletions())
       .WillRepeatedly(Return(true));
-  // Bypass the (usually 30-second) timeout until the PasswordStore reports
-  // failure.
-  tester.account_store()->SetSyncTaskTimeoutForTest(base::TimeDelta());
 
   uint64_t failed_data_types = BlockUntilBrowsingDataRemoved(
       base::Time(), base::Time::Max(), constants::DATA_TYPE_ACCOUNT_PASSWORDS,
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 7b8c65164..59e2665 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -2943,8 +2943,6 @@
     "policy/server_backed_state/server_backed_state_keys_broker.h",
     "policy/status_collector/activity_storage.cc",
     "policy/status_collector/activity_storage.h",
-    "policy/status_collector/affiliated_session_service.cc",
-    "policy/status_collector/affiliated_session_service.h",
     "policy/status_collector/app_info_generator.cc",
     "policy/status_collector/app_info_generator.h",
     "policy/status_collector/child_activity_storage.cc",
@@ -2956,6 +2954,8 @@
     "policy/status_collector/enterprise_activity_storage.cc",
     "policy/status_collector/enterprise_activity_storage.h",
     "policy/status_collector/interval_map.h",
+    "policy/status_collector/managed_session_service.cc",
+    "policy/status_collector/managed_session_service.h",
     "policy/status_collector/status_collector.cc",
     "policy/status_collector/status_collector.h",
     "policy/status_collector/status_collector_state.cc",
@@ -4236,10 +4236,10 @@
     "policy/server_backed_state/device_cloud_state_keys_uploader_unittest.cc",
     "policy/server_backed_state/server_backed_state_keys_broker_unittest.cc",
     "policy/status_collector/activity_storage_unittest.cc",
-    "policy/status_collector/affiliated_session_service_unittest.cc",
     "policy/status_collector/app_info_generator_unittest.cc",
     "policy/status_collector/enterprise_activity_storage_unittest.cc",
     "policy/status_collector/interval_map_unittest.cc",
+    "policy/status_collector/managed_session_service_unittest.cc",
     "policy/uploading/heartbeat_scheduler_unittest.cc",
     "policy/uploading/status_uploader_unittest.cc",
     "policy/uploading/system_log_uploader_unittest.cc",
diff --git a/chrome/browser/chromeos/extensions/accessibility_features_apitest.cc b/chrome/browser/chromeos/extensions/accessibility_features_apitest.cc
index 57c0419..cbe5f8e 100644
--- a/chrome/browser/chromeos/extensions/accessibility_features_apitest.cc
+++ b/chrome/browser/chromeos/extensions/accessibility_features_apitest.cc
@@ -271,9 +271,7 @@
 
 // Tests that an extension with modify permission can modify accessibility
 // features, while an extension that doesn't have the permission can't.
-//
-// Disabled for being flaky (https://crbug.com/1225390).
-IN_PROC_BROWSER_TEST_P(AccessibilityFeaturesApiTest, DISABLED_Set) {
+IN_PROC_BROWSER_TEST_P(AccessibilityFeaturesApiTest, Set) {
   // WARNING: Make sure that features which load Chrome extension are not
   // enabled at this point (before the test app is loaded), as that may break
   // the test:
diff --git a/chrome/browser/chromeos/full_restore/full_restore_app_launch_handler_browsertest.cc b/chrome/browser/chromeos/full_restore/full_restore_app_launch_handler_browsertest.cc
index 924287d7..ab25997 100644
--- a/chrome/browser/chromeos/full_restore/full_restore_app_launch_handler_browsertest.cc
+++ b/chrome/browser/chromeos/full_restore/full_restore_app_launch_handler_browsertest.cc
@@ -199,17 +199,6 @@
   ::full_restore::SaveWindowInfo(window_info);
 }
 
-void WaitForAppLaunchInfoSaved() {
-  ::full_restore::FullRestoreSaveHandler* save_handler =
-      ::full_restore::FullRestoreSaveHandler::GetInstance();
-  base::OneShotTimer* timer = save_handler->GetTimerForTesting();
-  if (timer->IsRunning()) {
-    // Simulate timeout, and the launch info is saved.
-    timer->FireNow();
-  }
-  content::RunAllTasksUntilIdle();
-}
-
 std::string GetTestApp1Id(const std::string& package_name) {
   return ArcAppListPrefs::GetAppId(package_name, kTestAppActivity);
 }
@@ -329,6 +318,20 @@
     return nullptr;
   }
 
+  void WaitForAppLaunchInfoSaved() {
+    ::full_restore::FullRestoreSaveHandler* save_handler =
+        ::full_restore::FullRestoreSaveHandler::GetInstance();
+    base::OneShotTimer* timer = save_handler->GetTimerForTesting();
+    if (timer->IsRunning()) {
+      // Simulate timeout, and the launch info is saved.
+      timer->FireNow();
+    }
+    content::RunAllTasksUntilIdle();
+
+    ::full_restore::FullRestoreReadHandler::GetInstance()
+        ->profile_path_to_restore_data_.clear();
+  }
+
   void SaveChromeAppLaunchInfo(const std::string& app_id) {
     ::full_restore::SaveAppLaunchInfo(
         profile()->GetPath(),
@@ -2142,6 +2145,20 @@
                               web_app::SystemAppType::MEDIA);
   }
 
+  void WaitForAppLaunchInfoSaved() {
+    ::full_restore::FullRestoreSaveHandler* save_handler =
+        ::full_restore::FullRestoreSaveHandler::GetInstance();
+    base::OneShotTimer* timer = save_handler->GetTimerForTesting();
+    if (timer->IsRunning()) {
+      // Simulate timeout, and the launch info is saved.
+      timer->FireNow();
+    }
+    content::RunAllTasksUntilIdle();
+
+    ::full_restore::FullRestoreReadHandler::GetInstance()
+        ->profile_path_to_restore_data_.clear();
+  }
+
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
 };
diff --git a/chrome/browser/chromeos/full_restore/full_restore_service_unittest.cc b/chrome/browser/chromeos/full_restore/full_restore_service_unittest.cc
index 5e70d0e..1429e62 100644
--- a/chrome/browser/chromeos/full_restore/full_restore_service_unittest.cc
+++ b/chrome/browser/chromeos/full_restore/full_restore_service_unittest.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/full_restore/full_restore_prefs.h"
 #include "chrome/browser/chromeos/full_restore/full_restore_service_factory.h"
+#include "chrome/browser/first_run/first_run.h"
 #include "chrome/browser/notifications/notification_display_service_tester.h"
 #include "chrome/browser/prefs/session_startup_pref.h"
 #include "chrome/common/chrome_switches.h"
@@ -21,8 +22,10 @@
 #include "components/full_restore/app_launch_info.h"
 #include "components/full_restore/features.h"
 #include "components/full_restore/full_restore_info.h"
+#include "components/full_restore/full_restore_read_handler.h"
 #include "components/full_restore/full_restore_save_handler.h"
 #include "components/full_restore/full_restore_utils.h"
+#include "components/full_restore/restore_data.h"
 #include "components/sync/base/client_tag_hash.h"
 #include "components/sync/base/model_type.h"
 #include "components/sync/model/sync_change.h"
@@ -243,6 +246,9 @@
     timer->FireNow();
 
     content::RunAllTasksUntilIdle();
+
+    ::full_restore::FullRestoreReadHandler::GetInstance()
+        ->profile_path_to_restore_data_.clear();
   }
 };
 
@@ -290,6 +296,7 @@
       kRestoreAppsAndPagesPrefName,
       static_cast<int>(RestoreOption::kAskEveryTime));
 
+  first_run::ResetCachedSentinelDataForTesting();
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       switches::kForceFirstRun);
 
@@ -298,6 +305,10 @@
   EXPECT_EQ(RestoreOption::kAskEveryTime, GetRestoreOption());
 
   VerifyNotification(false, false);
+
+  base::CommandLine::ForCurrentProcess()->RemoveSwitch(
+      switches::kForceFirstRun);
+  first_run::ResetCachedSentinelDataForTesting();
 }
 
 // For a brand new user, if sync off, set 'Ask Every Time' as the default value,
diff --git a/chrome/browser/chromeos/policy/status_collector/affiliated_session_service.cc b/chrome/browser/chromeos/policy/status_collector/affiliated_session_service.cc
deleted file mode 100644
index 5162988d..0000000
--- a/chrome/browser/chromeos/policy/status_collector/affiliated_session_service.cc
+++ /dev/null
@@ -1,104 +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.
-
-#include "chrome/browser/chromeos/policy/status_collector/affiliated_session_service.h"
-
-#include "base/logging.h"
-#include "chrome/browser/ash/profiles/profile_helper.h"
-
-namespace policy {
-
-namespace {
-
-constexpr base::TimeDelta kMinimumSuspendDuration =
-    base::TimeDelta::FromMinutes(1);
-
-bool IsPrimaryAndAffiliated(Profile* profile) {
-  user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
-  bool is_primary = chromeos::ProfileHelper::Get()->IsPrimaryProfile(profile);
-  bool is_affiliated = user && user->IsAffiliated();
-  if (!is_primary || !is_affiliated) {
-    VLOG(1) << "The profile for the primary user is not associated with an "
-               "affiliated user.";
-  }
-  return is_primary && is_affiliated;
-}
-
-}  // namespace
-
-AffiliatedSessionService::AffiliatedSessionService(base::Clock* clock)
-    : clock_(clock), session_manager_(session_manager::SessionManager::Get()) {
-  if (session_manager_) {
-    // To alleviate tight coupling in unit tests to DeviceStatusCollector.
-    session_manager_observation_.Observe(session_manager_);
-    is_session_locked_ = session_manager_->IsScreenLocked();
-  }
-  power_manager_observation_.Observe(chromeos::PowerManagerClient::Get());
-}
-
-AffiliatedSessionService::~AffiliatedSessionService() = default;
-
-void AffiliatedSessionService::AddObserver(
-    AffiliatedSessionService::Observer* observer) {
-  observers_.AddObserver(observer);
-}
-
-void AffiliatedSessionService::RemoveObserver(
-    AffiliatedSessionService::Observer* observer) {
-  observers_.RemoveObserver(observer);
-}
-
-void AffiliatedSessionService::OnSessionStateChanged() {
-  bool is_session_locked = session_manager_->IsScreenLocked();
-  if (is_session_locked_ == is_session_locked) {
-    return;
-  }
-  is_session_locked_ = is_session_locked;
-
-  if (is_session_locked_) {
-    for (auto& observer : observers_) {
-      observer.OnLocked();
-    }
-  } else {
-    for (auto& observer : observers_) {
-      observer.OnUnlocked();
-    }
-  }
-}
-
-void AffiliatedSessionService::OnUserProfileLoaded(
-    const AccountId& account_id) {
-  Profile* profile =
-      chromeos::ProfileHelper::Get()->GetProfileByAccountId(account_id);
-  if (!IsPrimaryAndAffiliated(profile)) {
-    return;
-  }
-  profile_observations_.AddObservation(profile);
-  for (auto& observer : observers_) {
-    observer.OnAffiliatedLogin(profile);
-  }
-}
-
-void AffiliatedSessionService::OnProfileWillBeDestroyed(Profile* profile) {
-  is_session_locked_ = false;
-  if (!IsPrimaryAndAffiliated(profile)) {
-    return;
-  }
-  for (auto& observer : observers_) {
-    observer.OnAffiliatedLogout(profile);
-  }
-  profile_observations_.RemoveObservation(profile);
-}
-
-void AffiliatedSessionService::SuspendDone(base::TimeDelta sleep_duration) {
-  if (sleep_duration < kMinimumSuspendDuration) {
-    return;
-  }
-  for (auto& observer : observers_) {
-    observer.OnResumeActive(clock_->Now() - sleep_duration);
-  }
-}
-
-}  // namespace policy
diff --git a/chrome/browser/chromeos/policy/status_collector/affiliated_session_service.h b/chrome/browser/chromeos/policy/status_collector/affiliated_session_service.h
deleted file mode 100644
index ca2b1b2..0000000
--- a/chrome/browser/chromeos/policy/status_collector/affiliated_session_service.h
+++ /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.
-
-#ifndef CHROME_BROWSER_CHROMEOS_POLICY_STATUS_COLLECTOR_AFFILIATED_SESSION_SERVICE_H_
-#define CHROME_BROWSER_CHROMEOS_POLICY_STATUS_COLLECTOR_AFFILIATED_SESSION_SERVICE_H_
-
-#include "base/observer_list.h"
-#include "base/observer_list_types.h"
-#include "base/scoped_multi_source_observation.h"
-#include "base/scoped_observation.h"
-#include "base/time/clock.h"
-#include "base/time/default_clock.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_observer.h"
-#include "chromeos/dbus/power/power_manager_client.h"
-#include "components/account_id/account_id.h"
-#include "components/session_manager/core/session_manager.h"
-#include "components/session_manager/core/session_manager_observer.h"
-
-namespace policy {
-
-class AffiliatedSessionService : public session_manager::SessionManagerObserver,
-                                 public ProfileObserver,
-                                 public chromeos::PowerManagerClient::Observer {
- public:
-  class Observer : public base::CheckedObserver {
-   public:
-    // Occurs when an affiliated primary user has logged in.
-    virtual void OnAffiliatedLogin(Profile* profile) {}
-
-    // Occurs when an affiliated primary user has logged out.
-    virtual void OnAffiliatedLogout(Profile* profile) {}
-
-    // Occurs when the active user has locked the user session.
-    virtual void OnLocked() {}
-
-    // Occurs when the active user has unlocked the user session.
-    virtual void OnUnlocked() {}
-
-    // Occurs when the device recovers from a suspend state, where
-    // |suspend_time| is the time when the suspend state
-    // first occurred. Short duration suspends are not reported.
-    virtual void OnResumeActive(base::Time suspend_time) {}
-  };
-
-  explicit AffiliatedSessionService(
-      base::Clock* clock = base::DefaultClock::GetInstance());
-  AffiliatedSessionService(const AffiliatedSessionService&) = delete;
-  AffiliatedSessionService& operator=(const AffiliatedSessionService&) = delete;
-  ~AffiliatedSessionService() override;
-
-  void AddObserver(Observer* observer);
-
-  void RemoveObserver(Observer* observer);
-
-  // session_manager::SessionManagerObserver::Observer
-  void OnSessionStateChanged() override;
-  void OnUserProfileLoaded(const AccountId& account_id) override;
-
-  // ProfileObserver
-  void OnProfileWillBeDestroyed(Profile* profile) override;
-
-  // chromeos::PowerManagerClient::Observer
-  void SuspendDone(base::TimeDelta sleep_duration) override;
-
- private:
-  bool is_session_locked_;
-
-  base::Clock* clock_;
-
-  base::ObserverList<Observer> observers_;
-
-  session_manager::SessionManager* const session_manager_;
-
-  base::ScopedMultiSourceObservation<Profile, ProfileObserver>
-      profile_observations_{this};
-  base::ScopedObservation<session_manager::SessionManager,
-                          session_manager::SessionManagerObserver>
-      session_manager_observation_{this};
-  base::ScopedObservation<chromeos::PowerManagerClient,
-                          chromeos::PowerManagerClient::Observer>
-      power_manager_observation_{this};
-};
-
-}  // namespace policy
-
-#endif  // CHROME_BROWSER_CHROMEOS_POLICY_STATUS_COLLECTOR_AFFILIATED_SESSION_SERVICE_H_
diff --git a/chrome/browser/chromeos/policy/status_collector/app_info_generator.cc b/chrome/browser/chromeos/policy/status_collector/app_info_generator.cc
index 1f96fc0..1178770 100644
--- a/chrome/browser/chromeos/policy/status_collector/app_info_generator.cc
+++ b/chrome/browser/chromeos/policy/status_collector/app_info_generator.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/chromeos/policy/status_collector/app_info_generator.h"
 
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
+#include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/web_applications/web_app_provider_factory.h"
 #include "chrome/browser/web_applications/web_app_registrar.h"
@@ -19,6 +20,18 @@
 
 namespace {
 
+bool IsPrimaryAndAffiliated(Profile* profile) {
+  user_manager::User* user =
+      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+  bool is_primary = chromeos::ProfileHelper::Get()->IsPrimaryProfile(profile);
+  bool is_affiliated = user && user->IsAffiliated();
+  if (!is_primary || !is_affiliated) {
+    VLOG(1) << "The profile for the primary user is not associated with an "
+               "affiliated user.";
+  }
+  return is_primary && is_affiliated;
+}
+
 em::AppInfo::Status ExtractStatus(const apps::mojom::Readiness readiness) {
   switch (readiness) {
     case apps::mojom::Readiness::kReady:
@@ -78,10 +91,15 @@
 AppInfoGenerator::AppInfoProvider::~AppInfoProvider() = default;
 
 AppInfoGenerator::AppInfoGenerator(
+    ManagedSessionService* managed_session_service,
     base::TimeDelta max_stored_past_activity_interval,
     base::Clock* clock)
     : max_stored_past_activity_interval_(max_stored_past_activity_interval),
-      clock_(*clock) {}
+      clock_(*clock) {
+  if (managed_session_service) {
+    managed_session_observation_.Observe(managed_session_service);
+  }
+}
 
 AppInfoGenerator::AppInstances::AppInstances(const base::Time start_time_)
     : start_time(start_time_) {}
@@ -153,7 +171,11 @@
   SetIdleDurationsToOpen();
 }
 
-void AppInfoGenerator::OnAffiliatedLogin(Profile* profile) {
+void AppInfoGenerator::OnLogin(Profile* profile) {
+  if (!IsPrimaryAndAffiliated(profile)) {
+    return;
+  }
+
   if (!apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile(profile)) {
     VLOG(1) << "No apps available. Will not track usage.";
     return;
@@ -168,7 +190,11 @@
   }
 }
 
-void AppInfoGenerator::OnAffiliatedLogout(Profile* profile) {
+void AppInfoGenerator::OnLogout(Profile* profile) {
+  if (!IsPrimaryAndAffiliated(profile)) {
+    return;
+  }
+
   if (provider_) {
     if (should_report_) {
       provider_->app_service_proxy.InstanceRegistry().RemoveObserver(this);
diff --git a/chrome/browser/chromeos/policy/status_collector/app_info_generator.h b/chrome/browser/chromeos/policy/status_collector/app_info_generator.h
index c315a1b..89d0b601 100644
--- a/chrome/browser/chromeos/policy/status_collector/app_info_generator.h
+++ b/chrome/browser/chromeos/policy/status_collector/app_info_generator.h
@@ -13,7 +13,7 @@
 #include "base/time/default_clock.h"
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
 #include "chrome/browser/chromeos/policy/status_collector/activity_storage.h"
-#include "chrome/browser/chromeos/policy/status_collector/affiliated_session_service.h"
+#include "chrome/browser/chromeos/policy/status_collector/managed_session_service.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/services/app_service/public/cpp/instance.h"
@@ -30,11 +30,12 @@
 // A class that is responsible for collecting application inventory and usage
 // information.
 class AppInfoGenerator : public apps::InstanceRegistry::Observer,
-                         public AffiliatedSessionService::Observer {
+                         public ManagedSessionService::Observer {
  public:
   using Result = absl::optional<std::vector<enterprise_management::AppInfo>>;
 
   explicit AppInfoGenerator(
+      ManagedSessionService* managed_session_service,
       base::TimeDelta max_stored_past_activity_interval,
       base::Clock* clock = base::DefaultClock::GetInstance());
   AppInfoGenerator(const AppInfoGenerator&) = delete;
@@ -59,9 +60,9 @@
   // up until the current time, so it may be reported.
   void OnWillReport();
 
-  // AffiliatedSessionManager::Observer
-  void OnAffiliatedLogin(Profile* profile) override;
-  void OnAffiliatedLogout(Profile* profile) override;
+  // ManagedSessionService::Observer
+  void OnLogin(Profile* profile) override;
+  void OnLogout(Profile* profile) override;
   void OnLocked() override;
   void OnUnlocked() override;
   void OnResumeActive(base::Time suspend_time) override;
@@ -122,6 +123,10 @@
   base::TimeDelta max_stored_past_activity_interval_;
 
   const base::Clock& clock_;
+
+  base::ScopedObservation<ManagedSessionService,
+                          ManagedSessionService::Observer>
+      managed_session_observation_{this};
 };
 
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/status_collector/app_info_generator_unittest.cc b/chrome/browser/chromeos/policy/status_collector/app_info_generator_unittest.cc
index 5b646ea..cb504b0e 100644
--- a/chrome/browser/chromeos/policy/status_collector/app_info_generator_unittest.cc
+++ b/chrome/browser/chromeos/policy/status_collector/app_info_generator_unittest.cc
@@ -166,11 +166,24 @@
     GetInstanceRegistry().OnInstances(deltas);
   }
 
+  std::unique_ptr<TestingProfile> CreateProfile(const AccountId& account_id,
+                                                bool is_affiliated = true) {
+    TestingProfile::Builder profile_builder;
+    profile_builder.SetProfileName(account_id.GetUserEmail());
+    auto profile = profile_builder.Build();
+    user_manager_->AddUserWithAffiliationAndTypeAndProfile(
+        account_id, is_affiliated, user_manager::UserType::USER_TYPE_REGULAR,
+        profile.get());
+    return profile;
+  }
+
   void SetUp() override {
     auto user_manager = std::make_unique<ash::FakeChromeUserManager>();
+    user_manager_ = user_manager.get();
     user_manager_enabler_ = std::make_unique<user_manager::ScopedUserManager>(
         std::move(user_manager));
-    profile_ = std::make_unique<TestingProfile>();
+    account_id_ = AccountId::FromUserEmail("affiliated@managed.com");
+    profile_ = CreateProfile(account_id_);
     test_clock().SetNow(MakeLocalTime("25-MAR-2020 1:30am"));
 
     web_app::WebAppProviderFactory::GetInstance()->SetTestingFactoryAndUse(
@@ -206,13 +219,13 @@
   std::unique_ptr<AppInfoGenerator> GetGenerator(
       base::TimeDelta max_stored_past_activity_interval =
           base::TimeDelta::FromDays(0)) {
-    return std::make_unique<AppInfoGenerator>(max_stored_past_activity_interval,
-                                              &test_clock());
+    return std::make_unique<AppInfoGenerator>(
+        nullptr, max_stored_past_activity_interval, &test_clock());
   }
 
   std::unique_ptr<AppInfoGenerator> GetReadyGenerator() {
     auto generator = GetGenerator();
-    generator->OnAffiliatedLogin(profile());
+    generator->OnLogin(profile());
     generator->OnReportingChanged(true);
     return generator;
   }
@@ -239,6 +252,10 @@
 
   Profile* profile() { return profile_.get(); }
 
+  ash::FakeChromeUserManager* user_manager() { return user_manager_; }
+
+  AccountId account_id() { return account_id_; }
+
   static auto EqActivity(const base::Time& start_time,
                          const base::Time& end_time) {
     return AllOf(
@@ -265,8 +282,10 @@
   apps::ScopedOmitPluginVmAppsForTesting
       scoped_omit_plugin_vm_apps_for_testing_;
   content::BrowserTaskEnvironment task_environment_;
+  AccountId account_id_;
   std::unique_ptr<TestingProfile> profile_;
   web_app::WebAppRegistrarMutable* app_registrar_;
+  ash::FakeChromeUserManager* user_manager_;
   std::unique_ptr<user_manager::ScopedUserManager> user_manager_enabler_;
   TestingPrefServiceSimple pref_service_;
 
@@ -283,6 +302,7 @@
   PushApp("c", "ThirdApp", apps::mojom::Readiness::kUninstalledByUser, "",
           apps::mojom::AppType::kCrostini);
 
+  user_manager()->LoginUser(account_id(), true);
   auto generator = GetReadyGenerator();
   auto result = generator->Generate();
 
@@ -297,6 +317,7 @@
 }
 
 TEST_F(AppInfoGeneratorTest, GenerateWebApp) {
+  user_manager()->LoginUser(account_id(), true);
   auto generator = GetReadyGenerator();
   PushApp("c", "App", apps::mojom::Readiness::kUninstalledByUser, "",
           apps::mojom::AppType::kWeb);
@@ -321,6 +342,7 @@
 }
 
 TEST_F(AppInfoGeneratorTest, MultipleInstances) {
+  user_manager()->LoginUser(account_id(), true);
   auto generator = GetReadyGenerator();
   PushApp("a", "FirstApp", apps::mojom::Readiness::kDisabledByPolicy, "1.1",
           apps::mojom::AppType::kArc);
@@ -347,18 +369,54 @@
 }
 
 TEST_F(AppInfoGeneratorTest, ShouldNotReport) {
+  user_manager()->LoginUser(account_id(), true);
   PushApp("a", "FirstApp", apps::mojom::Readiness::kDisabledByPolicy, "1.1",
           apps::mojom::AppType::kArc);
 
   auto generator = GetGenerator();
   generator->OnReportingChanged(false);
-  generator->OnAffiliatedLogin(profile());
+  generator->OnLogin(profile());
+  auto result = generator->Generate();
+
+  EXPECT_FALSE(result.has_value());
+}
+
+TEST_F(AppInfoGeneratorTest, UnaffiliatedUser) {
+  auto unaffiliated_account_id =
+      AccountId::FromUserEmail("unaffiliated@unmanaged.com");
+  auto unaffiliated_profile =
+      CreateProfile(unaffiliated_account_id, /* is_affiliated= */ false);
+  user_manager()->LoginUser(unaffiliated_account_id, true);
+  PushApp("a", "FirstApp", apps::mojom::Readiness::kDisabledByPolicy, "1.1",
+          apps::mojom::AppType::kArc);
+
+  auto generator = GetGenerator();
+  generator->OnReportingChanged(true);
+  generator->OnLogin(unaffiliated_profile.get());
+  auto result = generator->Generate();
+
+  EXPECT_FALSE(result.has_value());
+}
+
+TEST_F(AppInfoGeneratorTest, SecondaryUser) {
+  user_manager()->LoginUser(account_id(), true);
+  auto secondary_account_id = AccountId::FromUserEmail("secondary@managed.com");
+  auto secondary_profile =
+      CreateProfile(secondary_account_id, /* is_affiliated= */ true);
+  user_manager()->LoginUser(secondary_account_id, true);
+  PushApp("a", "FirstApp", apps::mojom::Readiness::kDisabledByPolicy, "1.1",
+          apps::mojom::AppType::kArc);
+
+  auto generator = GetGenerator();
+  generator->OnReportingChanged(true);
+  generator->OnLogin(secondary_profile.get());
   auto result = generator->Generate();
 
   EXPECT_FALSE(result.has_value());
 }
 
 TEST_F(AppInfoGeneratorTest, OnReportedSuccessfully) {
+  user_manager()->LoginUser(account_id(), true);
   auto generator = GetReadyGenerator();
   PushApp("a", "FirstApp", apps::mojom::Readiness::kDisabledByPolicy, "1.1",
           apps::mojom::AppType::kArc);
@@ -388,6 +446,7 @@
 }
 
 TEST_F(AppInfoGeneratorTest, OnWillReport) {
+  user_manager()->LoginUser(account_id(), true);
   auto generator = GetReadyGenerator();
   PushApp("a", "FirstApp", apps::mojom::Readiness::kDisabledByPolicy, "1.1",
           apps::mojom::AppType::kArc);
@@ -426,12 +485,13 @@
 }
 
 TEST_F(AppInfoGeneratorTest, OnLogoutOnLogin) {
+  user_manager()->LoginUser(account_id(), true);
   PushApp("a", "FirstApp", apps::mojom::Readiness::kDisabledByPolicy, "1.1",
           apps::mojom::AppType::kArc);
   auto generator = GetGenerator();
   generator->OnReportingChanged(true);
-  generator->OnAffiliatedLogin(profile());
-  generator->OnAffiliatedLogout(profile());
+  generator->OnLogin(profile());
+  generator->OnLogout(profile());
   Instance app_instance("a");
   test_clock().SetNow(MakeLocalTime("29-MAR-2020 1:30pm"));
   PushAppInstance(app_instance, apps::InstanceState::kStarted);
@@ -443,7 +503,7 @@
 
   EXPECT_FALSE(result.has_value());
 
-  generator->OnAffiliatedLogin(profile());
+  generator->OnLogin(profile());
 
   test_clock().SetNow(MakeLocalTime("30-MAR-2020 2:30pm"));
   PushAppInstance(app_instance, apps::InstanceState::kStarted);
@@ -462,6 +522,7 @@
 }
 
 TEST_F(AppInfoGeneratorTest, OnLocked) {
+  user_manager()->LoginUser(account_id(), true);
   auto generator = GetReadyGenerator();
   PushApp("a", "FirstApp", apps::mojom::Readiness::kDisabledByPolicy, "1.1",
           apps::mojom::AppType::kArc);
@@ -484,6 +545,7 @@
 }
 
 TEST_F(AppInfoGeneratorTest, OnUnlocked) {
+  user_manager()->LoginUser(account_id(), true);
   auto generator = GetReadyGenerator();
   PushApp("a", "FirstApp", apps::mojom::Readiness::kDisabledByPolicy, "1.1",
           apps::mojom::AppType::kArc);
@@ -512,6 +574,7 @@
 }
 
 TEST_F(AppInfoGeneratorTest, OnResumeActive) {
+  user_manager()->LoginUser(account_id(), true);
   auto generator = GetReadyGenerator();
   PushApp("a", "FirstApp", apps::mojom::Readiness::kDisabledByPolicy, "1.1",
           apps::mojom::AppType::kArc);
@@ -540,6 +603,7 @@
 }
 
 TEST_F(AppInfoGeneratorTest, OnLoginRemoveOldUsage) {
+  user_manager()->LoginUser(account_id(), true);
   PushApp("a", "FirstApp", apps::mojom::Readiness::kDisabledByPolicy, "1.1",
           apps::mojom::AppType::kArc);
   PushApp("b", "SecondApp", apps::mojom::Readiness::kReady, "1.2",
@@ -548,7 +612,7 @@
       1);  // Exclude all past usage except for UTC today and yesterday.
   auto generator = GetGenerator(max_days_past);
   generator->OnReportingChanged(true);
-  generator->OnAffiliatedLogin(profile());
+  generator->OnLogin(profile());
 
   Instance app_instance1("a");
   test_clock().SetNow(MakeLocalTime("28-MAR-2020 1:30am"));
@@ -561,9 +625,9 @@
   test_clock().SetNow(MakeLocalTime("29-MAR-2020 3:30am"));
   PushAppInstance(app_instance2, apps::InstanceState::kDestroyed);
 
-  generator->OnAffiliatedLogout(profile());
+  generator->OnLogout(profile());
   test_clock().SetNow(MakeLocalTime("30-MAR-2020 11:00am"));
-  generator->OnAffiliatedLogin(profile());
+  generator->OnLogin(profile());
 
   auto result = generator->Generate();
 
diff --git a/chrome/browser/chromeos/policy/status_collector/device_status_collector.cc b/chrome/browser/chromeos/policy/status_collector/device_status_collector.cc
index 127983a4..3d8f2a4 100644
--- a/chrome/browser/chromeos/policy/status_collector/device_status_collector.cc
+++ b/chrome/browser/chromeos/policy/status_collector/device_status_collector.cc
@@ -1443,7 +1443,9 @@
       graphics_status_fetcher_(graphics_status_fetcher),
       crash_report_info_fetcher_(crash_report_info_fetcher),
       power_manager_(chromeos::PowerManagerClient::Get()),
-      app_info_generator_(kMaxStoredPastActivityInterval, clock_) {
+      app_info_generator_(&managed_session_service_,
+                          kMaxStoredPastActivityInterval,
+                          clock_) {
   // protected fields of `StatusCollector`.
   max_stored_past_activity_interval_ = kMaxStoredPastActivityInterval;
   max_stored_future_activity_interval_ = kMaxStoredFutureActivityInterval;
@@ -1547,8 +1549,7 @@
   stats_reporting_pref_subscription_ = cros_settings_->AddSettingsObserver(
       chromeos::kStatsReportingPref, callback);
 
-  affiliated_session_service_.AddObserver(&app_info_generator_);
-
+  // TODO(b/191986061):: consider using ScopedObservation instead.
   power_manager_->AddObserver(this);
 
   // Fetch the current values of the policies.
@@ -1603,7 +1604,6 @@
 
 DeviceStatusCollector::~DeviceStatusCollector() {
   power_manager_->RemoveObserver(this);
-  affiliated_session_service_.RemoveObserver(&app_info_generator_);
 }
 
 // static
diff --git a/chrome/browser/chromeos/policy/status_collector/device_status_collector.h b/chrome/browser/chromeos/policy/status_collector/device_status_collector.h
index b64d0cd7..7816073 100644
--- a/chrome/browser/chromeos/policy/status_collector/device_status_collector.h
+++ b/chrome/browser/chromeos/policy/status_collector/device_status_collector.h
@@ -211,8 +211,8 @@
 
   static void RegisterPrefs(PrefRegistrySimple* registry);
 
-  AffiliatedSessionService* GetAffiliatedSessionServiceForTesting() {
-    return &affiliated_session_service_;
+  ManagedSessionService* GetManagedSessionServiceForTesting() {
+    return &managed_session_service_;
   }
 
   // How often to poll to see if the user is idle.
@@ -480,7 +480,7 @@
   base::CallbackListSubscription app_info_subscription_;
   base::CallbackListSubscription stats_reporting_pref_subscription_;
 
-  AffiliatedSessionService affiliated_session_service_;
+  ManagedSessionService managed_session_service_;
 
   AppInfoGenerator app_info_generator_;
 
diff --git a/chrome/browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc b/chrome/browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc
index 4704e9e..a8e183d8 100644
--- a/chrome/browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc
+++ b/chrome/browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc
@@ -947,7 +947,7 @@
     options->crash_report_info_fetcher =
         base::BindRepeating(&GetEmptyCrashReportInfo);
     options->app_info_generator = std::make_unique<policy::AppInfoGenerator>(
-        base::TimeDelta::FromDays(0));
+        nullptr, base::TimeDelta::FromDays(0));
     return options;
   }
 
@@ -3608,8 +3608,8 @@
   MockRegularUserWithAffiliation(account_id, true);
   scoped_testing_cros_settings_.device_settings()->SetBoolean(
       chromeos::kReportDeviceAppInfo, true);
-  status_collector_->GetAffiliatedSessionServiceForTesting()
-      ->OnUserProfileLoaded(account_id);
+  status_collector_->GetManagedSessionServiceForTesting()->OnUserProfileLoaded(
+      account_id);
   auto* app_proxy =
       apps::AppServiceProxyFactory::GetForProfile(testing_profile_.get());
   auto app1 = apps::mojom::App::New();
diff --git a/chrome/browser/chromeos/policy/status_collector/managed_session_service.cc b/chrome/browser/chromeos/policy/status_collector/managed_session_service.cc
new file mode 100644
index 0000000..35184f3
--- /dev/null
+++ b/chrome/browser/chromeos/policy/status_collector/managed_session_service.cc
@@ -0,0 +1,110 @@
+// 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/chromeos/policy/status_collector/managed_session_service.h"
+
+#include "base/logging.h"
+#include "chrome/browser/ash/login/existing_user_controller.h"
+#include "chrome/browser/ash/profiles/profile_helper.h"
+#include "components/user_manager/user_manager.h"
+
+namespace policy {
+
+namespace {
+
+constexpr base::TimeDelta kMinimumSuspendDuration =
+    base::TimeDelta::FromMinutes(1);
+
+}  // namespace
+
+ManagedSessionService::ManagedSessionService(base::Clock* clock)
+    : clock_(clock), session_manager_(session_manager::SessionManager::Get()) {
+  if (session_manager_) {
+    // To alleviate tight coupling in unit tests to DeviceStatusCollector.
+    session_manager_observation_.Observe(session_manager_);
+    is_session_locked_ = session_manager_->IsScreenLocked();
+  }
+  if (user_manager::UserManager::IsInitialized()) {
+    authenticator_observation_.Observe(ash::UserSessionManager::GetInstance());
+  }
+  power_manager_observation_.Observe(chromeos::PowerManagerClient::Get());
+}
+
+ManagedSessionService::~ManagedSessionService() {
+  if (ash::ExistingUserController::current_controller()) {
+    ash::ExistingUserController::current_controller()
+        ->RemoveLoginStatusConsumer(this);
+  }
+}
+
+void ManagedSessionService::AddObserver(
+    ManagedSessionService::Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void ManagedSessionService::RemoveObserver(
+    ManagedSessionService::Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+void ManagedSessionService::OnSessionStateChanged() {
+  bool is_session_locked = session_manager_->IsScreenLocked();
+  if (is_session_locked_ == is_session_locked) {
+    return;
+  }
+  is_session_locked_ = is_session_locked;
+
+  if (is_session_locked_) {
+    for (auto& observer : observers_) {
+      observer.OnLocked();
+    }
+  } else {
+    for (auto& observer : observers_) {
+      observer.OnUnlocked();
+    }
+  }
+}
+
+void ManagedSessionService::OnUserProfileLoaded(const AccountId& account_id) {
+  Profile* profile =
+      chromeos::ProfileHelper::Get()->GetProfileByAccountId(account_id);
+  profile_observations_.AddObservation(profile);
+  for (auto& observer : observers_) {
+    observer.OnLogin(profile);
+  }
+}
+
+void ManagedSessionService::OnProfileWillBeDestroyed(Profile* profile) {
+  is_session_locked_ = false;
+  for (auto& observer : observers_) {
+    observer.OnLogout(profile);
+  }
+  profile_observations_.RemoveObservation(profile);
+}
+
+void ManagedSessionService::SuspendDone(base::TimeDelta sleep_duration) {
+  if (sleep_duration < kMinimumSuspendDuration) {
+    return;
+  }
+  for (auto& observer : observers_) {
+    observer.OnResumeActive(clock_->Now() - sleep_duration);
+  }
+}
+
+void ManagedSessionService::OnAuthAttemptStarted() {
+  if (ash::ExistingUserController::current_controller()) {
+    ash::ExistingUserController::current_controller()
+        ->RemoveLoginStatusConsumer(this);
+    ash::ExistingUserController::current_controller()->AddLoginStatusConsumer(
+        this);
+  }
+}
+
+void ManagedSessionService::OnAuthFailure(const chromeos::AuthFailure& error) {
+  for (auto& observer : observers_) {
+    observer.OnLoginFailure(error);
+  }
+}
+
+}  // namespace policy
diff --git a/chrome/browser/chromeos/policy/status_collector/managed_session_service.h b/chrome/browser/chromeos/policy/status_collector/managed_session_service.h
new file mode 100644
index 0000000..52f6d4bb
--- /dev/null
+++ b/chrome/browser/chromeos/policy/status_collector/managed_session_service.h
@@ -0,0 +1,107 @@
+// 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 CHROME_BROWSER_CHROMEOS_POLICY_STATUS_COLLECTOR_MANAGED_SESSION_SERVICE_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_STATUS_COLLECTOR_MANAGED_SESSION_SERVICE_H_
+
+#include "base/observer_list.h"
+#include "base/observer_list_types.h"
+#include "base/scoped_multi_source_observation.h"
+#include "base/scoped_observation.h"
+#include "base/time/clock.h"
+#include "base/time/default_clock.h"
+#include "chrome/browser/ash/login/session/user_session_manager.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_observer.h"
+#include "chromeos/dbus/power/power_manager_client.h"
+#include "chromeos/login/auth/auth_status_consumer.h"
+#include "components/account_id/account_id.h"
+#include "components/session_manager/core/session_manager.h"
+#include "components/session_manager/core/session_manager_observer.h"
+
+namespace policy {
+
+class ManagedSessionService : public session_manager::SessionManagerObserver,
+                              public ProfileObserver,
+                              public chromeos::PowerManagerClient::Observer,
+                              public chromeos::AuthStatusConsumer,
+                              public ash::UserAuthenticatorObserver {
+ public:
+  class Observer : public base::CheckedObserver {
+   public:
+    // Occurs when a user's login attempt fails.
+    virtual void OnLoginFailure(const chromeos::AuthFailure& error) {}
+
+    // Occurs when a user has logged in.
+    virtual void OnLogin(Profile* profile) {}
+
+    // Occurs when a user has logged out.
+    virtual void OnLogout(Profile* profile) {}
+
+    // Occurs when the active user has locked the user session.
+    virtual void OnLocked() {}
+
+    // Occurs when the active user has unlocked the user session.
+    virtual void OnUnlocked() {}
+
+    // Occurs when the device recovers from a suspend state, where
+    // |suspend_time| is the time when the suspend state
+    // first occurred. Short duration suspends are not reported.
+    virtual void OnResumeActive(base::Time suspend_time) {}
+  };
+
+  explicit ManagedSessionService(
+      base::Clock* clock = base::DefaultClock::GetInstance());
+  ManagedSessionService(const ManagedSessionService&) = delete;
+  ManagedSessionService& operator=(const ManagedSessionService&) = delete;
+  ~ManagedSessionService() override;
+
+  void AddObserver(Observer* observer);
+
+  void RemoveObserver(Observer* observer);
+
+  // session_manager::SessionManagerObserver::Observer
+  void OnSessionStateChanged() override;
+  void OnUserProfileLoaded(const AccountId& account_id) override;
+
+  // ProfileObserver
+  void OnProfileWillBeDestroyed(Profile* profile) override;
+
+  // chromeos::PowerManagerClient::Observer
+  void SuspendDone(base::TimeDelta sleep_duration) override;
+
+  void OnAuthSuccess(const ash::UserContext& user_context) override {}
+
+  void OnAuthFailure(const chromeos::AuthFailure& error) override;
+
+  void OnAuthAttemptStarted() override;
+
+ private:
+  bool is_session_locked_;
+
+  base::Clock* clock_;
+
+  base::ObserverList<Observer> observers_;
+
+  session_manager::SessionManager* const session_manager_;
+
+  base::ScopedMultiSourceObservation<Profile, ProfileObserver>
+      profile_observations_{this};
+  base::ScopedObservation<session_manager::SessionManager,
+                          session_manager::SessionManagerObserver>
+      session_manager_observation_{this};
+  base::ScopedObservation<chromeos::PowerManagerClient,
+                          chromeos::PowerManagerClient::Observer>
+      power_manager_observation_{this};
+  base::ScopedObservation<
+      ash::UserSessionManager,
+      ash::UserAuthenticatorObserver,
+      &ash::UserSessionManager::AddUserAuthenticatorObserver,
+      &ash::UserSessionManager::RemoveUserAuthenticatorObserver>
+      authenticator_observation_{this};
+};
+
+}  // namespace policy
+
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_STATUS_COLLECTOR_MANAGED_SESSION_SERVICE_H_
diff --git a/chrome/browser/chromeos/policy/status_collector/affiliated_session_service_unittest.cc b/chrome/browser/chromeos/policy/status_collector/managed_session_service_unittest.cc
similarity index 73%
rename from chrome/browser/chromeos/policy/status_collector/affiliated_session_service_unittest.cc
rename to chrome/browser/chromeos/policy/status_collector/managed_session_service_unittest.cc
index cffd115..da195126 100644
--- a/chrome/browser/chromeos/policy/status_collector/affiliated_session_service_unittest.cc
+++ b/chrome/browser/chromeos/policy/status_collector/managed_session_service_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/chromeos/policy/status_collector/affiliated_session_service.h"
+#include "chrome/browser/chromeos/policy/status_collector/managed_session_service.h"
 
 #include "base/test/simple_test_clock.h"
 #include "chrome/browser/ash/login/users/chrome_user_manager.h"
@@ -17,9 +17,9 @@
 
 namespace policy {
 
-class AffiliatedSessionServiceTest
+class ManagedSessionServiceTest
     : public ::testing::Test,
-      public policy::AffiliatedSessionService::Observer {
+      public policy::ManagedSessionService::Observer {
  protected:
   using SessionState = session_manager::SessionState;
 
@@ -30,12 +30,12 @@
     user_manager_enabler_ = std::make_unique<user_manager::ScopedUserManager>(
         std::move(user_manager));
 
-    affiliated_session_service_ =
-        std::make_unique<AffiliatedSessionService>(&test_clock_);
+    managed_session_service_ =
+        std::make_unique<ManagedSessionService>(&test_clock_);
   }
 
   void TearDown() override {
-    affiliated_session_service_.reset();
+    managed_session_service_.reset();
     chromeos::PowerManagerClient::Shutdown();
   }
 
@@ -54,8 +54,8 @@
     return profile;
   }
 
-  AffiliatedSessionService* affiliated_session_service() {
-    return affiliated_session_service_.get();
+  ManagedSessionService* managed_session_service() {
+    return managed_session_service_.get();
   }
 
   session_manager::SessionManager* session_manager() {
@@ -68,14 +68,19 @@
 
   base::SimpleTestClock* test_clock() { return &test_clock_; }
 
-  void OnAffiliatedLogin(Profile* profile) override { logged_in_ = profile; }
-  void OnAffiliatedLogout(Profile* profile) override { logged_out_ = profile; }
+  void OnLoginFailure(const chromeos::AuthFailure& error) override {
+    auth_failure_ = error;
+  }
+  void OnLogin(Profile* profile) override { logged_in_ = profile; }
+  void OnLogout(Profile* profile) override { logged_out_ = profile; }
   void OnLocked() override { locked_ = true; }
   void OnUnlocked() override { unlocked_ = true; }
   void OnResumeActive(base::Time time) override {
     suspend_time_ = std::make_unique<base::Time>(time);
   }
 
+  chromeos::AuthFailure auth_failure_ =
+      chromeos::AuthFailure::AuthFailureNone();
   Profile* logged_in_ = nullptr;
   Profile* logged_out_ = nullptr;
   bool locked_ = false;
@@ -92,11 +97,11 @@
 
   base::SimpleTestClock test_clock_;
 
-  std::unique_ptr<AffiliatedSessionService> affiliated_session_service_;
+  std::unique_ptr<ManagedSessionService> managed_session_service_;
 };
 
-TEST_F(AffiliatedSessionServiceTest, OnSessionStateChanged) {
-  affiliated_session_service()->AddObserver(this);
+TEST_F(ManagedSessionServiceTest, OnSessionStateChanged) {
+  managed_session_service()->AddObserver(this);
 
   session_manager()->SetSessionState(SessionState::LOCKED);
   session_manager()->SetSessionState(SessionState::ACTIVE);
@@ -129,49 +134,49 @@
   EXPECT_TRUE(unlocked_);
 }
 
-TEST_F(AffiliatedSessionServiceTest, OnUserProfileLoadedAffiliatedAndPrimary) {
+TEST_F(ManagedSessionServiceTest, OnUserProfileLoadedAffiliatedAndPrimary) {
   AccountId affiliated_account_id =
       AccountId::FromUserEmail("user0@managed.com");
   std::unique_ptr<TestingProfile> affiliated_profile = CreateProfile(
       affiliated_account_id, true /* affiliated */, true /* login */);
-  affiliated_session_service()->AddObserver(this);
+  managed_session_service()->AddObserver(this);
 
   session_manager()->NotifyUserProfileLoaded(affiliated_account_id);
 
   EXPECT_TRUE(affiliated_profile->IsSameOrParent(logged_in_));
 }
 
-TEST_F(AffiliatedSessionServiceTest, OnUserProfileLoadedAffiliated) {
+TEST_F(ManagedSessionServiceTest, OnUserProfileLoadedAffiliated) {
   AccountId secondary_account_id =
       AccountId::FromUserEmail("user3@managed.com");
   std::unique_ptr<TestingProfile> secondary_profile = CreateProfile(
       secondary_account_id, true /* affiliated */, false /* login */);
-  affiliated_session_service()->AddObserver(this);
+  managed_session_service()->AddObserver(this);
 
   session_manager()->NotifyUserProfileLoaded(secondary_account_id);
 
-  EXPECT_EQ(logged_in_, nullptr);
+  EXPECT_TRUE(secondary_profile->IsSameOrParent(logged_in_));
 }
 
-TEST_F(AffiliatedSessionServiceTest, OnUserProfileLoadedPrimary) {
+TEST_F(ManagedSessionServiceTest, OnUserProfileLoadedPrimary) {
   AccountId unaffiliated_account_id =
       AccountId::FromUserEmail("user2@managed.com");
   std::unique_ptr<TestingProfile> unaffiliated_profile = CreateProfile(
       unaffiliated_account_id, false /* affiliated */, true /* login */);
-  affiliated_session_service()->AddObserver(this);
+  managed_session_service()->AddObserver(this);
 
   session_manager()->NotifyUserProfileLoaded(unaffiliated_account_id);
 
-  EXPECT_EQ(logged_in_, nullptr);
+  EXPECT_TRUE(unaffiliated_profile->IsSameOrParent(logged_in_));
 }
 
-TEST_F(AffiliatedSessionServiceTest,
+TEST_F(ManagedSessionServiceTest,
        OnProfileWillBeDestroyedAffiliatedAndPrimary) {
   AccountId affiliated_account_id =
       AccountId::FromUserEmail("user0@managed.com");
   std::unique_ptr<TestingProfile> affiliated_profile = CreateProfile(
       affiliated_account_id, true /* affiliated */, true /* login */);
-  affiliated_session_service()->AddObserver(this);
+  managed_session_service()->AddObserver(this);
 
   session_manager()->NotifyUserProfileLoaded(affiliated_account_id);
   affiliated_profile->MaybeSendDestroyedNotification();
@@ -179,34 +184,34 @@
   EXPECT_TRUE(affiliated_profile->IsSameOrParent(logged_out_));
 }
 
-TEST_F(AffiliatedSessionServiceTest, OnProfileWillBeDestroyedAffiliated) {
+TEST_F(ManagedSessionServiceTest, OnProfileWillBeDestroyedAffiliated) {
   AccountId secondary_account_id =
       AccountId::FromUserEmail("user3@managed.com");
   std::unique_ptr<TestingProfile> secondary_profile = CreateProfile(
       secondary_account_id, true /* affiliated */, false /* login */);
-  affiliated_session_service()->AddObserver(this);
+  managed_session_service()->AddObserver(this);
 
   session_manager()->NotifyUserProfileLoaded(secondary_account_id);
   secondary_profile->MaybeSendDestroyedNotification();
 
-  EXPECT_EQ(logged_out_, nullptr);
+  EXPECT_TRUE(secondary_profile->IsSameOrParent(logged_in_));
 }
 
-TEST_F(AffiliatedSessionServiceTest, OnProfileWillBeDestroyedPrimary) {
+TEST_F(ManagedSessionServiceTest, OnProfileWillBeDestroyedPrimary) {
   AccountId unaffiliated_account_id =
       AccountId::FromUserEmail("user2@managed.com");
   std::unique_ptr<TestingProfile> unaffiliated_profile = CreateProfile(
       unaffiliated_account_id, false /* affiliated */, true /* login */);
-  affiliated_session_service()->AddObserver(this);
+  managed_session_service()->AddObserver(this);
 
   session_manager()->NotifyUserProfileLoaded(unaffiliated_account_id);
   unaffiliated_profile->MaybeSendDestroyedNotification();
 
-  EXPECT_EQ(logged_out_, nullptr);
+  EXPECT_TRUE(unaffiliated_profile->IsSameOrParent(logged_in_));
 }
 
-TEST_F(AffiliatedSessionServiceTest, SuspendDone) {
-  affiliated_session_service()->AddObserver(this);
+TEST_F(ManagedSessionServiceTest, SuspendDone) {
+  managed_session_service()->AddObserver(this);
   test_clock()->SetNow(base::Time::Now());
   base::TimeDelta sleep_duration = base::TimeDelta::FromHours(2);
 
@@ -215,13 +220,13 @@
   EXPECT_EQ(*suspend_time_, test_clock()->Now() - sleep_duration);
 }
 
-TEST_F(AffiliatedSessionServiceTest, RemoveObserver) {
+TEST_F(ManagedSessionServiceTest, RemoveObserver) {
   AccountId account_id = AccountId::FromUserEmail("user0@managed.com");
   std::unique_ptr<TestingProfile> profile =
       CreateProfile(account_id, true /* affiliated */, true /* login */);
-  affiliated_session_service()->AddObserver(this);
+  managed_session_service()->AddObserver(this);
 
-  affiliated_session_service()->RemoveObserver(this);
+  managed_session_service()->RemoveObserver(this);
 
   session_manager()->SetSessionState(SessionState::LOCKED);
   session_manager()->SetSessionState(SessionState::ACTIVE);
@@ -236,4 +241,14 @@
   EXPECT_FALSE(profile->IsSameOrParent(logged_out_));
 }
 
+TEST_F(ManagedSessionServiceTest, LoginFailure) {
+  managed_session_service()->AddObserver(this);
+
+  managed_session_service()->OnAuthFailure(chromeos::AuthFailure(
+      chromeos::AuthFailure::FailureReason::OWNER_REQUIRED));
+
+  EXPECT_EQ(auth_failure_.reason(),
+            chromeos::AuthFailure::FailureReason::OWNER_REQUIRED);
+}
+
 }  // namespace policy
diff --git a/chrome/browser/device_api/device_attribute_api.cc b/chrome/browser/device_api/device_attribute_api.cc
index 31311476..66bc6edd 100644
--- a/chrome/browser/device_api/device_attribute_api.cc
+++ b/chrome/browser/device_api/device_attribute_api.cc
@@ -22,9 +22,13 @@
 
 using Result = blink::mojom::DeviceAttributeResult;
 
+const char kNotAllowedOriginErrorMessage[] =
+    "The current origin cannot use this web API because it is not allowed by "
+    "the DeviceAttributesAllowedForOrigins policy.";
+
 #if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS)
 const char kNotSupportedPlatformErrorMessage[] =
-    "This restricted web API is not supported on the current platform.";
+    "This web API is not supported on the current platform.";
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
@@ -46,6 +50,12 @@
 
 }  // namespace
 
+void ReportNotAllowedError(
+    base::OnceCallback<void(DeviceAttributeResultPtr)> callback) {
+  std::move(callback).Run(
+      Result::NewErrorMessage(kNotAllowedOriginErrorMessage));
+}
+
 void GetDirectoryId(DeviceAPIService::GetDirectoryIdCallback callback) {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   const std::string attribute = g_browser_process->platform_part()
diff --git a/chrome/browser/device_api/device_attribute_api.h b/chrome/browser/device_api/device_attribute_api.h
index 9275d53..e13fea68 100644
--- a/chrome/browser/device_api/device_attribute_api.h
+++ b/chrome/browser/device_api/device_attribute_api.h
@@ -8,9 +8,12 @@
 #include "third_party/blink/public/mojom/device/device.mojom.h"
 
 using blink::mojom::DeviceAPIService;
+using blink::mojom::DeviceAttributeResultPtr;
 
 namespace device_attribute_api {
 
+void ReportNotAllowedError(
+    base::OnceCallback<void(DeviceAttributeResultPtr)> callback);
 void GetDirectoryId(DeviceAPIService::GetDirectoryIdCallback callback);
 void GetHostname(DeviceAPIService::GetHostnameCallback callback);
 void GetSerialNumber(DeviceAPIService::GetSerialNumberCallback callback);
diff --git a/chrome/browser/device_api/device_service_impl.cc b/chrome/browser/device_api/device_service_impl.cc
index a8167a1..2fbe734a 100644
--- a/chrome/browser/device_api/device_service_impl.cc
+++ b/chrome/browser/device_api/device_service_impl.cc
@@ -5,6 +5,9 @@
 
 #include <memory>
 
+#include "base/containers/contains.h"
+#include "build/chromeos_buildflags.h"
+#include "chrome/browser/app_mode/app_mode_utils.h"
 #include "chrome/browser/device_api/device_attribute_api.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/web_applications/components/policy/web_app_policy_constants.h"
@@ -15,8 +18,64 @@
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "url/origin.h"
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "chrome/browser/ash/app_mode/web_app/web_kiosk_app_data.h"
+#include "chrome/browser/ash/app_mode/web_app/web_kiosk_app_manager.h"
+#include "chrome/browser/ash/login/app_mode/kiosk_launch_controller.h"
+#endif
+
 namespace {
 
+// Check whether the target origin is allowed to access to the device
+// attributes.
+bool CanAccessDeviceAttributes(const PrefService* prefs,
+                               const url::Origin& origin) {
+  const base::ListValue* prefs_list =
+      prefs->GetList(prefs::kDeviceAttributesAllowedForOrigins);
+  if (!prefs_list)
+    return false;
+
+  return base::Contains(prefs_list->GetList(), origin, [](const auto& entry) {
+    return url::Origin::Create(GURL(entry.GetString()));
+  });
+}
+
+// Check whether the target origin is the same as the main application running
+// in the Kiosk session.
+// TODO(anqing): After Kiosk is migrated to Lacros, the launch url needs to be
+// stored in the lacros-browser when the app is launched. Then it can be used to
+// compare with |origin|.
+bool IsEqualToKioskOrigin(const url::Origin& origin) {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  const AccountId& account_id =
+      user_manager::UserManager::Get()->GetPrimaryUser()->GetAccountId();
+  const ash::WebKioskAppData* app_data =
+      ash::WebKioskAppManager::Get()->GetAppByAccountId(account_id);
+  return url::Origin::Create(app_data->install_url()) == origin;
+#else
+  return false;
+#endif
+}
+
+// Check whether the target origin is included in the WebAppInstallForceList
+// policy.
+bool IsForceInstalledOrigin(const PrefService* prefs,
+                            const url::Origin& origin) {
+  const base::ListValue* prefs_list =
+      prefs->GetList(prefs::kWebAppInstallForceList);
+  if (!prefs_list)
+    return false;
+
+  return base::Contains(prefs_list->GetList(), origin, [](const auto& entry) {
+    std::string entry_url = entry.FindKey(web_app::kUrlKey)->GetString();
+    return url::Origin::Create(GURL(entry_url));
+  });
+}
+
+const PrefService* GetPrefs(content::RenderFrameHost* host) {
+  return Profile::FromBrowserContext(host->GetBrowserContext())->GetPrefs();
+}
+
 bool IsTrustedContext(content::RenderFrameHost* host,
                       const url::Origin& origin) {
   // TODO(anqing): This feature flag is turned on by default for origin trial.
@@ -24,23 +83,11 @@
   if (!base::FeatureList::IsEnabled(features::kEnableRestrictedWebApis))
     return false;
 
-  PrefService* prefs =
-      Profile::FromBrowserContext(host->GetBrowserContext())->GetPrefs();
-
-  if (!prefs->GetBoolean(
-          prefs::kManagedWebAppsAccessToDeviceAttributesAllowed)) {
-    return false;
+  if (chrome::IsRunningInAppMode()) {
+    return IsEqualToKioskOrigin(origin);
+  } else {
+    return IsForceInstalledOrigin(GetPrefs(host), origin);
   }
-
-  // TODO(apotapchuk): Implement a more efficient way of checking the trustness
-  // status of the app.
-  for (const base::Value& entry :
-       prefs->GetList(prefs::kWebAppInstallForceList)->GetList()) {
-    if (origin ==
-        url::Origin::Create(GURL(entry.FindKey(web_app::kUrlKey)->GetString())))
-      return true;
-  }
-  return false;
 }
 
 }  // namespace
@@ -52,7 +99,7 @@
   pref_change_registrar_.Init(
       Profile::FromBrowserContext(host->GetBrowserContext())->GetPrefs());
   pref_change_registrar_.Add(
-      prefs::kManagedWebAppsAccessToDeviceAttributesAllowed,
+      prefs::kDeviceAttributesAllowedForOrigins,
       base::BindRepeating(&DeviceServiceImpl::OnDisposingIfNeeded,
                           base::Unretained(this)));
   pref_change_registrar_.Add(
@@ -82,8 +129,7 @@
 
 // static
 void DeviceServiceImpl::RegisterProfilePrefs(PrefRegistrySimple* registry) {
-  registry->RegisterBooleanPref(
-      prefs::kManagedWebAppsAccessToDeviceAttributesAllowed, true);
+  registry->RegisterListPref(prefs::kDeviceAttributesAllowedForOrigins);
 }
 
 void DeviceServiceImpl::OnDisposingIfNeeded() {
@@ -95,23 +141,39 @@
 }
 
 void DeviceServiceImpl::GetDirectoryId(GetDirectoryIdCallback callback) {
-  device_attribute_api::GetDirectoryId(std::move(callback));
+  GetDeviceAttribute(base::BindOnce(device_attribute_api::GetDirectoryId),
+                     std::move(callback));
 }
 
 void DeviceServiceImpl::GetHostname(GetHostnameCallback callback) {
-  device_attribute_api::GetHostname(std::move(callback));
+  GetDeviceAttribute(base::BindOnce(device_attribute_api::GetHostname),
+                     std::move(callback));
 }
 
 void DeviceServiceImpl::GetSerialNumber(GetSerialNumberCallback callback) {
-  device_attribute_api::GetSerialNumber(std::move(callback));
+  GetDeviceAttribute(base::BindOnce(device_attribute_api::GetSerialNumber),
+                     std::move(callback));
 }
 
 void DeviceServiceImpl::GetAnnotatedAssetId(
     GetAnnotatedAssetIdCallback callback) {
-  device_attribute_api::GetAnnotatedAssetId(std::move(callback));
+  GetDeviceAttribute(base::BindOnce(device_attribute_api::GetAnnotatedAssetId),
+                     std::move(callback));
 }
 
 void DeviceServiceImpl::GetAnnotatedLocation(
     GetAnnotatedLocationCallback callback) {
-  device_attribute_api::GetAnnotatedLocation(std::move(callback));
+  GetDeviceAttribute(base::BindOnce(device_attribute_api::GetAnnotatedLocation),
+                     std::move(callback));
+}
+
+void DeviceServiceImpl::GetDeviceAttribute(
+    base::OnceCallback<void(DeviceAttributeCallback)> handler,
+    DeviceAttributeCallback callback) {
+  if (!CanAccessDeviceAttributes(GetPrefs(host_), origin())) {
+    device_attribute_api::ReportNotAllowedError(std::move(callback));
+    return;
+  }
+
+  std::move(handler).Run(std::move(callback));
 }
diff --git a/chrome/browser/device_api/device_service_impl.h b/chrome/browser/device_api/device_service_impl.h
index d1f4091f..bcdc3493 100644
--- a/chrome/browser/device_api/device_service_impl.h
+++ b/chrome/browser/device_api/device_service_impl.h
@@ -19,6 +19,9 @@
 class DeviceServiceImpl final
     : public content::DocumentServiceBase<blink::mojom::DeviceAPIService> {
  public:
+  using DeviceAttributeCallback =
+      base::OnceCallback<void(blink::mojom::DeviceAttributeResultPtr)>;
+
   // Tries to attach this mojo service to |host| for trusted web applications.
   // Will dynamically disconnect if the trustness status is revoked.
   static void Create(
@@ -44,6 +47,10 @@
       content::RenderFrameHost* host,
       mojo::PendingReceiver<blink::mojom::DeviceAPIService> receiver);
 
+  void GetDeviceAttribute(
+      base::OnceCallback<void(DeviceAttributeCallback)> handler,
+      DeviceAttributeCallback callback);
+
   void OnDisposingIfNeeded();
 
   content::RenderFrameHost* const host_;
diff --git a/chrome/browser/device_api/device_service_unittest.cc b/chrome/browser/device_api/device_service_unittest.cc
index 5586a88..925cb43 100644
--- a/chrome/browser/device_api/device_service_unittest.cc
+++ b/chrome/browser/device_api/device_service_unittest.cc
@@ -15,13 +15,34 @@
 #include "components/prefs/scoped_user_pref_update.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/navigation_simulator.h"
+#include "content/public/test/web_contents_tester.h"
 #include "url/gurl.h"
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "base/command_line.h"
+#include "base/test/scoped_command_line.h"
+#include "chrome/browser/ash/app_mode/web_app/web_kiosk_app_manager.h"
+#include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
+#include "chrome/common/chrome_switches.h"
+#include "components/user_manager/scoped_user_manager.h"
+#endif
+
 namespace {
 
-constexpr char kDefaultAppInstallUrl[] = "https://example.com/";
+constexpr char kDefaultAppInstallUrl[] = "https://example.com/install";
 constexpr char kTrustedUrl[] = "https://example.com/sample";
 constexpr char kUntrustedUrl[] = "https://non-example.com/sample";
+constexpr char kKioskAppInstallUrl[] = "https://kiosk.com/install";
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+constexpr char kAppEmail[] = "email@example.com";
+constexpr char kKioskAppUrl[] = "https://kiosk.com/sample";
+constexpr char kInvalidKioskAppUrl[] = "https://invalid-kiosk.com/sample";
+#endif
+
+void VerifyErrorMessageResult(blink::mojom::DeviceAttributeResultPtr result) {
+  result->is_error_message();
+}
 
 }  // namespace
 
@@ -30,6 +51,7 @@
   void SetUp() override {
     ChromeRenderViewHostTestHarness::SetUp();
     InstallTrustedApp();
+    SetAllowedOrigin();
   }
 
   void InstallTrustedApp() {
@@ -46,15 +68,28 @@
     update->ClearList();
   }
 
-  void TryCreatingService(const GURL& url) {
-    content::NavigationSimulator::NavigateAndCommitFromBrowser(web_contents(),
+  void SetAllowedOrigin() {
+    base::Value allowed_origins(base::Value::Type::LIST);
+    allowed_origins.Append(base::Value(kTrustedUrl));
+    allowed_origins.Append(base::Value(kKioskAppInstallUrl));
+    profile()->GetPrefs()->Set(prefs::kDeviceAttributesAllowedForOrigins,
+                               allowed_origins);
+  }
+
+  void RemoveAllowedOrigin() {
+    ListPrefUpdate update(profile()->GetPrefs(),
+                          prefs::kDeviceAttributesAllowedForOrigins);
+    update->ClearList();
+  }
+
+  void TryCreatingService(content::WebContents* web_contents, const GURL& url) {
+    content::NavigationSimulator::NavigateAndCommitFromBrowser(web_contents,
                                                                url);
     DeviceServiceImpl::Create(main_rfh(), remote_.BindNewPipeAndPassReceiver());
   }
 
-  void SetWebAppDeviceAttributesQueryPref(bool allowed) {
-    profile()->GetPrefs()->SetBoolean(
-        prefs::kManagedWebAppsAccessToDeviceAttributesAllowed, allowed);
+  void TryCreatingService(const GURL& url) {
+    TryCreatingService(web_contents(), url);
   }
 
   mojo::Remote<blink::mojom::DeviceAPIService>* remote() { return &remote_; }
@@ -69,20 +104,105 @@
   ASSERT_TRUE(remote()->is_connected());
 }
 
-TEST_F(DeviceAPIServiceTest, EnableServiceByTurnOnPrefs) {
-  SetWebAppDeviceAttributesQueryPref(true);
+TEST_F(DeviceAPIServiceTest, ReportErrorForDisallowedOrigin) {
   TryCreatingService(GURL(kTrustedUrl));
+  RemoveAllowedOrigin();
+
+  remote()->get()->GetDirectoryId(base::BindOnce(VerifyErrorMessageResult));
+  remote()->get()->GetHostname(base::BindOnce(VerifyErrorMessageResult));
+  remote()->get()->GetSerialNumber(base::BindOnce(VerifyErrorMessageResult));
+  remote()->get()->GetAnnotatedAssetId(
+      base::BindOnce(VerifyErrorMessageResult));
+  remote()->get()->GetAnnotatedLocation(
+      base::BindOnce(VerifyErrorMessageResult));
   remote()->FlushForTesting();
   ASSERT_TRUE(remote()->is_connected());
 }
 
-TEST_F(DeviceAPIServiceTest, DisableServiceByTurnOffPrefs) {
-  SetWebAppDeviceAttributesQueryPref(false);
+// The service should be disabled in the Incognito mode.
+TEST_F(DeviceAPIServiceTest, IncognitoProfile) {
+  std::unique_ptr<content::WebContents> incognito_web_contents =
+      content::WebContentsTester::CreateTestWebContents(
+          profile()->GetPrimaryOTRProfile(/*create_if_needed=*/true), nullptr);
+  TryCreatingService(incognito_web_contents.get(), GURL(kTrustedUrl));
+
+  remote()->FlushForTesting();
+  ASSERT_FALSE(remote()->is_connected());
+}
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+
+class DeviceAPIServiceWithKioskUserTest : public DeviceAPIServiceTest {
+ public:
+  DeviceAPIServiceWithKioskUserTest()
+      : fake_user_manager_(new ash::FakeChromeUserManager()),
+        scoped_user_manager_(base::WrapUnique(fake_user_manager_)) {}
+
+  void SetUp() override {
+    DeviceAPIServiceTest::SetUp();
+    command_line_.GetProcessCommandLine()->AppendSwitch(
+        switches::kForceAppMode);
+    account_id_ = AccountId::FromUserEmail(kAppEmail);
+    app_manager_ = std::make_unique<ash::WebKioskAppManager>();
+  }
+
+  void TearDown() override {
+    app_manager_.reset();
+    DeviceAPIServiceTest::TearDown();
+  }
+
+  void LoginKioskUser() {
+    app_manager()->AddAppForTesting(account_id(), GURL(kKioskAppInstallUrl));
+    fake_user_manager()->AddWebKioskAppUser(account_id());
+    fake_user_manager()->LoginUser(account_id());
+  }
+
+  ash::FakeChromeUserManager* fake_user_manager() const {
+    return fake_user_manager_;
+  }
+
+  const AccountId& account_id() const { return account_id_; }
+
+  ash::WebKioskAppManager* app_manager() const { return app_manager_.get(); }
+
+ private:
+  ash::FakeChromeUserManager* fake_user_manager_;
+  user_manager::ScopedUserManager scoped_user_manager_;
+  base::test::ScopedCommandLine command_line_;
+  AccountId account_id_;
+  std::unique_ptr<ash::WebKioskAppManager> app_manager_;
+};
+
+// The service should be enabled if the current origin is same as the origin of
+// Kiosk app.
+TEST_F(DeviceAPIServiceWithKioskUserTest, EnableServiceForKioskOrigin) {
+  LoginKioskUser();
+  TryCreatingService(GURL(kKioskAppUrl));
+  remote()->FlushForTesting();
+  ASSERT_TRUE(remote()->is_connected());
+}
+
+// The service should be disabled if the current origin is different from the
+// origin of Kiosk app.
+TEST_F(DeviceAPIServiceWithKioskUserTest, DisableServiceForInvalidOrigin) {
+  LoginKioskUser();
+  TryCreatingService(GURL(kInvalidKioskAppUrl));
+  remote()->FlushForTesting();
+  ASSERT_FALSE(remote()->is_connected());
+}
+
+// The service should be disabled if the current origin is different from the
+// origin of Kiosk app, even if it is trusted (force-installed).
+TEST_F(DeviceAPIServiceWithKioskUserTest,
+       DisableServiceForNonKioskTrustedOrigin) {
+  LoginKioskUser();
   TryCreatingService(GURL(kTrustedUrl));
   remote()->FlushForTesting();
   ASSERT_FALSE(remote()->is_connected());
 }
 
+#endif
+
 class DeviceAPIServiceWithFeatureFlagTest : public DeviceAPIServiceTest {
  public:
   DeviceAPIServiceWithFeatureFlagTest() {
diff --git a/chrome/browser/devtools/devtools_window.cc b/chrome/browser/devtools/devtools_window.cc
index 0dfdbb15..eccb36f 100644
--- a/chrome/browser/devtools/devtools_window.cc
+++ b/chrome/browser/devtools/devtools_window.cc
@@ -1281,7 +1281,10 @@
                                         const GURL& target_url,
                                         WebContents* new_contents) {
   if (target_url.SchemeIs(content::kChromeDevToolsScheme) &&
-      target_url.path().rfind("toolbox.html") != std::string::npos) {
+      (target_url.path().rfind("device_mode_emulation_frame.html") !=
+           std::string::npos
+       // TODO(crbug.com/1228264): Remove toolbox.html allowance
+       || target_url.path().rfind("toolbox.html") != std::string::npos)) {
     CHECK(can_dock_);
 
     // Ownership will be passed in DevToolsWindow::AddNewContents.
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index e36d5d3..baa10ae 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -4987,6 +4987,11 @@
     "expiry_milestone": 94
   },
   {
+    "name": "sharing-hub-link-toggle",
+    "owners": [ "sophey", "chrome-sharing-eng@google.com" ],
+    "expiry_milestone": 98
+  },
+  {
     "name": "sharing-prefer-vapid",
     "owners": [ "//chrome/browser/sharing/OWNERS" ],
     "expiry_milestone": 87
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 63e35fd..7495b4a4 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -3500,6 +3500,10 @@
     "Enable showing the start surface when launching Chrome via the "
     "launcher.";
 
+const char kSharingHubLinkToggleName[] = "Sharing Hub Link Toggle";
+const char kSharingHubLinkToggleDescription[] =
+    "Enable the link toggle in the Sharing Hub.";
+
 const char kStrictSiteIsolationName[] = "Strict site isolation";
 const char kStrictSiteIsolationDescription[] =
     "Security mode that enables site isolation for all sites (SitePerProcess). "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 581b8862..359a13d 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1996,6 +1996,9 @@
 extern const char kStartSurfaceAndroidName[];
 extern const char kStartSurfaceAndroidDescription[];
 
+extern const char kSharingHubLinkToggleName[];
+extern const char kSharingHubLinkToggleDescription[];
+
 extern const char kStrictSiteIsolationName[];
 extern const char kStrictSiteIsolationDescription[];
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index 68f1ef1b..b311c038 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -236,6 +236,7 @@
     &kServiceManagerForDownload,
     &kShareButtonInTopToolbar,
     &kSharedClipboardUI,
+    &kSharingHubLinkToggle,
     &kSingleTouchSelect,
     &kSpannableInlineAutocomplete,
     &kSpecialLocaleWrapper,
@@ -648,6 +649,9 @@
 const base::Feature kShareButtonInTopToolbar{"ShareButtonInTopToolbar",
                                              base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kSharingHubLinkToggle{"SharingHubLinkToggle",
+                                          base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kSingleTouchSelect{"SingleTouchSelect",
                                        base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h
index 186bc00..8186fa79 100644
--- a/chrome/browser/flags/android/chrome_feature_list.h
+++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -116,6 +116,7 @@
 extern const base::Feature kServiceManagerForBackgroundPrefetch;
 extern const base::Feature kServiceManagerForDownload;
 extern const base::Feature kShareButtonInTopToolbar;
+extern const base::Feature kSharingHubLinkToggle;
 extern const base::Feature kSingleTouchSelect;
 extern const base::Feature kSpannableInlineAutocomplete;
 extern const base::Feature kSpecialLocaleWrapper;
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index 203bfaa..169b0e45 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -472,6 +472,7 @@
     public static final String SHARED_CLIPBOARD_UI = "SharedClipboardUI";
     public static final String SHARED_HIGHLIGHTING_V2 = "SharedHighlightingV2";
     public static final String SHARED_HIGHLIGHTING_AMP = "SharedHighlightingAmp";
+    public static final String SHARING_HUB_LINK_TOGGLE = "SharingHubLinkToggle";
     public static final String SINGLE_TOUCH_SELECT = "SingleTouchSelect";
     public static final String SHOW_TRUSTED_PUBLISHER_URL = "ShowTrustedPublisherURL";
     public static final String SMART_SUGGESTION_FOR_LARGE_DOWNLOADS =
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageSettings.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageSettings.java
index ab4b0f0..4fcf6954 100644
--- a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageSettings.java
+++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageSettings.java
@@ -69,8 +69,8 @@
         getActivity().setTitle(R.string.language_settings);
         mPrefChangeRegistrar = new PrefChangeRegistrar();
 
-        // Show the detailed language settings if DETAILED_LANGUAGE_SETTINGS feature is enabled.
-        if (ChromeFeatureList.isEnabled(ChromeFeatureList.DETAILED_LANGUAGE_SETTINGS)) {
+        // Create the correct version of language settings.
+        if (shouldShowDetailedPreferences()) {
             createDetailedPreferences(savedInstanceState, rootKey);
         } else {
             createBasicPreferences(savedInstanceState, rootKey);
@@ -80,6 +80,18 @@
     }
 
     /**
+     * The detailed language preferences should be shown if the flag to enable them or the app
+     * language prompt is enabled. If neither flag is enabled, but an override language is set the
+     * detailed language preferences should still be shown.
+     * @return Whether or not to show the detailed language preferences.
+     */
+    private boolean shouldShowDetailedPreferences() {
+        return ChromeFeatureList.isEnabled(ChromeFeatureList.DETAILED_LANGUAGE_SETTINGS)
+                || ChromeFeatureList.isEnabled(ChromeFeatureList.APP_LANGUAGE_PROMPT)
+                || GlobalAppLocaleController.getInstance().isOverridden();
+    }
+
+    /**
      * Create the old language and translate settings page.  Delete once no longer used.
      */
     private void createBasicPreferences(Bundle savedInstanceState, String rootKey) {
diff --git a/chrome/browser/password_manager/android/password_store_bridge.cc b/chrome/browser/password_manager/android/password_store_bridge.cc
index 48c9928..d4914d8b 100644
--- a/chrome/browser/password_manager/android/password_store_bridge.cc
+++ b/chrome/browser/password_manager/android/password_store_bridge.cc
@@ -89,7 +89,8 @@
 }
 
 void PasswordStoreBridge::ClearAllPasswords(JNIEnv* env) {
-  password_store_->ClearStore(
+  password_store_->RemoveLoginsCreatedBetween(
+      base::Time(), base::Time::Max(),
       base::BindOnce(&PasswordStoreBridge::OnPasswordStoreCleared,
                      weak_factory_.GetWeakPtr()));
 }
diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc
index 9d984faa..327a2dd 100644
--- a/chrome/browser/pdf/pdf_extension_test.cc
+++ b/chrome/browser/pdf/pdf_extension_test.cc
@@ -1474,7 +1474,14 @@
   return true;
 }
 
-IN_PROC_BROWSER_TEST_F(PDFExtensionTest, PdfAccessibilityInIframe) {
+// Flaky, see crbug.com/1228762
+#if defined(OS_CHROMEOS)
+#define MAYBE_PdfAccessibilityInIframe DISABLED_PdfAccessibilityInIframe
+#else
+#define MAYBE_PdfAccessibilityInIframe PdfAccessibilityInIframe
+#endif
+
+IN_PROC_BROWSER_TEST_F(PDFExtensionTest, MAYBE_PdfAccessibilityInIframe) {
   content::BrowserAccessibilityState::GetInstance()->EnableAccessibility();
   GURL test_iframe_url(embedded_test_server()->GetURL("/pdf/test-iframe.html"));
   ui_test_utils::NavigateToURL(browser(), test_iframe_url);
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index ed53c564..51ac33d 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -1409,9 +1409,9 @@
   { key::kFetchKeepaliveDurationSecondsOnShutdown,
     prefs::kFetchKeepaliveDurationOnShutdown,
     base::Value::Type::INTEGER },
-  { key::kManagedWebAppsAccessToDeviceAttributesAllowed,
-    prefs::kManagedWebAppsAccessToDeviceAttributesAllowed,
-    base::Value::Type::BOOLEAN },
+  { key::kDeviceAttributesAllowedForOrigins,
+    prefs::kDeviceAttributesAllowedForOrigins,
+    base::Value::Type::LIST },
 #endif  // !defined(OS_ANDROID)
 
   { key::kSuppressDifferentOriginSubframeDialogs,
diff --git a/chrome/browser/profiles/gaia_info_update_service_unittest.cc b/chrome/browser/profiles/gaia_info_update_service_unittest.cc
index 2bbb2661..5d7c931c 100644
--- a/chrome/browser/profiles/gaia_info_update_service_unittest.cc
+++ b/chrome/browser/profiles/gaia_info_update_service_unittest.cc
@@ -18,7 +18,6 @@
 #include "chrome/browser/profiles/profile_attributes_entry.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_downloader.h"
-#include "chrome/browser/profiles/profile_info_cache_unittest.h"
 #include "chrome/browser/profiles/profiles_state.h"
 #include "chrome/browser/signin/chrome_signin_client_factory.h"
 #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
@@ -32,7 +31,9 @@
 #include "components/signin/public/base/signin_pref_names.h"
 #include "components/signin/public/identity_manager/account_info.h"
 #include "components/sync_preferences/pref_service_syncable.h"
+#include "content/public/test/browser_task_environment.h"
 #include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/image/image_unittest_util.h"
 
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc
index 88309c7..01f7289 100644
--- a/chrome/browser/profiles/profile.cc
+++ b/chrome/browser/profiles/profile.cc
@@ -62,6 +62,7 @@
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
+#include "chrome/common/chrome_constants.h"
 #include "chromeos/lacros/lacros_chrome_service_impl.h"
 #endif
 
@@ -409,6 +410,14 @@
          profile_metrics::BrowserProfileType::kSystem;
 }
 
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+// static
+bool Profile::IsMainProfilePath(base::FilePath profile_path) {
+  // The main profile is the one with the "Default" path.
+  return profile_path.BaseName().value() == chrome::kInitialProfile;
+}
+#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
+
 bool Profile::IsPrimaryOTRProfile() const {
   return IsOffTheRecord() && GetOTRProfileID() == OTRProfileID::PrimaryID();
 }
diff --git a/chrome/browser/profiles/profile.h b/chrome/browser/profiles/profile.h
index b28d8706..e3e819d 100644
--- a/chrome/browser/profiles/profile.h
+++ b/chrome/browser/profiles/profile.h
@@ -445,11 +445,14 @@
   bool IsSystemProfile() const;
 
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
-  // Returns `true` if this is the first/initial Profile in Lacros, and - for
-  // regular sessions, if this Profile has the Device Account logged in.
+  // Returns `true` if this is the first/initial Profile path in Lacros, and -
+  // for regular sessions, if this Profile has the Device Account logged in.
   // For non-regular sessions (Guest Sessions, Managed Guest Sessions) which do
   // not have the concept of a Device Account, the latter condition is not
   // checked.
+  static bool IsMainProfilePath(base::FilePath profile_path);
+
+  // Returns true if this is the main profile as defined above.
   virtual bool IsMainProfile() const = 0;
 #endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
 
diff --git a/chrome/browser/profiles/profile_attributes_storage.h b/chrome/browser/profiles/profile_attributes_storage.h
index 9c4233e..b11f9508 100644
--- a/chrome/browser/profiles/profile_attributes_storage.h
+++ b/chrome/browser/profiles/profile_attributes_storage.h
@@ -182,12 +182,11 @@
   void DisableProfileMetricsForTesting();
 
  private:
-  FRIEND_TEST_ALL_PREFIXES(ProfileInfoCacheTest, EntriesInAttributesStorage);
   FRIEND_TEST_ALL_PREFIXES(ProfileAttributesStorageTest,
                            DownloadHighResAvatarTest);
   FRIEND_TEST_ALL_PREFIXES(ProfileAttributesStorageTest,
                            NothingToDownloadHighResAvatarTest);
-  FRIEND_TEST_ALL_PREFIXES(ProfileInfoCacheTest,
+  FRIEND_TEST_ALL_PREFIXES(ProfileAttributesStorageTest,
                            MigrateLegacyProfileNamesAndRecomputeIfNeeded);
 
   // Starts downloading the high res avatar at index |icon_index| for profile
diff --git a/chrome/browser/profiles/profile_attributes_storage_unittest.cc b/chrome/browser/profiles/profile_attributes_storage_unittest.cc
index 12339d6b..145a3fdb 100644
--- a/chrome/browser/profiles/profile_attributes_storage_unittest.cc
+++ b/chrome/browser/profiles/profile_attributes_storage_unittest.cc
@@ -10,6 +10,8 @@
 #include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/format_macros.h"
+#include "base/scoped_observation.h"
+#include "base/strings/strcat.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/metrics/histogram_tester.h"
@@ -25,10 +27,12 @@
 #include "chrome/browser/signin/signin_util.h"
 #include "chrome/browser/supervised_user/supervised_user_constants.h"
 #include "chrome/browser/ui/ui_features.h"
+#include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile_manager.h"
 #include "components/account_id/account_id.h"
 #include "components/profile_metrics/state.h"
+#include "components/sync_preferences/pref_service_syncable.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -147,6 +151,12 @@
 #endif  // defined(OS_WIN)
 }
 
+std::u16string ConcatenateGaiaAndProfileNames(
+    const std::u16string& gaia_name,
+    const std::u16string& profile_name) {
+  return base::StrCat({gaia_name, u" (", profile_name, u")"});
+}
+
 }  // namespace
 
 class ProfileAttributesStorageTest : public testing::Test {
@@ -162,8 +172,6 @@
     EnableObserver();
   }
 
-  void TearDown() override { DisableObserver(); }
-
   base::FilePath GetProfilePath(const std::string& base_name) {
     return testing_profile_manager_.profile_manager()->user_data_dir().
         AppendASCII(base_name);
@@ -185,8 +193,8 @@
     EXPECT_CALL(observer_, OnProfileHostedDomainChanged(_)).Times(0);
   }
 
-  void EnableObserver() { storage()->AddObserver(&observer_); }
-  void DisableObserver() { storage()->RemoveObserver(&observer_); }
+  void EnableObserver() { scoped_observation_.Observe(storage()); }
+  void DisableObserver() { scoped_observation_.Reset(); }
 
   void AddCallExpectationsForRemoveProfile(size_t profile_number) {
     base::FilePath profile_path = GetProfilePath(
@@ -232,16 +240,25 @@
   }
 
   void ResetProfileAttributesStorage() {
+    bool was_observing = scoped_observation_.IsObserving();
     DisableObserver();
     testing_profile_manager_.DeleteProfileAttributesStorage();
-    EnableObserver();
+    // Restore observation if there was any.
+    if (was_observing)
+      EnableObserver();
   }
 
-  TestingProfileManager testing_profile_manager_;
+  TestingProfileManager& testing_profile_manager() {
+    return testing_profile_manager_;
+  }
 
  private:
   content::BrowserTaskEnvironment task_environment_;
+  TestingProfileManager testing_profile_manager_;
   ProfileAttributesTestObserver observer_;
+  base::ScopedObservation<ProfileAttributesStorage,
+                          ProfileAttributesStorage::Observer>
+      scoped_observation_{&observer_};
 };
 
 TEST_F(ProfileAttributesStorageTest, ProfileNotFound) {
@@ -286,6 +303,91 @@
   EXPECT_EQ(u"new_profile_name_1", entry->GetName());
 }
 
+TEST_F(ProfileAttributesStorageTest, AddProfiles) {
+  DisableObserver();  // This test doesn't test observers.
+
+  EXPECT_EQ(0u, storage()->GetNumberOfProfiles());
+  // Avatar icons not used on Android.
+#if !defined(OS_ANDROID)
+  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+#endif
+
+  for (size_t i = 0; i < 4u; ++i) {
+    base::FilePath profile_path =
+        GetProfilePath(base::StringPrintf("path_%zu", i));
+    std::u16string profile_name =
+        base::ASCIIToUTF16(base::StringPrintf("name_%zu", i));
+#if !defined(OS_ANDROID)
+
+    size_t icon_id = GetDefaultAvatarIconResourceIDAtIndex(i);
+    const SkBitmap* icon = rb.GetImageNamed(icon_id).ToSkBitmap();
+
+#endif  // !defined(OS_ANDROID)
+    std::string supervised_user_id;
+#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
+    if (i == 3u)
+      supervised_user_id = supervised_users::kChildAccountSUID;
+#endif
+
+    ProfileAttributesInitParams params;
+    params.profile_path = profile_path;
+    params.profile_name = profile_name;
+    params.icon_index = i;
+    params.supervised_user_id = supervised_user_id;
+    storage()->AddProfile(std::move(params));
+
+    ProfileAttributesEntry* entry =
+        storage()->GetProfileAttributesWithPath(profile_path);
+    entry->SetBackgroundStatus(true);
+    std::u16string gaia_name =
+        base::ASCIIToUTF16(base::StringPrintf("gaia_%zu", i));
+    entry->SetGAIAName(gaia_name);
+
+    EXPECT_EQ(i + 1, storage()->GetNumberOfProfiles());
+    std::u16string expected_profile_name =
+        ConcatenateGaiaAndProfileNames(gaia_name, profile_name);
+
+    EXPECT_EQ(expected_profile_name, entry->GetName());
+
+    EXPECT_EQ(profile_path, entry->GetPath());
+#if !defined(OS_ANDROID)
+    const SkBitmap* actual_icon = entry->GetAvatarIcon().ToSkBitmap();
+    EXPECT_EQ(icon->width(), actual_icon->width());
+    EXPECT_EQ(icon->height(), actual_icon->height());
+#endif
+#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
+    EXPECT_EQ(i == 3u, entry->IsSupervised());
+#else
+    EXPECT_FALSE(entry->IsSupervised());
+    EXPECT_FALSE(entry->IsOmitted());
+#endif  // BUILDFLAG(ENABLE_SUPERVISED_USERS)
+    EXPECT_EQ(supervised_user_id, entry->GetSupervisedUserId());
+  }
+
+  // Reset the storage and test the it reloads correctly.
+  ResetProfileAttributesStorage();
+
+  EXPECT_EQ(4u, storage()->GetNumberOfProfiles());
+  for (size_t i = 0; i < 4u; ++i) {
+    base::FilePath profile_path =
+        GetProfilePath(base::StringPrintf("path_%zu", i));
+    ProfileAttributesEntry* entry =
+        storage()->GetProfileAttributesWithPath(profile_path);
+    std::u16string profile_name =
+        base::ASCIIToUTF16(base::StringPrintf("name_%zu", i));
+    std::u16string gaia_name =
+        base::ASCIIToUTF16(base::StringPrintf("gaia_%zu", i));
+    std::u16string expected_profile_name =
+        ConcatenateGaiaAndProfileNames(gaia_name, profile_name);
+    EXPECT_EQ(expected_profile_name, entry->GetName());
+#if !defined(OS_ANDROID)
+    EXPECT_EQ(i, entry->GetAvatarIconIndex());
+#endif
+    EXPECT_EQ(true, entry->GetBackgroundStatus());
+    EXPECT_EQ(gaia_name, entry->GetGAIAName());
+  }
+}
+
 TEST_F(ProfileAttributesStorageTest, RemoveProfile) {
   EXPECT_EQ(0U, storage()->GetNumberOfProfiles());
 
@@ -311,6 +413,57 @@
   EXPECT_EQ(entry, nullptr);
 }
 
+TEST_F(ProfileAttributesStorageTest, RemoveProfileByAccountId) {
+  DisableObserver();  // This test doesn't test observers.
+  EXPECT_EQ(0u, storage()->GetNumberOfProfiles());
+  const struct {
+    const char* profile_path;
+    const char* profile_name;
+    AccountId account_id;
+    bool is_consented_primary_account;
+  } kTestCases[] = {
+      {"path_1", "name_1", AccountId::FromUserEmailGaiaId("email1", "111111"),
+       true},
+      {"path_2", "name_3", AccountId::FromUserEmailGaiaId("email2", "222222"),
+       true},
+      {"path_3", "name_3", AccountId::FromUserEmailGaiaId("email3", "333333"),
+       false},
+      {"path_4", "name_4", AccountId::FromUserEmailGaiaId("email4", "444444"),
+       false}};
+
+  for (size_t i = 0; i < base::size(kTestCases); ++i) {
+    ProfileAttributesInitParams params;
+    params.profile_path = GetProfilePath(kTestCases[i].profile_path);
+    params.profile_name = base::ASCIIToUTF16(kTestCases[i].profile_name);
+    params.gaia_id = kTestCases[i].account_id.GetGaiaId();
+    params.user_name =
+        base::UTF8ToUTF16(kTestCases[i].account_id.GetUserEmail());
+    params.is_consented_primary_account =
+        kTestCases[i].is_consented_primary_account;
+    storage()->AddProfile(std::move(params));
+    EXPECT_EQ(i + 1, storage()->GetNumberOfProfiles());
+  }
+
+  storage()->RemoveProfileByAccountId(kTestCases[2].account_id);
+  EXPECT_EQ(3u, storage()->GetNumberOfProfiles());
+
+  storage()->RemoveProfileByAccountId(kTestCases[0].account_id);
+  EXPECT_EQ(2u, storage()->GetNumberOfProfiles());
+
+  // This profile is already deleted.
+  storage()->RemoveProfileByAccountId(kTestCases[2].account_id);
+  EXPECT_EQ(2u, storage()->GetNumberOfProfiles());
+
+  // Remove profile by partial match.
+  storage()->RemoveProfileByAccountId(
+      AccountId::FromUserEmail(kTestCases[1].account_id.GetUserEmail()));
+  EXPECT_EQ(1u, storage()->GetNumberOfProfiles());
+
+  // Remove last profile.
+  storage()->RemoveProfileByAccountId(kTestCases[3].account_id);
+  EXPECT_EQ(0u, storage()->GetNumberOfProfiles());
+}
+
 TEST_F(ProfileAttributesStorageTest, MultipleProfiles) {
   EXPECT_EQ(0U, storage()->GetNumberOfProfiles());
 
@@ -343,6 +496,53 @@
   }
 }
 
+TEST_F(ProfileAttributesStorageTest, AddStubProfile) {
+  DisableObserver();  // This test doesn't test observers.
+  EXPECT_EQ(0u, storage()->GetNumberOfProfiles());
+
+  // Add some profiles with and without a '.' in their paths.
+  const struct {
+    const char* profile_path;
+    const char* profile_name;
+  } kTestCases[] = {
+      {"path.test0", "name_0"},
+      {"path_test1", "name_1"},
+      {"path.test2", "name_2"},
+      {"path_test3", "name_3"},
+  };
+  const size_t kNumProfiles = base::size(kTestCases);
+
+  for (auto test_case : kTestCases) {
+    base::FilePath profile_path = GetProfilePath(test_case.profile_path);
+    std::u16string profile_name = base::ASCIIToUTF16(test_case.profile_name);
+
+    ProfileAttributesInitParams params;
+    params.profile_path = profile_path;
+    params.profile_name = profile_name;
+    storage()->AddProfile(std::move(params));
+    ProfileAttributesEntry* entry =
+        storage()->GetProfileAttributesWithPath(profile_path);
+    EXPECT_TRUE(entry);
+    EXPECT_EQ(profile_name, entry->GetName());
+  }
+
+  ASSERT_EQ(kNumProfiles, storage()->GetNumberOfProfiles());
+
+  // Check that the profiles can be extracted from the local state.
+  std::vector<std::string> names;
+  PrefService* local_state = g_browser_process->local_state();
+  const base::DictionaryValue* attributes =
+      local_state->GetDictionary(prefs::kProfileAttributes);
+  for (const auto kv : attributes->DictItems()) {
+    const base::Value& info = kv.second;
+    const std::string* name = info.FindStringKey("name");
+    names.push_back(*name);
+  }
+
+  for (size_t i = 0; i < kNumProfiles; i++)
+    ASSERT_FALSE(names[i].empty());
+}
+
 TEST_F(ProfileAttributesStorageTest, InitialValues) {
 #if defined(OS_ANDROID)
   // Android has only one default avatar.
@@ -415,6 +615,84 @@
                       /*is_signed_in_with_credential_provider=*/false);
 }
 
+// Checks that ProfileAttributesStorage doesn't crash when
+// ProfileAttributesEntry initialization modifies an attributes entry.
+// This is a regression test for https://crbug.com/1180497.
+TEST_F(ProfileAttributesStorageTest, ModifyEntryWhileInitializing) {
+  DisableObserver();  // This test doesn't test observers.
+  base::FilePath profile_path = GetProfilePath("test");
+  {
+    signin_util::ScopedForceSigninSetterForTesting force_signin_setter(true);
+    AccountId account_id = AccountId::FromUserEmailGaiaId("email", "111111");
+    ProfileAttributesInitParams params;
+    params.profile_path = profile_path;
+    params.profile_name = u"Test";
+    params.gaia_id = account_id.GetGaiaId();
+    params.user_name = base::UTF8ToUTF16(account_id.GetUserEmail());
+    storage()->AddProfile(std::move(params));
+    ProfileAttributesEntry* entry =
+        storage()->GetProfileAttributesWithPath(profile_path);
+    // Set up the state so that ProfileAttributesEntry::Initialize() will modify
+    // the entry.
+    entry->LockForceSigninProfile(true);
+  }
+  // Reinitialize ProfileAttributesStorage.
+  ResetProfileAttributesStorage();
+  storage();  // Should not crash.
+
+  // The IsSigninRequired attribute should be cleaned up.
+  ProfileAttributesEntry* entry =
+      storage()->GetProfileAttributesWithPath(profile_path);
+  EXPECT_FALSE(entry->IsSigninRequired());
+}
+
+TEST_F(ProfileAttributesStorageTest, ProfileNamesOnInit) {
+  DisableObserver();  // This test doesn't test observers.
+  // Set up the storage with two profiles having the same GAIA given name.
+  // The second profile also has a profile name matching the GAIA given name.
+  std::u16string kDefaultProfileName = u"Person 1";
+  std::u16string kCommonName = u"Joe";
+
+  // Create and initialize the first profile.
+  base::FilePath path_1 = GetProfilePath("path_1");
+  ProfileAttributesInitParams params_1;
+  params_1.profile_path = path_1;
+  params_1.profile_name = kDefaultProfileName;
+  storage()->AddProfile(std::move(params_1));
+  ProfileAttributesEntry* entry_1 =
+      storage()->GetProfileAttributesWithPath(path_1);
+  entry_1->SetGAIAGivenName(kCommonName);
+  EXPECT_EQ(entry_1->GetName(), kCommonName);
+
+  // Create and initialize the second profile.
+  base::FilePath path_2 = GetProfilePath("path_2");
+  ProfileAttributesInitParams params_2;
+  params_2.profile_path = path_2;
+  params_2.profile_name = kCommonName;
+  storage()->AddProfile(std::move(params_2));
+  ProfileAttributesEntry* entry_2 =
+      storage()->GetProfileAttributesWithPath(path_2);
+  entry_2->SetGAIAGivenName(kCommonName);
+  EXPECT_EQ(entry_2->GetName(), kCommonName);
+
+  // The first profile name should be modified.
+  EXPECT_EQ(entry_1->GetName(),
+            ConcatenateGaiaAndProfileNames(kCommonName, kDefaultProfileName));
+
+  // Reset the storage to test profile names set on initialization.
+  ResetProfileAttributesStorage();
+  entry_1 = storage()->GetProfileAttributesWithPath(path_1);
+  entry_2 = storage()->GetProfileAttributesWithPath(path_2);
+
+  // Freshly initialized entries should not report name changes.
+  EXPECT_FALSE(entry_1->HasProfileNameChanged());
+  EXPECT_FALSE(entry_2->HasProfileNameChanged());
+
+  EXPECT_EQ(entry_1->GetName(),
+            ConcatenateGaiaAndProfileNames(kCommonName, kDefaultProfileName));
+  EXPECT_EQ(entry_2->GetName(), kCommonName);
+}
+
 TEST_F(ProfileAttributesStorageTest, EntryAccessors) {
   AddTestingProfile();
 
@@ -611,6 +889,144 @@
   EXPECT_EQ("foo", entry->GetGAIAId());
 }
 
+TEST_F(ProfileAttributesStorageTest, GAIAName) {
+  DisableObserver();  // This test doesn't test observers.
+
+  base::FilePath profile_path_1 = GetProfilePath("path_1");
+  ProfileAttributesInitParams params_1;
+  params_1.profile_path = profile_path_1;
+  params_1.profile_name = u"Person 1";
+  storage()->AddProfile(std::move(params_1));
+  ProfileAttributesEntry* entry_1 =
+      storage()->GetProfileAttributesWithPath(profile_path_1);
+  base::FilePath profile_path_2 = GetProfilePath("path_2");
+  ProfileAttributesInitParams params_2;
+  params_2.profile_path = profile_path_2;
+  params_2.profile_name = u"Person 2";
+  storage()->AddProfile(std::move(params_2));
+  ProfileAttributesEntry* entry_2 =
+      storage()->GetProfileAttributesWithPath(profile_path_2);
+
+  // Sanity check.
+  EXPECT_TRUE(entry_1->GetGAIAName().empty());
+  EXPECT_TRUE(entry_2->GetGAIAName().empty());
+
+  // Set GAIA name.
+  std::u16string gaia_name(u"Pat Smith");
+  entry_2->SetGAIAName(gaia_name);
+  // Since there is a GAIA name, we use that as a display name.
+  EXPECT_TRUE(entry_1->GetGAIAName().empty());
+  EXPECT_EQ(gaia_name, entry_2->GetGAIAName());
+  EXPECT_EQ(gaia_name, entry_2->GetName());
+
+  std::u16string custom_name(u"Custom name");
+  entry_2->SetLocalProfileName(custom_name, false);
+
+  std::u16string expected_profile_name =
+      ConcatenateGaiaAndProfileNames(gaia_name, custom_name);
+  EXPECT_EQ(expected_profile_name, entry_2->GetName());
+  EXPECT_EQ(gaia_name, entry_2->GetGAIAName());
+}
+
+TEST_F(ProfileAttributesStorageTest, ConcatenateGaiaNameAndProfileName) {
+  DisableObserver();  // This test doesn't test observers.
+
+  // We should only append the profile name to the GAIA name if:
+  // - The user has chosen a profile name on purpose.
+  // - Two profiles has the sama GAIA name and we need to show it to
+  //   clear ambiguity.
+  // If one of the two conditions hold, we will show the profile name in this
+  // format |GAIA name (Profile local name)|
+  // Single profile.
+  base::FilePath profile_path_1 = GetProfilePath("path_1");
+  ProfileAttributesInitParams params_1;
+  params_1.profile_path = profile_path_1;
+  params_1.profile_name = u"Person 1";
+  storage()->AddProfile(std::move(params_1));
+  ProfileAttributesEntry* entry_1 =
+      storage()->GetProfileAttributesWithPath(profile_path_1);
+  EXPECT_EQ(u"Person 1", entry_1->GetName());
+  entry_1->SetGAIAName(u"Patt Smith");
+  EXPECT_EQ(u"Patt Smith", entry_1->GetName());
+  entry_1->SetGAIAGivenName(u"Patt");
+  EXPECT_EQ(u"Patt", entry_1->GetName());
+
+  // Set a custom profile name.
+  entry_1->SetLocalProfileName(u"Work", false);
+  EXPECT_EQ(u"Patt (Work)", entry_1->GetName());
+
+  // Set the profile name to be equal to GAIA name.
+  entry_1->SetLocalProfileName(u"patt", false);
+  EXPECT_EQ(u"Patt", entry_1->GetName());
+
+  // Multiple profiles.
+  // Add another profile with the same GAIA name and a default profile name.
+  base::FilePath profile_path_2 = GetProfilePath("path_2");
+  ProfileAttributesInitParams params_2;
+  params_2.profile_path = profile_path_2;
+  params_2.profile_name = u"Person 2";
+  storage()->AddProfile(std::move(params_2));
+  ProfileAttributesEntry* entry_2 =
+      storage()->GetProfileAttributesWithPath(profile_path_2);
+  EXPECT_EQ(u"Patt", entry_1->GetName());
+  EXPECT_EQ(u"Person 2", entry_2->GetName());
+
+  entry_1->SetLocalProfileName(u"Work", false);
+  EXPECT_EQ(u"Patt (Work)", entry_1->GetName());
+  EXPECT_EQ(u"Person 2", entry_2->GetName());
+
+  // A second profile with a different GAIA name should not affect the first
+  // profile.
+  entry_2->SetGAIAGivenName(u"Olly");
+  EXPECT_EQ(u"Patt (Work)", entry_1->GetName());
+  EXPECT_EQ(u"Olly", entry_2->GetName());
+
+  // Mark profile name as default.
+  entry_1->SetLocalProfileName(u"Person 1", true);
+  EXPECT_EQ(u"Patt", entry_1->GetName());
+  EXPECT_EQ(u"Olly", entry_2->GetName());
+
+  // Add a third profile with the same GAIA name as the first.
+  // The two profiles are marked as using default profile names.
+  base::FilePath profile_path_3 = GetProfilePath("path_3");
+  ProfileAttributesInitParams params_3;
+  params_3.profile_path = profile_path_3;
+  params_3.profile_name = u"Person 3";
+  storage()->AddProfile(std::move(params_3));
+  ProfileAttributesEntry* entry_3 =
+      storage()->GetProfileAttributesWithPath(profile_path_3);
+  entry_3->SetGAIAName(u"Patt Smith");
+  EXPECT_EQ(u"Patt", entry_1->GetName());
+  EXPECT_EQ(u"Patt Smith", entry_3->GetName());
+
+  // Two profiles with same GAIA name and default profile name.
+  // Empty GAIA given name.
+  entry_3->SetGAIAName(u"Patt");
+  EXPECT_EQ(u"Patt (Person 1)", entry_1->GetName());
+  EXPECT_EQ(u"Patt (Person 3)", entry_3->GetName());
+  // Set GAIA given name.
+  entry_3->SetGAIAGivenName(u"Patt");
+  EXPECT_EQ(u"Patt (Person 1)", entry_1->GetName());
+  EXPECT_EQ(u"Patt (Person 3)", entry_3->GetName());
+
+  // Customize the profile name for one of the two profiles.
+  entry_3->SetLocalProfileName(u"Personal", false);
+  EXPECT_EQ(u"Patt", entry_1->GetName());
+  EXPECT_EQ(u"Patt (Personal)", entry_3->GetName());
+
+  // Set one of the profile names to be equal to GAIA name, we should show
+  // the profile name even if it is Person n to clear ambiguity.
+  entry_3->SetLocalProfileName(u"patt", false);
+  EXPECT_EQ(u"Patt (Person 1)", entry_1->GetName());
+  EXPECT_EQ(u"Patt", entry_3->GetName());
+
+  // Never show the profile name if it is equal GAIA name.
+  entry_1->SetLocalProfileName(u"Patt", false);
+  EXPECT_EQ(u"Patt", entry_1->GetName());
+  EXPECT_EQ(u"Patt", entry_3->GetName());
+  EXPECT_EQ(u"Olly", entry_2->GetName());
+}
+
 TEST_F(ProfileAttributesStorageTest, SupervisedUsersAccessors) {
   AddTestingProfile();
 
@@ -639,6 +1055,33 @@
 #endif  // BUILDFLAG(ENABLE_SUPERVISED_USERS)
 }
 
+#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
+TEST_F(ProfileAttributesStorageTest, CreateSupervisedTestingProfile) {
+  DisableObserver();  // This test doesn't test observers.
+
+  base::FilePath path_1 =
+      testing_profile_manager().CreateTestingProfile("default")->GetPath();
+  std::u16string supervised_user_name = u"Supervised User";
+  base::FilePath path_2 =
+      testing_profile_manager()
+          .CreateTestingProfile(
+              "test1", std::unique_ptr<sync_preferences::PrefServiceSyncable>(),
+              supervised_user_name, 0, supervised_users::kChildAccountSUID,
+              TestingProfile::TestingFactories())
+          ->GetPath();
+  base::FilePath profile_paths[] = {path_1, path_2};
+  for (const base::FilePath& path : profile_paths) {
+    ProfileAttributesEntry* entry =
+        storage()->GetProfileAttributesWithPath(path);
+    bool is_supervised = entry->GetName() == supervised_user_name;
+    EXPECT_EQ(is_supervised, entry->IsSupervised());
+    std::string supervised_user_id =
+        is_supervised ? supervised_users::kChildAccountSUID : "";
+    EXPECT_EQ(supervised_user_id, entry->GetSupervisedUserId());
+  }
+}
+#endif
+
 TEST_F(ProfileAttributesStorageTest, ReSortTriggered) {
   DisableObserver();  // No need to test observers in this test.
 
@@ -1392,3 +1835,116 @@
   EXPECT_TRUE(gfx::test::AreImagesEqual(gaia_image, image_loaded));
 }
 #endif  // !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
+
+#if !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
+TEST_F(ProfileAttributesStorageTest,
+       MigrateLegacyProfileNamesAndRecomputeIfNeeded) {
+  DisableObserver();  // This test doesn't test observers.
+  EXPECT_EQ(0U, storage()->GetNumberOfProfiles());
+  // Mimic a pre-existing Directory with profiles that has legacy profile
+  // names.
+  const struct {
+    const char* profile_path;
+    const char* profile_name;
+    bool is_using_default_name;
+  } kTestCases[] = {
+      {"path_1", "Default Profile", true}, {"path_2", "First user", true},
+      {"path_3", "Lemonade", true},        {"path_4", "Batman", true},
+      {"path_5", "Batman", false},         {"path_6", "Person 2", true},
+      {"path_7", "Person 3", true},        {"path_8", "Person 1", true},
+      {"path_9", "Person 2", true},        {"path_10", "Person 1", true},
+      {"path_11", "Smith", false},         {"path_12", "Person 2", true}};
+  const size_t kNumProfiles = base::size(kTestCases);
+
+  ProfileAttributesEntry* entry = nullptr;
+  for (size_t i = 0; i < kNumProfiles; ++i) {
+    base::FilePath profile_path = GetProfilePath(kTestCases[i].profile_path);
+    ProfileAttributesInitParams params;
+    params.profile_path = profile_path;
+    params.profile_name = base::ASCIIToUTF16(kTestCases[i].profile_name);
+    params.icon_index = i;
+    storage()->AddProfile(std::move(params));
+    entry = storage()->GetProfileAttributesWithPath(profile_path);
+    EXPECT_TRUE(entry);
+    entry->SetIsUsingDefaultName(kTestCases[i].is_using_default_name);
+  }
+
+  EXPECT_EQ(kNumProfiles, storage()->GetNumberOfProfiles());
+
+  ResetProfileAttributesStorage();
+  ProfileAttributesStorage::SetLegacyProfileMigrationForTesting(true);
+  storage();
+  ProfileAttributesStorage::SetLegacyProfileMigrationForTesting(false);
+
+  entry = storage()->GetProfileAttributesWithPath(
+      GetProfilePath(kTestCases[4].profile_path));
+  EXPECT_EQ(base::ASCIIToUTF16(kTestCases[4].profile_name), entry->GetName());
+  entry = storage()->GetProfileAttributesWithPath(
+      GetProfilePath(kTestCases[10].profile_path));
+  EXPECT_EQ(base::ASCIIToUTF16(kTestCases[10].profile_name), entry->GetName());
+
+  // Legacy profile names like "Default Profile" and "First user" should be
+  // migrated to "Person %n" type names, i.e. any permutation of "Person %n".
+  std::set<std::u16string> expected_profile_names{
+      u"Person 1", u"Person 2", u"Person 3", u"Person 4", u"Person 5",
+      u"Person 6", u"Person 7", u"Person 8", u"Person 9", u"Person 10"};
+
+  const char* profile_paths[] = {
+      kTestCases[0].profile_path, kTestCases[1].profile_path,
+      kTestCases[2].profile_path, kTestCases[3].profile_path,
+      kTestCases[5].profile_path, kTestCases[6].profile_path,
+      kTestCases[7].profile_path, kTestCases[8].profile_path,
+      kTestCases[9].profile_path, kTestCases[11].profile_path};
+
+  std::set<std::u16string> actual_profile_names;
+  for (auto* path : profile_paths) {
+    entry = storage()->GetProfileAttributesWithPath(GetProfilePath(path));
+    actual_profile_names.insert(entry->GetName());
+  }
+  EXPECT_EQ(actual_profile_names, expected_profile_names);
+}
+#endif  // !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
+
+#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_ANDROID)
+TEST_F(ProfileAttributesStorageTest,
+       DontMigrateLegacyProfileNamesWithoutNewAvatarMenu) {
+  DisableObserver();  // This test doesn't test observers.
+  EXPECT_EQ(0U, storage()->GetNumberOfProfiles());
+
+  const struct {
+    const char* profile_path;
+    const char* profile_name;
+  } kTestCases[] = {{"path_1", "Default Profile"},
+                    {"path_2", "First user"},
+                    {"path_3", "Lemonade"},
+                    {"path_4", "Batman"}};
+  const size_t kNumProfiles = base::size(kTestCases);
+
+  for (size_t i = 0; i < kNumProfiles; ++i) {
+    base::FilePath profile_path = GetProfilePath(kTestCases[i].profile_path);
+    ProfileAttributesInitParams params;
+    params.profile_path = profile_path;
+    params.profile_name = base::ASCIIToUTF16(kTestCases[i].profile_name);
+    params.icon_index = i;
+    storage()->AddProfile(std::move(params));
+    ProfileAttributesEntry* entry =
+        storage()->GetProfileAttributesWithPath(profile_path);
+    EXPECT_TRUE(entry);
+    entry->SetIsUsingDefaultName(true);
+  }
+  EXPECT_EQ(kNumProfiles, storage()->GetNumberOfProfiles());
+
+  ResetProfileAttributesStorage();
+
+  // Profile names should have been preserved.
+  for (size_t i = 0; i < kNumProfiles; ++i) {
+    base::FilePath profile_path = GetProfilePath(kTestCases[i].profile_path);
+    std::u16string profile_name =
+        base::ASCIIToUTF16(kTestCases[i].profile_name);
+    ProfileAttributesEntry* entry =
+        storage()->GetProfileAttributesWithPath(profile_path);
+    EXPECT_TRUE(entry);
+    EXPECT_EQ(profile_name, entry->GetName());
+  }
+}
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_ANDROID)
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index 48028878..5d87d4fff 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -903,7 +903,7 @@
   // Profile must be at "Default" path.
   // `IdentityManager' will guarantee that the Chrome OS Device Account is
   // signed into `this' Profile, if it's the Main Profile.
-  return GetBaseName().value() == chrome::kInitialProfile;
+  return Profile::IsMainProfilePath(GetPath());
 }
 #endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
 
diff --git a/chrome/browser/profiles/profile_info_cache_unittest.cc b/chrome/browser/profiles/profile_info_cache_unittest.cc
deleted file mode 100644
index 27c7245b..0000000
--- a/chrome/browser/profiles/profile_info_cache_unittest.cc
+++ /dev/null
@@ -1,883 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/profiles/profile_info_cache_unittest.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <algorithm>
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/cxx17_backports.h"
-#include "base/files/file_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/time/time.h"
-#include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/profiles/avatar_menu.h"
-#include "chrome/browser/profiles/profile_attributes_init_params.h"
-#include "chrome/browser/profiles/profile_attributes_storage.h"
-#include "chrome/browser/profiles/profile_avatar_icon_util.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/signin/signin_util.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/test/base/testing_browser_process.h"
-#include "components/account_id/account_id.h"
-#include "components/prefs/testing_pref_service.h"
-#include "components/sync_preferences/pref_service_syncable.h"
-#include "content/public/test/browser_task_environment.h"
-#include "content/public/test/test_utils.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/image/image.h"
-#include "ui/gfx/image/image_unittest_util.h"
-
-#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
-#include "chrome/browser/supervised_user/supervised_user_constants.h"
-#endif
-
-using base::ASCIIToUTF16;
-using base::UTF8ToUTF16;
-using content::BrowserThread;
-
-namespace {
-
-#if !defined(OS_ANDROID)
-size_t GetDefaultAvatarIconResourceIDAtIndex(int index) {
-#if defined(OS_WIN)
-  return profiles::GetOldDefaultAvatar2xIconResourceIDAtIndex(index);
-#else
-  return profiles::GetDefaultAvatarIconResourceIDAtIndex(index);
-#endif  // defined(OS_WIN)
-}
-#endif  // !defined(OS_ANDROID)
-
-}  //  namespace
-
-ProfileNameVerifierObserver::ProfileNameVerifierObserver(
-    TestingProfileManager* testing_profile_manager)
-    : testing_profile_manager_(testing_profile_manager) {
-  DCHECK(testing_profile_manager_);
-}
-
-ProfileNameVerifierObserver::~ProfileNameVerifierObserver() {
-}
-
-void ProfileNameVerifierObserver::OnProfileAdded(
-    const base::FilePath& profile_path) {
-  ProfileAttributesEntry* entry =
-      GetCache()->GetProfileAttributesWithPath(profile_path);
-  std::u16string profile_name = entry->GetName();
-  EXPECT_TRUE(profile_names_.find(profile_path) == profile_names_.end());
-  profile_names_.insert({profile_path, profile_name});
-}
-
-void ProfileNameVerifierObserver::OnProfileWillBeRemoved(
-    const base::FilePath& profile_path) {
-  auto it = profile_names_.find(profile_path);
-  EXPECT_TRUE(it != profile_names_.end());
-  profile_names_.erase(it);
-}
-
-void ProfileNameVerifierObserver::OnProfileWasRemoved(
-    const base::FilePath& profile_path,
-    const std::u16string& profile_name) {
-  EXPECT_TRUE(profile_names_.find(profile_path) == profile_names_.end());
-}
-
-void ProfileNameVerifierObserver::OnProfileNameChanged(
-    const base::FilePath& profile_path,
-    const std::u16string& old_profile_name) {
-  ProfileAttributesEntry* entry =
-      GetCache()->GetProfileAttributesWithPath(profile_path);
-  std::u16string new_profile_name = entry->GetName();
-  EXPECT_TRUE(profile_names_[profile_path] == old_profile_name);
-  profile_names_[profile_path] = new_profile_name;
-}
-
-void ProfileNameVerifierObserver::OnProfileAvatarChanged(
-    const base::FilePath& profile_path) {
-  EXPECT_TRUE(profile_names_.find(profile_path) != profile_names_.end());
-}
-
-ProfileAttributesStorage* ProfileNameVerifierObserver::GetCache() {
-  return testing_profile_manager_->profile_attributes_storage();
-}
-
-ProfileInfoCacheTest::ProfileInfoCacheTest()
-    : testing_profile_manager_(TestingBrowserProcess::GetGlobal()),
-      name_observer_(&testing_profile_manager_) {}
-
-ProfileInfoCacheTest::~ProfileInfoCacheTest() {
-}
-
-void ProfileInfoCacheTest::SetUp() {
-  ASSERT_TRUE(testing_profile_manager_.SetUp());
-  testing_profile_manager_.profile_attributes_storage()->AddObserver(
-      &name_observer_);
-}
-
-void ProfileInfoCacheTest::TearDown() {
-  // Drain remaining tasks to make sure all tasks are completed. This prevents
-  // memory leaks.
-  content::RunAllTasksUntilIdle();
-}
-
-ProfileAttributesStorage* ProfileInfoCacheTest::GetCache() {
-  return testing_profile_manager_.profile_attributes_storage();
-}
-
-base::FilePath ProfileInfoCacheTest::GetProfilePath(
-    const std::string& base_name) {
-  return testing_profile_manager_.profile_manager()->user_data_dir().
-      AppendASCII(base_name);
-}
-
-void ProfileInfoCacheTest::ResetCache() {
-  testing_profile_manager_.DeleteProfileAttributesStorage();
-}
-
-std::u16string ProfileInfoCacheTest::GetConcatenation(
-    const std::u16string& gaia_name,
-    const std::u16string profile_name) {
-  std::u16string name_to_display(gaia_name);
-  name_to_display.append(u" (");
-  name_to_display.append(profile_name);
-  name_to_display.append(u")");
-  return name_to_display;
-}
-
-TEST_F(ProfileInfoCacheTest, AddProfiles) {
-  EXPECT_EQ(0u, GetCache()->GetNumberOfProfiles());
-  // Avatar icons not used on Android.
-#if !defined(OS_ANDROID)
-  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-#endif
-
-  for (uint32_t i = 0; i < 4; ++i) {
-    base::FilePath profile_path =
-        GetProfilePath(base::StringPrintf("path_%ud", i));
-    std::u16string profile_name =
-        ASCIIToUTF16(base::StringPrintf("name_%ud", i));
-#if !defined(OS_ANDROID)
-
-    size_t icon_id = GetDefaultAvatarIconResourceIDAtIndex(i);
-    const SkBitmap* icon = rb.GetImageNamed(icon_id).ToSkBitmap();
-
-#endif  // !defined(OS_ANDROID)
-    std::string supervised_user_id;
-#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
-    if (i == 3)
-      supervised_user_id = supervised_users::kChildAccountSUID;
-#endif
-
-    ProfileAttributesInitParams params;
-    params.profile_path = profile_path;
-    params.profile_name = profile_name;
-    params.icon_index = i;
-    params.supervised_user_id = supervised_user_id;
-    GetCache()->AddProfile(std::move(params));
-
-    ProfileAttributesEntry* entry =
-        GetCache()->GetProfileAttributesWithPath(profile_path);
-    entry->SetBackgroundStatus(true);
-    std::u16string gaia_name = ASCIIToUTF16(base::StringPrintf("gaia_%ud", i));
-    entry->SetGAIAName(gaia_name);
-
-    EXPECT_EQ(i + 1, GetCache()->GetNumberOfProfiles());
-    std::u16string expected_profile_name =
-        GetConcatenation(gaia_name, profile_name);
-
-    EXPECT_EQ(expected_profile_name, entry->GetName());
-
-    EXPECT_EQ(profile_path, entry->GetPath());
-#if !defined(OS_ANDROID)
-    const SkBitmap* actual_icon = entry->GetAvatarIcon().ToSkBitmap();
-    EXPECT_EQ(icon->width(), actual_icon->width());
-    EXPECT_EQ(icon->height(), actual_icon->height());
-#endif
-#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
-    EXPECT_EQ(i == 3, entry->IsSupervised());
-#else
-    EXPECT_FALSE(entry->IsSupervised());
-    EXPECT_FALSE(entry->IsOmitted());
-#endif  // BUILDFLAG(ENABLE_SUPERVISED_USERS)
-    EXPECT_EQ(supervised_user_id, entry->GetSupervisedUserId());
-  }
-
-  // Reset the cache and test the it reloads correctly.
-  ResetCache();
-
-  EXPECT_EQ(4u, GetCache()->GetNumberOfProfiles());
-  for (uint32_t i = 0; i < 4; ++i) {
-    base::FilePath profile_path =
-          GetProfilePath(base::StringPrintf("path_%ud", i));
-    ProfileAttributesEntry* entry =
-        GetCache()->GetProfileAttributesWithPath(profile_path);
-    std::u16string profile_name =
-        ASCIIToUTF16(base::StringPrintf("name_%ud", i));
-    std::u16string gaia_name = ASCIIToUTF16(base::StringPrintf("gaia_%ud", i));
-    std::u16string expected_profile_name =
-        GetConcatenation(gaia_name, profile_name);
-    EXPECT_EQ(expected_profile_name, entry->GetName());
-#if !defined(OS_ANDROID)
-    EXPECT_EQ(i, entry->GetAvatarIconIndex());
-#endif
-    EXPECT_EQ(true, entry->GetBackgroundStatus());
-    EXPECT_EQ(gaia_name, entry->GetGAIAName());
-  }
-}
-
-TEST_F(ProfileInfoCacheTest, GAIAName) {
-  base::FilePath profile_path_1 = GetProfilePath("path_1");
-  ProfileAttributesInitParams params_1;
-  params_1.profile_path = profile_path_1;
-  params_1.profile_name = u"Person 1";
-  GetCache()->AddProfile(std::move(params_1));
-  ProfileAttributesEntry* entry_1 =
-      GetCache()->GetProfileAttributesWithPath(profile_path_1);
-  base::FilePath profile_path_2 = GetProfilePath("path_2");
-  ProfileAttributesInitParams params_2;
-  params_2.profile_path = profile_path_2;
-  params_2.profile_name = u"Person 2";
-  GetCache()->AddProfile(std::move(params_2));
-  ProfileAttributesEntry* entry_2 =
-      GetCache()->GetProfileAttributesWithPath(profile_path_2);
-
-  // Sanity check.
-  EXPECT_TRUE(entry_1->GetGAIAName().empty());
-  EXPECT_TRUE(entry_2->GetGAIAName().empty());
-
-  // Set GAIA name.
-  std::u16string gaia_name(u"Pat Smith");
-  entry_2->SetGAIAName(gaia_name);
-  // Since there is a GAIA name, we use that as a display name.
-  EXPECT_TRUE(entry_1->GetGAIAName().empty());
-  EXPECT_EQ(gaia_name, entry_2->GetGAIAName());
-  EXPECT_EQ(gaia_name, entry_2->GetName());
-
-  std::u16string custom_name(u"Custom name");
-  entry_2->SetLocalProfileName(custom_name, false);
-
-  std::u16string expected_profile_name =
-      GetConcatenation(gaia_name, custom_name);
-  EXPECT_EQ(expected_profile_name, entry_2->GetName());
-  EXPECT_EQ(gaia_name, entry_2->GetGAIAName());
-}
-
-TEST_F(ProfileInfoCacheTest, ConcatenateGaiaNameAndProfileName) {
-  // We should only append the profile name to the GAIA name if:
-  // - The user has chosen a profile name on purpose.
-  // - Two profiles has the sama GAIA name and we need to show it to
-  //   clear ambiguity.
-  // If one of the two conditions hold, we will show the profile name in this
-  // format |GAIA name (Profile local name)|
-  // Single profile.
-  base::FilePath profile_path_1 = GetProfilePath("path_1");
-  ProfileAttributesInitParams params_1;
-  params_1.profile_path = profile_path_1;
-  params_1.profile_name = u"Person 1";
-  GetCache()->AddProfile(std::move(params_1));
-  ProfileAttributesEntry* entry_1 =
-      GetCache()->GetProfileAttributesWithPath(profile_path_1);
-  EXPECT_EQ(u"Person 1", entry_1->GetName());
-  entry_1->SetGAIAName(u"Patt Smith");
-  EXPECT_EQ(u"Patt Smith", entry_1->GetName());
-  entry_1->SetGAIAGivenName(u"Patt");
-  EXPECT_EQ(u"Patt", entry_1->GetName());
-
-  // Set a custom profile name.
-  entry_1->SetLocalProfileName(u"Work", false);
-  EXPECT_EQ(u"Patt (Work)", entry_1->GetName());
-
-  // Set the profile name to be equal to GAIA name.
-  entry_1->SetLocalProfileName(u"patt", false);
-  EXPECT_EQ(u"Patt", entry_1->GetName());
-
-  // Multiple profiles.
-  // Add another profile with the same GAIA name and a default profile name.
-  base::FilePath profile_path_2 = GetProfilePath("path_2");
-  ProfileAttributesInitParams params_2;
-  params_2.profile_path = profile_path_2;
-  params_2.profile_name = u"Person 2";
-  GetCache()->AddProfile(std::move(params_2));
-  ProfileAttributesEntry* entry_2 =
-      GetCache()->GetProfileAttributesWithPath(profile_path_2);
-  EXPECT_EQ(u"Patt", entry_1->GetName());
-  EXPECT_EQ(u"Person 2", entry_2->GetName());
-
-  entry_1->SetLocalProfileName(u"Work", false);
-  EXPECT_EQ(u"Patt (Work)", entry_1->GetName());
-  EXPECT_EQ(u"Person 2", entry_2->GetName());
-
-  // A second profile with a different GAIA name should not affect the first
-  // profile.
-  entry_2->SetGAIAGivenName(u"Olly");
-  EXPECT_EQ(u"Patt (Work)", entry_1->GetName());
-  EXPECT_EQ(u"Olly", entry_2->GetName());
-
-  // Mark profile name as default.
-  entry_1->SetLocalProfileName(u"Person 1", true);
-  EXPECT_EQ(u"Patt", entry_1->GetName());
-  EXPECT_EQ(u"Olly", entry_2->GetName());
-
-  // Add a third profile with the same GAIA name as the first.
-  // The two profiles are marked as using default profile names.
-  base::FilePath profile_path_3 = GetProfilePath("path_3");
-  ProfileAttributesInitParams params_3;
-  params_3.profile_path = profile_path_3;
-  params_3.profile_name = u"Person 3";
-  GetCache()->AddProfile(std::move(params_3));
-  ProfileAttributesEntry* entry_3 =
-      GetCache()->GetProfileAttributesWithPath(profile_path_3);
-  entry_3->SetGAIAName(u"Patt Smith");
-  EXPECT_EQ(u"Patt", entry_1->GetName());
-  EXPECT_EQ(u"Patt Smith", entry_3->GetName());
-
-  // Two profiles with same GAIA name and default profile name.
-  // Empty GAIA given name.
-  entry_3->SetGAIAName(u"Patt");
-  EXPECT_EQ(u"Patt (Person 1)", entry_1->GetName());
-  EXPECT_EQ(u"Patt (Person 3)", entry_3->GetName());
-  // Set GAIA given name.
-  entry_3->SetGAIAGivenName(u"Patt");
-  EXPECT_EQ(u"Patt (Person 1)", entry_1->GetName());
-  EXPECT_EQ(u"Patt (Person 3)", entry_3->GetName());
-
-  // Customize the profile name for one of the two profiles.
-  entry_3->SetLocalProfileName(u"Personal", false);
-  EXPECT_EQ(u"Patt", entry_1->GetName());
-  EXPECT_EQ(u"Patt (Personal)", entry_3->GetName());
-
-  // Set one of the profile names to be equal to GAIA name, we should show
-  // the profile name even if it is Person n to clear ambiguity.
-  entry_3->SetLocalProfileName(u"patt", false);
-  EXPECT_EQ(u"Patt (Person 1)", entry_1->GetName());
-  EXPECT_EQ(u"Patt", entry_3->GetName());
-
-  // Never show the profile name if it is equal GAIA name.
-  entry_1->SetLocalProfileName(u"Patt", false);
-  EXPECT_EQ(u"Patt", entry_1->GetName());
-  EXPECT_EQ(u"Patt", entry_3->GetName());
-  EXPECT_EQ(u"Olly", entry_2->GetName());
-}
-
-TEST_F(ProfileInfoCacheTest, DeleteProfile) {
-  EXPECT_EQ(0u, GetCache()->GetNumberOfProfiles());
-
-  base::FilePath path_1 = GetProfilePath("path_1");
-  ProfileAttributesInitParams params_1;
-  params_1.profile_path = path_1;
-  params_1.profile_name = u"name_1";
-  GetCache()->AddProfile(std::move(params_1));
-  EXPECT_EQ(1u, GetCache()->GetNumberOfProfiles());
-
-  base::FilePath path_2 = GetProfilePath("path_2");
-  std::u16string name_2 = u"name_2";
-  ProfileAttributesInitParams params_2;
-  params_2.profile_path = path_2;
-  params_2.profile_name = name_2;
-  GetCache()->AddProfile(std::move(params_2));
-  ProfileAttributesEntry* entry =
-      GetCache()->GetProfileAttributesWithPath(path_2);
-  EXPECT_EQ(2u, GetCache()->GetNumberOfProfiles());
-
-  GetCache()->RemoveProfile(path_1);
-  EXPECT_EQ(1u, GetCache()->GetNumberOfProfiles());
-  EXPECT_EQ(name_2, entry->GetName());
-
-  GetCache()->RemoveProfile(path_2);
-  EXPECT_EQ(0u, GetCache()->GetNumberOfProfiles());
-}
-
-TEST_F(ProfileInfoCacheTest, MutateProfile) {
-  base::FilePath profile_path_1 = GetProfilePath("path_1");
-  ProfileAttributesInitParams params_1;
-  params_1.profile_path = profile_path_1;
-  params_1.profile_name = u"name_1";
-  GetCache()->AddProfile(std::move(params_1));
-
-  base::FilePath profile_path_2 = GetProfilePath("path_2");
-  ProfileAttributesInitParams params_2;
-  params_2.profile_path = profile_path_2;
-  params_2.profile_name = u"name_2";
-  GetCache()->AddProfile(std::move(params_2));
-  ProfileAttributesEntry* entry_1 =
-      GetCache()->GetProfileAttributesWithPath(profile_path_1);
-  ProfileAttributesEntry* entry_2 =
-      GetCache()->GetProfileAttributesWithPath(profile_path_2);
-
-  std::u16string new_name = u"new_name";
-  entry_2->SetLocalProfileName(new_name, false);
-  EXPECT_EQ(new_name, entry_2->GetName());
-  EXPECT_NE(new_name, entry_1->GetName());
-
-  std::u16string new_user_name = u"user_name";
-  std::string new_gaia_id = "12345";
-  entry_2->SetAuthInfo(new_gaia_id, new_user_name, true);
-  EXPECT_EQ(new_user_name, entry_2->GetUserName());
-  EXPECT_EQ(new_gaia_id, entry_2->GetGAIAId());
-  EXPECT_NE(new_user_name, entry_1->GetUserName());
-
-  // Avatar icons not used on Android.
-#if !defined(OS_ANDROID)
-  const size_t new_icon_index = 3;
-  entry_2->SetAvatarIconIndex(new_icon_index);
-  EXPECT_EQ(new_icon_index, entry_2->GetAvatarIconIndex());
-#endif
-}
-
-// Will be removed SOON with ProfileInfoCache tests.
-TEST_F(ProfileInfoCacheTest, BackgroundModeStatus) {
-  base::FilePath path_1 = GetProfilePath("path_1");
-  ProfileAttributesInitParams params_1;
-  params_1.profile_path = path_1;
-  params_1.profile_name = u"name_1";
-  GetCache()->AddProfile(std::move(params_1));
-
-  base::FilePath path_2 = GetProfilePath("path_2");
-  ProfileAttributesInitParams params_2;
-  params_2.profile_path = path_2;
-  params_2.profile_name = u"name_2";
-  GetCache()->AddProfile(std::move(params_2));
-
-  ProfileAttributesEntry* entry_1 =
-      GetCache()->GetProfileAttributesWithPath(path_1);
-  ProfileAttributesEntry* entry_2 =
-      GetCache()->GetProfileAttributesWithPath(path_2);
-  EXPECT_FALSE(entry_1->GetBackgroundStatus());
-  EXPECT_FALSE(entry_2->GetBackgroundStatus());
-
-  entry_2->SetBackgroundStatus(true);
-
-  EXPECT_FALSE(entry_1->GetBackgroundStatus());
-  EXPECT_TRUE(entry_2->GetBackgroundStatus());
-
-  entry_1->SetBackgroundStatus(true);
-
-  EXPECT_TRUE(entry_1->GetBackgroundStatus());
-  EXPECT_TRUE(entry_2->GetBackgroundStatus());
-
-  entry_2->SetBackgroundStatus(false);
-
-  EXPECT_TRUE(entry_1->GetBackgroundStatus());
-  EXPECT_FALSE(entry_2->GetBackgroundStatus());
-}
-
-#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
-TEST_F(ProfileInfoCacheTest, SetSupervisedUserId) {
-  base::FilePath profile_path = GetProfilePath("test");
-  ProfileAttributesInitParams params;
-  params.profile_path = profile_path;
-  params.profile_name = u"Test";
-  GetCache()->AddProfile(std::move(params));
-  ProfileAttributesEntry* entry =
-      GetCache()->GetProfileAttributesWithPath(profile_path);
-  EXPECT_FALSE(entry->IsSupervised());
-
-  entry->SetSupervisedUserId(supervised_users::kChildAccountSUID);
-  EXPECT_TRUE(entry->IsSupervised());
-  EXPECT_EQ(supervised_users::kChildAccountSUID, entry->GetSupervisedUserId());
-
-  ResetCache();
-  entry = GetCache()->GetProfileAttributesWithPath(profile_path);
-  EXPECT_TRUE(entry->IsSupervised());
-
-  entry->SetSupervisedUserId(std::string());
-  EXPECT_FALSE(entry->IsSupervised());
-  EXPECT_EQ("", entry->GetSupervisedUserId());
-}
-#endif  // BUILDFLAG(ENABLE_SUPERVISED_USERS)
-
-#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
-TEST_F(ProfileInfoCacheTest, CreateSupervisedTestingProfile) {
-  base::FilePath path_1 =
-      testing_profile_manager_.CreateTestingProfile("default")->GetPath();
-  std::u16string supervised_user_name = u"Supervised User";
-  base::FilePath path_2 =
-      testing_profile_manager_
-          .CreateTestingProfile(
-              "test1", std::unique_ptr<sync_preferences::PrefServiceSyncable>(),
-              supervised_user_name, 0, supervised_users::kChildAccountSUID,
-              TestingProfile::TestingFactories())
-          ->GetPath();
-  base::FilePath profile_path[] = {path_1, path_2};
-  for (const base::FilePath& path : profile_path) {
-    ProfileAttributesEntry* entry =
-        GetCache()->GetProfileAttributesWithPath(path);
-    bool is_supervised = entry->GetName() == supervised_user_name;
-    EXPECT_EQ(is_supervised, entry->IsSupervised());
-    std::string supervised_user_id =
-        is_supervised ? supervised_users::kChildAccountSUID : "";
-    EXPECT_EQ(supervised_user_id, entry->GetSupervisedUserId());
-  }
-
-  // Supervised profiles have a custom theme, which needs to be deleted on the
-  // FILE thread. Reset the profile manager now so everything is deleted while
-  // we still have a FILE thread.
-  TestingBrowserProcess::GetGlobal()->SetProfileManager(nullptr);
-}
-#endif
-
-TEST_F(ProfileInfoCacheTest, AddStubProfile) {
-  EXPECT_EQ(0u, GetCache()->GetNumberOfProfiles());
-
-  // Add some profiles with and without a '.' in their paths.
-  const struct {
-    const char* profile_path;
-    const char* profile_name;
-  } kTestCases[] = {
-    { "path.test0", "name_0" },
-    { "path_test1", "name_1" },
-    { "path.test2", "name_2" },
-    { "path_test3", "name_3" },
-  };
-
-  for (size_t i = 0; i < base::size(kTestCases); ++i) {
-    base::FilePath profile_path = GetProfilePath(kTestCases[i].profile_path);
-    std::u16string profile_name = ASCIIToUTF16(kTestCases[i].profile_name);
-
-    ProfileAttributesInitParams params;
-    params.profile_path = profile_path;
-    params.profile_name = profile_name;
-    GetCache()->AddProfile(std::move(params));
-    ProfileAttributesEntry* entry =
-        GetCache()->GetProfileAttributesWithPath(profile_path);
-    EXPECT_TRUE(entry);
-    EXPECT_EQ(profile_name, entry->GetName());
-  }
-
-  ASSERT_EQ(4U, GetCache()->GetNumberOfProfiles());
-
-  // Check that the profiles can be extracted from the local state.
-  std::vector<std::u16string> names;
-  PrefService* local_state = g_browser_process->local_state();
-  const base::DictionaryValue* cache =
-      local_state->GetDictionary(prefs::kProfileAttributes);
-  std::u16string name;
-  for (base::DictionaryValue::Iterator it(*cache); !it.IsAtEnd();
-       it.Advance()) {
-    const base::DictionaryValue* info = NULL;
-    it.value().GetAsDictionary(&info);
-    info->GetString("name", &name);
-    names.push_back(name);
-  }
-
-  for (size_t i = 0; i < 4; i++)
-    ASSERT_FALSE(names[i].empty());
-}
-
-TEST_F(ProfileInfoCacheTest, EntriesInAttributesStorage) {
-  EXPECT_EQ(0u, GetCache()->GetNumberOfProfiles());
-
-  // Add some profiles with and without a '.' in their paths.
-  const struct {
-    const char* profile_path;
-    const char* profile_name;
-  } kTestCases[] = {
-    { "path.test0", "name_0" },
-    { "path_test1", "name_1" },
-    { "path.test2", "name_2" },
-    { "path_test3", "name_3" },
-  };
-
-  // Profiles are added and removed using all combinations of the old and the
-  // new interfaces. The content of |profile_attributes_entries_| in
-  // ProfileAttributesStorage is checked after each insert and delete operation.
-
-  // Add profiles.
-  for (size_t i = 0; i < base::size(kTestCases); ++i) {
-    base::FilePath profile_path = GetProfilePath(kTestCases[i].profile_path);
-    std::u16string profile_name = ASCIIToUTF16(kTestCases[i].profile_name);
-
-    ASSERT_EQ(0u, GetCache()->profile_attributes_entries_.count(
-                      profile_path.value()));
-
-    // Use ProfileInfoCache in profiles 0 and 2, and ProfileAttributesStorage in
-    // profiles 1 and 3.
-    ProfileAttributesInitParams params;
-    params.profile_path = profile_path;
-    params.profile_name = profile_name;
-    params.icon_index = i;
-    if (i == 0 || i == 2) {
-      GetCache()->AddProfile(std::move(params));
-    } else {
-      GetCache()->AddProfile(std::move(params));
-    }
-
-    ASSERT_EQ(i + 1, GetCache()->GetNumberOfProfiles());
-    ASSERT_EQ(i + 1, GetCache()->profile_attributes_entries_.size());
-
-    ASSERT_EQ(1u, GetCache()->profile_attributes_entries_.count(
-                      profile_path.value()));
-
-    ProfileAttributesEntry* entry =
-        GetCache()->GetProfileAttributesWithPath(profile_path);
-    EXPECT_EQ(entry,
-              &GetCache()->profile_attributes_entries_[profile_path.value()]);
-  }
-
-  // Remove profiles.
-  for (size_t i = 0; i < base::size(kTestCases); ++i) {
-    base::FilePath profile_path = GetProfilePath(kTestCases[i].profile_path);
-    ASSERT_EQ(1u, GetCache()->profile_attributes_entries_.count(
-                      profile_path.value()));
-
-    // Use ProfileInfoCache in profiles 0 and 1, and ProfileAttributesStorage in
-    // profiles 2 and 3.
-    if (i == 0 || i == 1)
-      GetCache()->RemoveProfile(profile_path);
-    else
-      GetCache()->RemoveProfile(profile_path);
-
-    ASSERT_EQ(0u, GetCache()->profile_attributes_entries_.count(
-                      profile_path.value()));
-
-    ProfileAttributesEntry* entry =
-        GetCache()->GetProfileAttributesWithPath(profile_path);
-    EXPECT_EQ(entry, nullptr);
-    ASSERT_EQ(0u, GetCache()->profile_attributes_entries_.count(
-                      profile_path.value()));
-  }
-}
-
-#if !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
-TEST_F(ProfileInfoCacheTest, MigrateLegacyProfileNamesAndRecomputeIfNeeded) {
-  EXPECT_EQ(0U, GetCache()->GetNumberOfProfiles());
-  // Mimick a pre-existing Directory with profiles that has legacy profile
-  // names.
-  const struct {
-    const char* profile_path;
-    const char* profile_name;
-    bool is_using_default_name;
-  } kTestCases[] = {
-      {"path_1", "Default Profile", true}, {"path_2", "First user", true},
-      {"path_3", "Lemonade", true},        {"path_4", "Batman", true},
-      {"path_5", "Batman", false},         {"path_6", "Person 2", true},
-      {"path_7", "Person 3", true},        {"path_8", "Person 1", true},
-      {"path_9", "Person 2", true},        {"path_10", "Person 1", true},
-      {"path_11", "Smith", false},         {"path_12", "Person 2", true}};
-
-  ProfileAttributesEntry* entry = nullptr;
-  for (size_t i = 0; i < base::size(kTestCases); ++i) {
-    base::FilePath profile_path = GetProfilePath(kTestCases[i].profile_path);
-    ProfileAttributesInitParams params;
-    params.profile_path = profile_path;
-    params.profile_name = ASCIIToUTF16(kTestCases[i].profile_name);
-    params.icon_index = i;
-    GetCache()->AddProfile(std::move(params));
-    entry = GetCache()->GetProfileAttributesWithPath(profile_path);
-    EXPECT_TRUE(entry);
-    entry->SetIsUsingDefaultName(kTestCases[i].is_using_default_name);
-  }
-
-  EXPECT_EQ(12U, GetCache()->GetNumberOfProfiles());
-
-  ResetCache();
-  ProfileAttributesStorage::SetLegacyProfileMigrationForTesting(true);
-  GetCache();
-  ProfileAttributesStorage::SetLegacyProfileMigrationForTesting(false);
-
-  entry = GetCache()->GetProfileAttributesWithPath(
-      GetProfilePath(kTestCases[4].profile_path));
-  EXPECT_EQ(ASCIIToUTF16(kTestCases[4].profile_name), entry->GetName());
-  entry = GetCache()->GetProfileAttributesWithPath(
-      GetProfilePath(kTestCases[10].profile_path));
-  EXPECT_EQ(ASCIIToUTF16(kTestCases[10].profile_name), entry->GetName());
-
-  // Legacy profile names like "Default Profile" and "First user" should be
-  // migrated to "Person %n" type names, i.e. any permutation of "Person %n".
-  std::set<std::u16string> expected_profile_names{
-      u"Person 1", u"Person 2", u"Person 3", u"Person 4", u"Person 5",
-      u"Person 6", u"Person 7", u"Person 8", u"Person 9", u"Person 10"};
-
-  const char* profile_path[] = {
-      kTestCases[0].profile_path, kTestCases[1].profile_path,
-      kTestCases[2].profile_path, kTestCases[3].profile_path,
-      kTestCases[5].profile_path, kTestCases[6].profile_path,
-      kTestCases[7].profile_path, kTestCases[8].profile_path,
-      kTestCases[9].profile_path, kTestCases[11].profile_path};
-
-  std::set<std::u16string> actual_profile_names;
-  for (auto* path : profile_path) {
-    entry = GetCache()->GetProfileAttributesWithPath(GetProfilePath(path));
-    actual_profile_names.insert(entry->GetName());
-  }
-  EXPECT_EQ(actual_profile_names, expected_profile_names);
-}
-#endif
-
-#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_ANDROID)
-TEST_F(ProfileInfoCacheTest,
-       DontMigrateLegacyProfileNamesWithoutNewAvatarMenu) {
-  EXPECT_EQ(0U, GetCache()->GetNumberOfProfiles());
-
-  const struct {
-    const char* profile_path;
-    const char* profile_name;
-  } kTestCases[] = {{"path_1", "Default Profile"},
-                    {"path_2", "First user"},
-                    {"path_3", "Lemonade"},
-                    {"path_4", "Batman"}};
-
-  for (size_t i = 0; i < base::size(kTestCases); ++i) {
-    base::FilePath profile_path = GetProfilePath(kTestCases[i].profile_path);
-    ProfileAttributesInitParams params;
-    params.profile_path = profile_path;
-    params.profile_name = ASCIIToUTF16(kTestCases[i].profile_name);
-    params.icon_index = i;
-    GetCache()->AddProfile(std::move(params));
-    ProfileAttributesEntry* entry =
-        GetCache()->GetProfileAttributesWithPath(profile_path);
-    EXPECT_TRUE(entry);
-    entry->SetIsUsingDefaultName(true);
-  }
-  EXPECT_EQ(4U, GetCache()->GetNumberOfProfiles());
-
-  ResetCache();
-
-  // Profile names should have been preserved.
-  for (size_t i = 0; i < base::size(kTestCases); ++i) {
-    base::FilePath profile_path = GetProfilePath(kTestCases[i].profile_path);
-    std::u16string profile_name = ASCIIToUTF16(kTestCases[i].profile_name);
-    ProfileAttributesEntry* entry =
-        GetCache()->GetProfileAttributesWithPath(profile_path);
-    EXPECT_TRUE(entry);
-    EXPECT_EQ(profile_name, entry->GetName());
-  }
-}
-#endif
-
-TEST_F(ProfileInfoCacheTest, RemoveProfileByAccountId) {
-  EXPECT_EQ(0u, GetCache()->GetNumberOfProfiles());
-  const struct {
-    const char* profile_path;
-    const char* profile_name;
-    AccountId account_id;
-    bool is_consented_primary_account;
-  } kTestCases[] = {
-      {"path_1", "name_1", AccountId::FromUserEmailGaiaId("email1", "111111"),
-       true},
-      {"path_2", "name_3", AccountId::FromUserEmailGaiaId("email2", "222222"),
-       true},
-      {"path_3", "name_3", AccountId::FromUserEmailGaiaId("email3", "333333"),
-       false},
-      {"path_4", "name_4", AccountId::FromUserEmailGaiaId("email4", "444444"),
-       false}};
-
-  for (size_t i = 0; i < base::size(kTestCases); ++i) {
-    ProfileAttributesInitParams params;
-    params.profile_path = GetProfilePath(kTestCases[i].profile_path);
-    params.profile_name = ASCIIToUTF16(kTestCases[i].profile_name);
-    params.gaia_id = kTestCases[i].account_id.GetGaiaId();
-    params.user_name = UTF8ToUTF16(kTestCases[i].account_id.GetUserEmail());
-    params.is_consented_primary_account =
-        kTestCases[i].is_consented_primary_account;
-    GetCache()->AddProfile(std::move(params));
-    EXPECT_EQ(i + 1, GetCache()->GetNumberOfProfiles());
-  }
-
-  GetCache()->RemoveProfileByAccountId(kTestCases[2].account_id);
-  EXPECT_EQ(3u, GetCache()->GetNumberOfProfiles());
-
-  GetCache()->RemoveProfileByAccountId(kTestCases[0].account_id);
-  EXPECT_EQ(2u, GetCache()->GetNumberOfProfiles());
-
-  // this profile is already deleted.
-  GetCache()->RemoveProfileByAccountId(kTestCases[2].account_id);
-  EXPECT_EQ(2u, GetCache()->GetNumberOfProfiles());
-
-  // Remove profile by partial match
-  GetCache()->RemoveProfileByAccountId(
-      AccountId::FromUserEmail(kTestCases[1].account_id.GetUserEmail()));
-  EXPECT_EQ(1u, GetCache()->GetNumberOfProfiles());
-
-  // Remove last profile
-  GetCache()->RemoveProfileByAccountId(kTestCases[3].account_id);
-  EXPECT_EQ(0u, GetCache()->GetNumberOfProfiles());
-}
-
-// Checks that ProfileInfoCache doesn't crash when ProfileAttributesEntry
-// initialization modifies the cache entry.
-// This is a regression test for https://crbug.com/1180497.
-TEST_F(ProfileInfoCacheTest, ModifiyEntryWhileInitializing) {
-  base::FilePath profile_path = GetProfilePath("test");
-  {
-    signin_util::ScopedForceSigninSetterForTesting force_signin_setter(true);
-    AccountId account_id = AccountId::FromUserEmailGaiaId("email", "111111");
-    ProfileAttributesInitParams params;
-    params.profile_path = profile_path;
-    params.profile_name = u"Test";
-    params.gaia_id = account_id.GetGaiaId();
-    params.user_name = UTF8ToUTF16(account_id.GetUserEmail());
-    GetCache()->AddProfile(std::move(params));
-    ProfileAttributesEntry* entry =
-        GetCache()->GetProfileAttributesWithPath(profile_path);
-    // Set up the state so that ProfileAttributesEntry::Initialize() will modify
-    // the cache entry.
-    entry->LockForceSigninProfile(true);
-  }
-  // Reinitialize ProfileInfoCache.
-  ResetCache();
-  GetCache();  // Should not crash.
-
-  // The IsSigninRequired attribute should be cleaned up.
-  ProfileAttributesEntry* entry =
-      GetCache()->GetProfileAttributesWithPath(profile_path);
-  EXPECT_FALSE(entry->IsSigninRequired());
-}
-
-TEST_F(ProfileInfoCacheTest, ProfileNamesOnInit) {
-  // Set up the cache with two profiles having the same GAIA given name.
-  // The second profile also has a profile name matching the GAIA given name.
-  std::u16string kDefaultProfileName = u"Person 1";
-  std::u16string kCommonName = u"Joe";
-
-  // Create and initialize the first profile.
-  base::FilePath path_1 = GetProfilePath("path_1");
-  ProfileAttributesInitParams params_1;
-  params_1.profile_path = path_1;
-  params_1.profile_name = kDefaultProfileName;
-  GetCache()->AddProfile(std::move(params_1));
-  ProfileAttributesEntry* entry_1 =
-      GetCache()->GetProfileAttributesWithPath(path_1);
-  entry_1->SetGAIAGivenName(kCommonName);
-  EXPECT_EQ(entry_1->GetName(), kCommonName);
-
-  // Create and initialize the second profile.
-  base::FilePath path_2 = GetProfilePath("path_2");
-  ProfileAttributesInitParams params_2;
-  params_2.profile_path = path_2;
-  params_2.profile_name = kCommonName;
-  GetCache()->AddProfile(std::move(params_2));
-  ProfileAttributesEntry* entry_2 =
-      GetCache()->GetProfileAttributesWithPath(path_2);
-  entry_2->SetGAIAGivenName(kCommonName);
-  EXPECT_EQ(entry_2->GetName(), kCommonName);
-
-  // The first profile name should be modified.
-  EXPECT_EQ(entry_1->GetName(),
-            GetConcatenation(kCommonName, kDefaultProfileName));
-
-  // Reset cache to test profile names set on initialization.
-  ResetCache();
-  entry_1 = GetCache()->GetProfileAttributesWithPath(path_1);
-  entry_2 = GetCache()->GetProfileAttributesWithPath(path_2);
-
-  // Freshly initialized entries should not report name changes.
-  EXPECT_FALSE(entry_1->HasProfileNameChanged());
-  EXPECT_FALSE(entry_2->HasProfileNameChanged());
-
-  EXPECT_EQ(entry_1->GetName(),
-            GetConcatenation(kCommonName, kDefaultProfileName));
-  EXPECT_EQ(entry_2->GetName(), kCommonName);
-}
diff --git a/chrome/browser/profiles/profile_info_cache_unittest.h b/chrome/browser/profiles/profile_info_cache_unittest.h
deleted file mode 100644
index 275c4832..0000000
--- a/chrome/browser/profiles/profile_info_cache_unittest.h
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_PROFILES_PROFILE_INFO_CACHE_UNITTEST_H_
-#define CHROME_BROWSER_PROFILES_PROFILE_INFO_CACHE_UNITTEST_H_
-
-#include <set>
-
-#include "chrome/browser/profiles/profile_attributes_storage.h"
-#include "chrome/test/base/testing_profile_manager.h"
-#include "content/public/test/browser_task_environment.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-class FilePath;
-}
-
-// Class used to test that ProfileInfoCache does not try to access any
-// unexpected profile names.
-class ProfileNameVerifierObserver : public ProfileAttributesStorage::Observer {
- public:
-  explicit ProfileNameVerifierObserver(
-      TestingProfileManager* testing_profile_manager);
-  ProfileNameVerifierObserver(const ProfileNameVerifierObserver&) = delete;
-  ProfileNameVerifierObserver& operator=(const ProfileNameVerifierObserver&) =
-      delete;
-  ~ProfileNameVerifierObserver() override;
-
-  // ProfileAttributesStorage::Observer overrides:
-  void OnProfileAdded(const base::FilePath& profile_path) override;
-  void OnProfileWillBeRemoved(const base::FilePath& profile_path) override;
-  void OnProfileWasRemoved(const base::FilePath& profile_path,
-                           const std::u16string& profile_name) override;
-  void OnProfileNameChanged(const base::FilePath& profile_path,
-                            const std::u16string& old_profile_name) override;
-  void OnProfileAvatarChanged(const base::FilePath& profile_path) override;
-
- private:
-  ProfileAttributesStorage* GetCache();
-  std::map<base::FilePath, std::u16string> profile_names_;
-  TestingProfileManager* testing_profile_manager_;
-};
-
-class ProfileInfoCacheTest : public testing::Test {
- protected:
-  ProfileInfoCacheTest();
-  ~ProfileInfoCacheTest() override;
-
-  void SetUp() override;
-  void TearDown() override;
-
-  ProfileAttributesStorage* GetCache();
-  base::FilePath GetProfilePath(const std::string& base_name);
-  void ResetCache();
-  void RemoveObserver();
-  std::u16string GetConcatenation(const std::u16string& gaia_name,
-                                  const std::u16string profile_name);
-
- private:
-  // BrowserTaskEnvironment needs to be up through the destruction of the
-  // TestingProfileManager below.
-  content::BrowserTaskEnvironment task_environment_;
-
- protected:
-  TestingProfileManager testing_profile_manager_;
-
- private:
-  ProfileNameVerifierObserver name_observer_;
-};
-
-#endif  // CHROME_BROWSER_PROFILES_PROFILE_INFO_CACHE_UNITTEST_H_
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
index 6231d7f..aef8964 100644
--- a/chrome/browser/profiles/profile_manager.cc
+++ b/chrome/browser/profiles/profile_manager.cc
@@ -1924,7 +1924,7 @@
             .get();
     if (password_store.get()) {
       password_store->RemoveLoginsCreatedBetween(
-          base::Time(), base::Time::Max(), base::OnceClosure());
+          base::Time(), base::Time::Max(), base::DoNothing());
     }
 
     // The Profile Data doesn't get wiped until Chrome closes. Since we promised
diff --git a/chrome/browser/resources/accessibility/accessibility.js b/chrome/browser/resources/accessibility/accessibility.js
index f60c8d5..8bc655d 100644
--- a/chrome/browser/resources/accessibility/accessibility.js
+++ b/chrome/browser/resources/accessibility/accessibility.js
@@ -73,6 +73,11 @@
   get kAXModeComplete() {
     return AXMode.kNativeAPIs | AXMode.kWebContents | AXMode.kInlineTextBoxes |
         AXMode.kScreenReader | AXMode.kHTML;
+  },
+
+  get kAXModeCompleteNoHTML() {
+    return AXMode.kNativeAPIs | AXMode.kWebContents | AXMode.kInlineTextBoxes |
+        AXMode.kScreenReader;
   }
 };
 
diff --git a/chrome/browser/resources/chromeos/login/arc_terms_of_service.html b/chrome/browser/resources/chromeos/login/arc_terms_of_service.html
index 0c8721b..01eff082 100644
--- a/chrome/browser/resources/chromeos/login/arc_terms_of_service.html
+++ b/chrome/browser/resources/chromeos/login/arc_terms_of_service.html
@@ -106,17 +106,19 @@
     <!-- As this dialog have pre-loading logic that require access to elements,
          dialog is marked as no-lazy. -->
     <oobe-adaptive-dialog id="arcTosDialog" for-step="loaded"
-        role="dialog"
-        aria-label$="[[i18nDynamic(locale, 'arcTermsOfServiceScreenHeading')]]"
+        role="dialog" aria-label$="[[getDialogTitle_(locale, isChild)]]"
         no-lazy>
       <iron-icon src="chrome://oobe/playstore.svg" slot="icon">
       </iron-icon>
       <h1 slot="title">
-        [[i18nDynamic(locale, 'arcTermsOfServiceScreenHeading')]]
+        [[getDialogTitle_(locale, isChild)]]
       </h1>
-      <p slot="subtitle">
+      <p slot="subtitle" hidden="[[isChild]]">
         [[i18nDynamic(locale, 'arcTermsOfServiceScreenDescription')]]
       </p>
+      <p slot="subtitle" hidden="[[!isChild]]">
+        [[i18nDynamic(locale, 'arcTermsOfServiceScreenDescriptionForChild')]]
+      </p>
       <div id="arcTosContainer" slot="content" class="flex layout vertical">
         <webview id="arcTosView" allowTransparency
             role="document" class="flex oobe-tos-webview"
diff --git a/chrome/browser/resources/chromeos/login/arc_terms_of_service.js b/chrome/browser/resources/chromeos/login/arc_terms_of_service.js
index d3bc27d..73a3e63 100644
--- a/chrome/browser/resources/chromeos/login/arc_terms_of_service.js
+++ b/chrome/browser/resources/chromeos/login/arc_terms_of_service.js
@@ -776,5 +776,13 @@
       this.lastFocusedElement_ = null;
     }
   },
+
+  /**
+   * Returns dialog title based on whether the active user is child.
+   */
+  getDialogTitle_(locale, isChild) {
+    return isChild ? this.i18n('arcTermsOfServiceScreenHeadingForChild') :
+                     this.i18n('arcTermsOfServiceScreenHeading');
+  }
 });
 })();
diff --git a/chrome/browser/resources/settings/chromeos/BUILD.gn b/chrome/browser/resources/settings/chromeos/BUILD.gn
index 56fbac3f..b9ea188e 100644
--- a/chrome/browser/resources/settings/chromeos/BUILD.gn
+++ b/chrome/browser/resources/settings/chromeos/BUILD.gn
@@ -380,6 +380,7 @@
     "chromeos/os_apps_page/android_apps_browser_proxy.m.js",
     "chromeos/os_apps_page/android_apps_subpage.m.js",
     "chromeos/os_apps_page/app_notifications_page/app_notifications_subpage.js",
+    "chromeos/os_apps_page/app_notifications_page/app_notification_row.js",
     "chromeos/os_apps_page/app_management_page/actions.m.js",
     "chromeos/os_apps_page/app_management_page/api_listener.m.js",
     "chromeos/os_apps_page/app_management_page/app_detail_view.m.js",
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/app_notifications_page/BUILD.gn b/chrome/browser/resources/settings/chromeos/os_apps_page/app_notifications_page/BUILD.gn
index cb7fe2c..dd348b9 100644
--- a/chrome/browser/resources/settings/chromeos/os_apps_page/app_notifications_page/BUILD.gn
+++ b/chrome/browser/resources/settings/chromeos/os_apps_page/app_notifications_page/BUILD.gn
@@ -8,7 +8,10 @@
 import("//tools/polymer/html_to_js.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
 
-polymer_element_files = [ "app_notifications_subpage.js" ]
+polymer_element_files = [
+  "app_notifications_subpage.js",
+  "app_notification_row.js",
+]
 
 js_type_check("closure_compile") {
   is_polymer3 = true
@@ -18,6 +21,13 @@
 
 js_library("app_notifications_subpage") {
   deps = [
+    ":app_notification_row",
+    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+  ]
+}
+
+js_library("app_notification_row") {
+  deps = [
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
   ]
 }
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/app_notifications_page/app_notification_row.html b/chrome/browser/resources/settings/chromeos/os_apps_page/app_notifications_page/app_notification_row.html
new file mode 100644
index 0000000..c5f2ecf
--- /dev/null
+++ b/chrome/browser/resources/settings/chromeos/os_apps_page/app_notifications_page/app_notification_row.html
@@ -0,0 +1,32 @@
+<style include="cr-icons">
+  :host {
+    align-items: center;
+    border-bottom: var(--card-separator);
+    color: var(--cros-text-color-primary);
+    display: flex;
+    flex-direction: row;
+    font-weight: 400;
+    height: 48px;
+  }
+
+  #appTitle {
+    flex: 1;
+    overflow: hidden;
+    text-overflow: ellipsis;
+  }
+
+  #appToggle {
+    padding: 0 20px 0 0;
+  }
+
+  #appIcon {
+    height: 32px;
+    margin-inline-end: 20px;
+    margin-inline-start: 24px;
+    width: 32px;
+  }
+</style>
+<img id="appIcon" src="chrome://app-icon/[[app.id]]/64"
+    alt="[[app.title]] app icon." aria-hidden="true">
+<div id="appTitle" aria-hidden="true">[[app.title]]</div>
+<cr-toggle id="appToggle"></cr-toggle>
\ No newline at end of file
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/app_notifications_page/app_notification_row.js b/chrome/browser/resources/settings/chromeos/os_apps_page/app_notifications_page/app_notification_row.js
new file mode 100644
index 0000000..e766983
--- /dev/null
+++ b/chrome/browser/resources/settings/chromeos/os_apps_page/app_notifications_page/app_notification_row.js
@@ -0,0 +1,31 @@
+// Copyright 2021 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 {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+/**
+ * @fileoverview
+ * 'app-notification-row' is a custom row element for the OS Settings
+ * Notifications Subpage. Each row contains an app icon, app name, and toggle.
+ */
+export class AppNotificationRowElement extends PolymerElement {
+  static get is() {
+    return 'app-notification-row';
+  }
+
+  static get template() {
+    return html`{__html_template__}`;
+  }
+
+  static get properties() {
+    return {
+      /** @type {!Object} */
+      app: {
+        type: Object,
+      },
+    };
+  }
+}
+
+customElements.define(AppNotificationRowElement.is, AppNotificationRowElement);
\ No newline at end of file
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/app_notifications_page/app_notifications_subpage.html b/chrome/browser/resources/settings/chromeos/os_apps_page/app_notifications_page/app_notifications_subpage.html
index a95c755..508abfd 100644
--- a/chrome/browser/resources/settings/chromeos/os_apps_page/app_notifications_page/app_notifications_subpage.html
+++ b/chrome/browser/resources/settings/chromeos/os_apps_page/app_notifications_page/app_notifications_subpage.html
@@ -1 +1,5 @@
-<div id="testDiv">Notifications</div>
\ No newline at end of file
+<div id="appNotificationsList">
+  <template is="dom-repeat" items="[[appList_]]" as="app">
+    <app-notification-row app="[[app]]"></app-notification-row>
+  </template>
+</div>
\ No newline at end of file
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/app_notifications_page/app_notifications_subpage.js b/chrome/browser/resources/settings/chromeos/os_apps_page/app_notifications_page/app_notifications_subpage.js
index 4089209..3d2e6f33 100644
--- a/chrome/browser/resources/settings/chromeos/os_apps_page/app_notifications_page/app_notifications_subpage.js
+++ b/chrome/browser/resources/settings/chromeos/os_apps_page/app_notifications_page/app_notifications_subpage.js
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import './app_notification_row.js';
 import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 /**
@@ -18,6 +19,24 @@
   static get template() {
     return html`{__html_template__}`;
   }
+
+  static get properties() {
+    return {
+      /**
+       * @type {!Array<!Object>}
+       * @private
+       */
+      appList_: {
+        type: Array,
+        // TODO(ethanimooney): Replace placeholders with proper implementation
+        // for apps
+        value: [
+          {title: 'Chrome', id: 'mgndgikekgjfcpckkfioiadnlibdjbkf'},
+          {title: 'Files', id: 'hhaomjibdihmijegdhdafkllkbggdgoj'}
+        ],
+      },
+    };
+  }
 }
 
 customElements.define(AppNotificationsSubpage.is, AppNotificationsSubpage);
\ No newline at end of file
diff --git a/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html
index 9e7f2ed..5a5af6b 100644
--- a/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html
+++ b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html
@@ -127,6 +127,13 @@
         padding-inline-end: var(--cr-icon-button-margin-start);
         width: var(--cr-link-row-icon-width, var(--cr-icon-size));
       }
+
+      @media (prefers-color-scheme: dark) {
+        .search-history-box-icon {
+          --iron-icon-fill-color: var(--cr-link-row-start-icon-color,
+              var(--google-grey-refresh-500));
+        }
+      }
     </style>
 
     <cr-dialog id="clearBrowsingDataDialog"
@@ -192,7 +199,7 @@
             <div class="search-history-box"
                 hidden="[[!shouldShowGoogleSearchHistoryLabel_(isSignedIn_)]]">
               <iron-icon class="search-history-box-icon" aria-hidden="true"
-                  icon="settings20:safety-check">
+                  icon="settings20:googleg">
               </iron-icon>
               <div id="googleSearchHistoryLabel"
                   inner-h-t-m-l="[[googleSearchHistoryString_]]">
diff --git a/chrome/browser/safe_browsing/chrome_safe_browsing_blocking_page_factory.cc b/chrome/browser/safe_browsing/chrome_safe_browsing_blocking_page_factory.cc
index 3f03916e..71bdbaab 100644
--- a/chrome/browser/safe_browsing/chrome_safe_browsing_blocking_page_factory.cc
+++ b/chrome/browser/safe_browsing/chrome_safe_browsing_blocking_page_factory.cc
@@ -4,8 +4,13 @@
 
 #include "chrome/browser/safe_browsing/chrome_safe_browsing_blocking_page_factory.h"
 
+#include "chrome/browser/history/history_service_factory.h"
+#include "chrome/browser/interstitials/chrome_settings_page_helper.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/safe_browsing/chrome_controller_client.h"
 #include "components/prefs/pref_service.h"
+#include "components/security_interstitials/content/content_metrics_helper.h"
+#include "components/security_interstitials/content/security_interstitial_controller_client.h"
 #include "content/public/browser/web_contents.h"
 
 namespace safe_browsing {
@@ -49,12 +54,40 @@
                       true,  // is_enhanced_protection_message_enabled
                       IsSafeBrowsingPolicyManaged(*prefs), kHelpCenterLink);
 
-  return new SafeBrowsingBlockingPage(ui_manager, web_contents, main_frame_url,
-                                      unsafe_resources, display_options,
-                                      should_trigger_reporting);
+  return new SafeBrowsingBlockingPage(
+      ui_manager, web_contents, main_frame_url, unsafe_resources,
+      CreateControllerClient(web_contents, unsafe_resources, ui_manager),
+      display_options, should_trigger_reporting);
 }
 
 ChromeSafeBrowsingBlockingPageFactory::ChromeSafeBrowsingBlockingPageFactory() =
     default;
 
+// static
+std::unique_ptr<security_interstitials::SecurityInterstitialControllerClient>
+ChromeSafeBrowsingBlockingPageFactory::CreateControllerClient(
+    content::WebContents* web_contents,
+    const SafeBrowsingBlockingPage::UnsafeResourceList& unsafe_resources,
+    const BaseUIManager* ui_manager) {
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents->GetBrowserContext());
+  DCHECK(profile);
+
+  std::unique_ptr<ContentMetricsHelper> metrics_helper =
+      std::make_unique<ContentMetricsHelper>(
+          HistoryServiceFactory::GetForProfile(
+              Profile::FromBrowserContext(web_contents->GetBrowserContext()),
+              ServiceAccessType::EXPLICIT_ACCESS),
+          unsafe_resources[0].url,
+          BaseBlockingPage::GetReportingInfo(unsafe_resources));
+
+  auto chrome_settings_page_helper =
+      std::make_unique<security_interstitials::ChromeSettingsPageHelper>();
+
+  return std::make_unique<ChromeControllerClient>(
+      web_contents, std::move(metrics_helper), profile->GetPrefs(),
+      ui_manager->app_locale(), ui_manager->default_safe_page(),
+      std::move(chrome_settings_page_helper));
+}
+
 }  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/chrome_safe_browsing_blocking_page_factory.h b/chrome/browser/safe_browsing/chrome_safe_browsing_blocking_page_factory.h
index 8f681a9..bfbf3c04 100644
--- a/chrome/browser/safe_browsing/chrome_safe_browsing_blocking_page_factory.h
+++ b/chrome/browser/safe_browsing/chrome_safe_browsing_blocking_page_factory.h
@@ -26,6 +26,15 @@
   ChromeSafeBrowsingBlockingPageFactory& operator=(
       const ChromeSafeBrowsingBlockingPageFactory&) = delete;
 
+  // Creates a SecurityInterstitialControllerClient configured for //chrome for
+  // safe browsing blocking pages.
+  static std::unique_ptr<
+      security_interstitials::SecurityInterstitialControllerClient>
+  CreateControllerClient(
+      content::WebContents* web_contents,
+      const SafeBrowsingBlockingPage::UnsafeResourceList& unsafe_resources,
+      const BaseUIManager* ui_manager);
+
  private:
   friend struct base::LazyInstanceTraitsBase<
       ChromeSafeBrowsingBlockingPageFactory>;
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.cc b/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.cc
index 374f246..ce359be 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.cc
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.cc
@@ -49,7 +49,7 @@
 // requests.
 // TODO(crbug.com/1191061): Tweak this number to an "optimal" value.
 constexpr char kMaxParallelActiveRequests[] = "wp-max-parallel-active-requests";
-constexpr int kDefaultMaxParallelActiveRequests = 50;
+constexpr int kDefaultMaxParallelActiveRequests = 5;
 
 const int kScanningTimeoutSeconds = 5 * 60;  // 5 minutes
 
diff --git a/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service_unittest.cc b/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service_unittest.cc
index a147c64..e1f8d42 100644
--- a/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service_unittest.cc
+++ b/chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service_unittest.cc
@@ -781,7 +781,7 @@
 }
 
 TEST_F(BinaryUploadServiceTest, TestMaxParallelRequestsFlag) {
-  EXPECT_EQ(50UL, BinaryUploadService::GetParallelActiveRequestsMax());
+  EXPECT_EQ(5UL, BinaryUploadService::GetParallelActiveRequestsMax());
 
   {
     base::test::ScopedCommandLine scoped_command_line;
@@ -801,21 +801,21 @@
     base::test::ScopedCommandLine scoped_command_line;
     scoped_command_line.GetProcessCommandLine()->AppendSwitchASCII(
         "wp-max-parallel-active-requests", "0");
-    EXPECT_EQ(50UL, BinaryUploadService::GetParallelActiveRequestsMax());
+    EXPECT_EQ(5UL, BinaryUploadService::GetParallelActiveRequestsMax());
   }
 
   {
     base::test::ScopedCommandLine scoped_command_line;
     scoped_command_line.GetProcessCommandLine()->AppendSwitchASCII(
         "wp-max-parallel-active-requests", "foo");
-    EXPECT_EQ(50UL, BinaryUploadService::GetParallelActiveRequestsMax());
+    EXPECT_EQ(5UL, BinaryUploadService::GetParallelActiveRequestsMax());
   }
 
   {
     base::test::ScopedCommandLine scoped_command_line;
     scoped_command_line.GetProcessCommandLine()->AppendSwitchASCII(
         "wp-max-parallel-active-requests", "-1");
-    EXPECT_EQ(50UL, BinaryUploadService::GetParallelActiveRequestsMax());
+    EXPECT_EQ(5UL, BinaryUploadService::GetParallelActiveRequestsMax());
   }
 }
 
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
index 28a2554..d03ff5e 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
@@ -13,9 +13,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/history/history_service_factory.h"
-#include "chrome/browser/interstitials/chrome_settings_page_helper.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/safe_browsing/chrome_controller_client.h"
 #include "chrome/browser/safe_browsing/chrome_safe_browsing_blocking_page_factory.h"
 #include "chrome/browser/safe_browsing/safe_browsing_metrics_collector_factory.h"
 #include "chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager_factory.h"
@@ -28,7 +26,6 @@
 #include "components/safe_browsing/core/common/features.h"
 #include "components/safe_browsing/core/common/safe_browsing_prefs.h"
 #include "components/safe_browsing/core/common/utils.h"
-#include "components/security_interstitials/content/content_metrics_helper.h"
 #include "components/security_interstitials/content/security_interstitial_controller_client.h"
 #include "components/security_interstitials/content/settings_page_helper.h"
 #include "components/security_interstitials/content/unsafe_resource_util.h"
@@ -86,16 +83,18 @@
     WebContents* web_contents,
     const GURL& main_frame_url,
     const UnsafeResourceList& unsafe_resources,
+    std::unique_ptr<
+        security_interstitials::SecurityInterstitialControllerClient>
+        controller_client,
     const BaseSafeBrowsingErrorUI::SBErrorDisplayOptions& display_options,
     bool should_trigger_reporting,
     network::SharedURLLoaderFactory* url_loader_for_testing)
-    : BaseBlockingPage(
-          ui_manager,
-          web_contents,
-          main_frame_url,
-          unsafe_resources,
-          CreateControllerClient(web_contents, unsafe_resources, ui_manager),
-          display_options),
+    : BaseBlockingPage(ui_manager,
+                       web_contents,
+                       main_frame_url,
+                       unsafe_resources,
+                       std::move(controller_client),
+                       display_options),
       threat_details_in_progress_(false),
       threat_source_(unsafe_resources[0].threat_source) {
   // Make sure the safe browsing service is available - it may not be when
@@ -103,6 +102,15 @@
   if (!g_browser_process->safe_browsing_service())
     return;
 
+  if (unsafe_resources.size() == 1) {
+    UMA_HISTOGRAM_ENUMERATION(
+        "SafeBrowsing.BlockingPage.ResourceType",
+        safe_browsing::GetResourceTypeFromRequestDestination(
+            unsafe_resources[0].request_destination));
+    UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.BlockingPage.RequestDestination",
+                              unsafe_resources[0].request_destination);
+  }
+
   // Start computing threat details. Trigger Manager will decide if it's safe to
   // begin collecting data at this time. The report will be sent only if the
   // user opts-in on the blocking page later.
@@ -196,46 +204,13 @@
     const GURL& main_frame_url,
     const UnsafeResource& unsafe_resource,
     bool should_trigger_reporting) {
-  UMA_HISTOGRAM_ENUMERATION(
-      "SafeBrowsing.BlockingPage.ResourceType",
-      safe_browsing::GetResourceTypeFromRequestDestination(
-          unsafe_resource.request_destination));
-  UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.BlockingPage.RequestDestination",
-                            unsafe_resource.request_destination);
-  const UnsafeResourceList resources{unsafe_resource};
   // Set up the factory if this has not been done already (tests do that
   // before this method is called).
   if (!factory_)
     factory_ = g_chrome_safe_browsing_blocking_page_factory.Pointer();
   return factory_->CreateSafeBrowsingPage(ui_manager, web_contents,
-                                          main_frame_url, resources,
+                                          main_frame_url, {unsafe_resource},
                                           should_trigger_reporting);
 }
 
-// static
-std::unique_ptr<SecurityInterstitialControllerClient>
-SafeBrowsingBlockingPage::CreateControllerClient(
-    WebContents* web_contents,
-    const UnsafeResourceList& unsafe_resources,
-    const BaseUIManager* ui_manager) {
-  Profile* profile = Profile::FromBrowserContext(
-      web_contents->GetBrowserContext());
-  DCHECK(profile);
-
-  std::unique_ptr<ContentMetricsHelper> metrics_helper =
-      std::make_unique<ContentMetricsHelper>(
-          HistoryServiceFactory::GetForProfile(
-              Profile::FromBrowserContext(web_contents->GetBrowserContext()),
-              ServiceAccessType::EXPLICIT_ACCESS),
-          unsafe_resources[0].url, GetReportingInfo(unsafe_resources));
-
-  auto chrome_settings_page_helper =
-      std::make_unique<security_interstitials::ChromeSettingsPageHelper>();
-
-  return std::make_unique<ChromeControllerClient>(
-      web_contents, std::move(metrics_helper), profile->GetPrefs(),
-      ui_manager->app_locale(), ui_manager->default_safe_page(),
-      std::move(chrome_settings_page_helper));
-}
-
 }  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.h b/chrome/browser/safe_browsing/safe_browsing_blocking_page.h
index 8bb85874..0ccb8c52 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.h
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.h
@@ -107,6 +107,9 @@
       content::WebContents* web_contents,
       const GURL& main_frame_url,
       const UnsafeResourceList& unsafe_resources,
+      std::unique_ptr<
+          security_interstitials::SecurityInterstitialControllerClient>
+          controller_client,
       const BaseSafeBrowsingErrorUI::SBErrorDisplayOptions& display_options,
       bool should_trigger_reporting,
       network::SharedURLLoaderFactory* url_loader_for_testing = nullptr);
@@ -135,11 +138,6 @@
   // SafeBrowsingBlockingPage.
   static SafeBrowsingBlockingPageFactory* factory_;
  private:
-  static std::unique_ptr<
-      security_interstitials::SecurityInterstitialControllerClient>
-  CreateControllerClient(content::WebContents* web_contents,
-                         const UnsafeResourceList& unsafe_resources,
-                         const BaseUIManager* ui_manager);
 
   DISALLOW_COPY_AND_ASSIGN(SafeBrowsingBlockingPage);
 };
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
index 722891be..69338e2 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
@@ -32,6 +32,7 @@
 #include "chrome/browser/policy/policy_test_utils.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/renderer_context_menu/render_view_context_menu_test_util.h"
+#include "chrome/browser/safe_browsing/chrome_safe_browsing_blocking_page_factory.h"
 #include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
 #include "chrome/browser/safe_browsing/safe_browsing_blocking_page_factory.h"
 #include "chrome/browser/safe_browsing/test_safe_browsing_service.h"
@@ -351,12 +352,17 @@
       const UnsafeResourceList& unsafe_resources,
       const BaseSafeBrowsingErrorUI::SBErrorDisplayOptions& display_options,
       bool should_trigger_reporting)
-      : SafeBrowsingBlockingPage(manager,
-                                 web_contents,
-                                 main_frame_url,
-                                 unsafe_resources,
-                                 display_options,
-                                 should_trigger_reporting),
+      : SafeBrowsingBlockingPage(
+            manager,
+            web_contents,
+            main_frame_url,
+            unsafe_resources,
+            ChromeSafeBrowsingBlockingPageFactory::CreateControllerClient(
+                web_contents,
+                unsafe_resources,
+                manager),
+            display_options,
+            should_trigger_reporting),
         wait_for_delete_(false) {
     // Don't wait the whole 3 seconds for the browser test.
     SetThreatDetailsProceedDelayForTesting(100);
diff --git a/chrome/browser/safe_browsing/ui_manager_unittest.cc b/chrome/browser/safe_browsing/ui_manager_unittest.cc
index 6dc674f..a4906fa 100644
--- a/chrome/browser/safe_browsing/ui_manager_unittest.cc
+++ b/chrome/browser/safe_browsing/ui_manager_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/values.h"
 #include "chrome/browser/net/system_network_context_manager.h"
 #include "chrome/browser/password_manager/password_store_factory.h"
+#include "chrome/browser/safe_browsing/chrome_safe_browsing_blocking_page_factory.h"
 #include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
 #include "chrome/browser/safe_browsing/safe_browsing_blocking_page_factory.h"
 #include "chrome/browser/safe_browsing/test_safe_browsing_service.h"
@@ -22,6 +23,7 @@
 #include "components/password_manager/core/browser/password_manager_test_utils.h"
 #include "components/safe_browsing/core/browser/db/util.h"
 #include "components/safe_browsing/core/common/safe_browsing_prefs.h"
+#include "components/security_interstitials/content/security_interstitial_controller_client.h"
 #include "components/security_interstitials/content/unsafe_resource_util.h"
 #include "components/security_interstitials/core/base_safe_browsing_error_ui.h"
 #include "components/security_interstitials/core/unsafe_resource.h"
@@ -463,6 +465,10 @@
             web_contents,
             main_frame_url,
             unsafe_resources,
+            ChromeSafeBrowsingBlockingPageFactory::CreateControllerClient(
+                web_contents,
+                unsafe_resources,
+                manager),
             BaseSafeBrowsingErrorUI::SBErrorDisplayOptions(
                 BaseBlockingPage::IsMainPageLoadBlocked(unsafe_resources),
                 false,                 // is_extended_reporting_opt_in_allowed
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProvider.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProvider.java
index 1232f9c..c4af5b8 100644
--- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProvider.java
+++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProvider.java
@@ -7,6 +7,7 @@
 import android.app.Activity;
 import android.content.ClipData;
 import android.content.ClipboardManager;
+import android.content.ComponentName;
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.view.View;
@@ -23,7 +24,6 @@
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.share.ChromeShareExtras;
 import org.chromium.chrome.browser.share.link_to_text.LinkToTextCoordinator;
 import org.chromium.chrome.browser.share.link_to_text.LinkToTextCoordinator.LinkGeneration;
 import org.chromium.chrome.browser.share.link_to_text.LinkToTextMetricsHelper;
@@ -58,7 +58,11 @@
 /**
  * Provides {@code PropertyModel}s of Chrome-provided sharing options.
  */
-class ChromeProvidedSharingOptionsProvider {
+public class ChromeProvidedSharingOptionsProvider {
+    // ComponentName used for Chrome share options in ShareParams.TargetChosenCallback
+    public static final ComponentName CHROME_PROVIDED_FEATURE_COMPONENT_NAME =
+            new ComponentName("CHROME", "CHROME_FEATURE");
+
     private final Activity mActivity;
     private final Supplier<Tab> mTabProvider;
     private final BottomSheetController mBottomSheetController;
@@ -70,11 +74,11 @@
     private final long mShareStartTime;
     private final List<FirstPartyOption> mOrderedFirstPartyOptions;
     private final ChromeOptionShareCallback mChromeOptionShareCallback;
-    private ScreenshotCoordinator mScreenshotCoordinator;
     private final String mUrl;
     private final ImageEditorModuleProvider mImageEditorModuleProvider;
     private final Tracker mFeatureEngagementTracker;
-    private @LinkGeneration int mLinkGenerationStatusForMetrics = LinkGeneration.MAX;
+    private final @LinkGeneration int mLinkGenerationStatusForMetrics;
+    private ScreenshotCoordinator mScreenshotCoordinator;
 
     /**
      * Constructs a new {@link ChromeProvidedSharingOptionsProvider}.
@@ -85,7 +89,6 @@
      * @param bottomSheetContent The {@link ShareSheetBottomSheetContent} for the current
      * activity.
      * @param shareParams The {@link ShareParams} for the current share.
-     * @param chromeShareExtras The {@link ChromeShareExtras} for the current share.
      * @param printTab A {@link Callback} that will print a given Tab.
      * @param shareStartTime The start time of the current share.
      * @param chromeOptionShareCallback A ChromeOptionShareCallback that can be used by
@@ -93,16 +96,14 @@
      * @param imageEditorModuleProvider Image Editor module entry point if present in the APK.
      * @param featureEngagementTracker feature engagement tracker.
      * @param url Url to share.
-     * @param shareDetailsForMetrics User action of sharing text from failed link-to-text
-     *         generation,
-     * sharing text from successful link-to-text generation, or sharing link-to-text.
+     * @param linkGenerationStatusForMetrics User action of sharing text from failed link-to-text
+     * generation, sharing text from successful link-to-text generation, or sharing link-to-text.
      */
     ChromeProvidedSharingOptionsProvider(Activity activity, Supplier<Tab> tabProvider,
             BottomSheetController bottomSheetController,
             ShareSheetBottomSheetContent bottomSheetContent, ShareParams shareParams,
-            ChromeShareExtras chromeShareExtras, Callback<Tab> printTab,
-            SettingsLauncher settingsLauncher, boolean isSyncEnabled, long shareStartTime,
-            ChromeOptionShareCallback chromeOptionShareCallback,
+            Callback<Tab> printTab, SettingsLauncher settingsLauncher, boolean isSyncEnabled,
+            long shareStartTime, ChromeOptionShareCallback chromeOptionShareCallback,
             ImageEditorModuleProvider imageEditorModuleProvider, Tracker featureEngagementTracker,
             String url, @LinkGeneration int linkGenerationStatusForMetrics) {
         mActivity = activity;
@@ -203,6 +204,7 @@
                         recordTimeToShare(mShareStartTime);
                         mBottomSheetController.hideContent(mBottomSheetContent, true);
                         mOnClickCallback.onResult(view);
+                        callTargetChosenCallback();
                     }, /*showNewBadge*/ false);
             return new FirstPartyOption(model, Arrays.asList(mContentTypesInBuilder),
                     Arrays.asList(mContentTypesToDisableFor), mDisableForMultiWindow);
@@ -297,6 +299,7 @@
                     // observer will then remove itself.
                     mBottomSheetController.addObserver(mSheetObserver);
                     mBottomSheetController.hideContent(mBottomSheetContent, true);
+                    callTargetChosenCallback();
                 }, showNewBadge);
 
         return new FirstPartyOption(propertyModel,
@@ -319,6 +322,7 @@
                     // observer will then remove itself.
                     mBottomSheetController.addObserver(mSheetObserver);
                     mBottomSheetController.hideContent(mBottomSheetContent, true);
+                    callTargetChosenCallback();
                 }, /*showNewBadge*/ false);
         return new FirstPartyOption(propertyModel,
                 Arrays.asList(ContentType.LINK_PAGE_VISIBLE, ContentType.TEXT,
@@ -451,6 +455,16 @@
                 .build();
     }
 
+    private void callTargetChosenCallback() {
+        ShareParams.TargetChosenCallback callback = mShareParams.getCallback();
+        if (callback != null) {
+            callback.onTargetChosen(CHROME_PROVIDED_FEATURE_COMPONENT_NAME);
+            // Reset callback after onTargetChosen() is called to prevent cancel() being called when
+            // the sheet is closed.
+            mShareParams.setCallback(null);
+        }
+    }
+
     static void recordTimeToShare(long shareStartTime) {
         RecordHistogram.recordMediumTimesHistogram("Sharing.SharingHubAndroid.TimeToShare",
                 System.currentTimeMillis() - shareStartTime);
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetCoordinator.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetCoordinator.java
index 479dd0d..f49afbc 100644
--- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetCoordinator.java
+++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetCoordinator.java
@@ -254,8 +254,8 @@
             return new ArrayList<>();
         }
         mChromeProvidedSharingOptionsProvider = new ChromeProvidedSharingOptionsProvider(activity,
-                mTabProvider, mBottomSheetController, mBottomSheet, shareParams, chromeShareExtras,
-                mPrintTabCallback, mSettingsLauncher, mIsSyncEnabled, mShareStartTime, this,
+                mTabProvider, mBottomSheetController, mBottomSheet, shareParams, mPrintTabCallback,
+                mSettingsLauncher, mIsSyncEnabled, mShareStartTime, this,
                 mImageEditorModuleProvider, mFeatureEngagementTracker,
                 getUrlToShare(shareParams, chromeShareExtras,
                         mTabProvider.get().isInitialized() ? mTabProvider.get().getUrl().getSpec()
@@ -287,9 +287,9 @@
             PostTask.postTask(UiThreadTaskTraits.DEFAULT, callback.bind(null));
             return;
         }
-        List<PropertyModel> models = mPropertyModelBuilder.selectThirdPartyApps(mBottomSheet,
-                contentTypes, params, saveLastUsed, params.getWindow(), mShareStartTime,
-                mLinkGenerationStatusForMetrics);
+        List<PropertyModel> models =
+                mPropertyModelBuilder.selectThirdPartyApps(mBottomSheet, contentTypes, params,
+                        saveLastUsed, mShareStartTime, mLinkGenerationStatusForMetrics);
         // More...
         PropertyModel morePropertyModel = ShareSheetPropertyModelBuilder.createPropertyModel(
                 AppCompatResources.getDrawable(activity, R.drawable.sharing_more),
@@ -308,6 +308,10 @@
                         profile = Profile.fromWebContents(mTabProvider.get().getWebContents());
                     }
                     ShareHelper.showDefaultShareUi(params, profile, saveLastUsed);
+                    // Reset callback to prevent cancel() being called when the custom sheet is
+                    // closed. The callback will be called by ShareHelper on actions from the
+                    // default share UI.
+                    params.setCallback(null);
                 },
                 /*displayNew*/ false);
         models.add(morePropertyModel);
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetPropertyModelBuilder.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetPropertyModelBuilder.java
index b169460a..e915dec 100644
--- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetPropertyModelBuilder.java
+++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetPropertyModelBuilder.java
@@ -25,7 +25,6 @@
 import org.chromium.chrome.browser.share.link_to_text.LinkToTextMetricsHelper;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.components.browser_ui.share.ShareParams;
-import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.modelutil.PropertyModel;
 
 import java.lang.annotation.Retention;
@@ -152,10 +151,8 @@
 
     protected List<PropertyModel> selectThirdPartyApps(ShareSheetBottomSheetContent bottomSheet,
             Set<Integer> contentTypes, ShareParams params, boolean saveLastUsed,
-            WindowAndroid window, long shareStartTime,
-            @LinkGeneration int linkGenerationStatusForMetrics) {
+            long shareStartTime, @LinkGeneration int linkGenerationStatusForMetrics) {
         List<String> thirdPartyActivityNames = getThirdPartyActivityNames();
-        final ShareParams.TargetChosenCallback callback = params.getCallback();
         List<ResolveInfo> resolveInfoList =
                 getCompatibleApps(contentTypes, params.getFileContentType());
         List<ResolveInfo> thirdPartyActivities = new ArrayList<>();
@@ -190,11 +187,9 @@
         for (int i = 0; i < MAX_NUM_APPS && i < thirdPartyActivities.size(); ++i) {
             ResolveInfo info = thirdPartyActivities.get(i);
             final int logIndex = i;
-            OnClickListener onClickListener = v -> {
-                onThirdPartyAppSelected(bottomSheet, params, window, callback, saveLastUsed,
-                        info.activityInfo, logIndex, shareStartTime,
-                        linkGenerationStatusForMetrics);
-            };
+            OnClickListener onClickListener = v
+                    -> onThirdPartyAppSelected(bottomSheet, params, saveLastUsed, info.activityInfo,
+                            logIndex, shareStartTime, linkGenerationStatusForMetrics);
             PropertyModel propertyModel =
                     createPropertyModel(ShareHelper.loadIconForResolveInfo(info, mPackageManager),
                             (String) info.loadLabel(mPackageManager), onClickListener,
@@ -206,9 +201,8 @@
     }
 
     private void onThirdPartyAppSelected(ShareSheetBottomSheetContent bottomSheet,
-            ShareParams params, WindowAndroid window, ShareParams.TargetChosenCallback callback,
-            boolean saveLastUsed, ActivityInfo ai, int logIndex, long shareStartTime,
-            @LinkGeneration int linkGenerationStatusForMetrics) {
+            ShareParams params, boolean saveLastUsed, ActivityInfo ai, int logIndex,
+            long shareStartTime, @LinkGeneration int linkGenerationStatusForMetrics) {
         // Record all metrics.
         RecordUserAction.record("SharingHubAndroid.ThirdPartyAppSelected");
         RecordHistogram.recordEnumeratedHistogram(
@@ -219,8 +213,12 @@
                     linkGenerationStatusForMetrics);
         }
         ComponentName component = new ComponentName(ai.applicationInfo.packageName, ai.name);
+        ShareParams.TargetChosenCallback callback = params.getCallback();
         if (callback != null) {
             callback.onTargetChosen(component);
+            // Reset callback after onTargetChosen() is called to prevent cancel() being called when
+            // the sheet is closed.
+            params.setCallback(null);
         }
         if (saveLastUsed) {
             ShareHelper.setLastShareComponentName(mProfile, component);
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProviderTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProviderTest.java
index 5b1fe71..3032fe0b 100644
--- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProviderTest.java
+++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProviderTest.java
@@ -40,7 +40,6 @@
 import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.share.ChromeShareExtras;
 import org.chromium.chrome.browser.share.link_to_text.LinkToTextCoordinator.LinkGeneration;
 import org.chromium.chrome.browser.share.share_sheet.ShareSheetPropertyModelBuilder.ContentType;
 import org.chromium.chrome.browser.tab.Tab;
@@ -78,36 +77,31 @@
     @Rule
     public JniMocker mJniMocker = new JniMocker();
 
+    private static final String URL = "http://www.google.com/";
+
     @Mock
     private UserPrefs.Natives mUserPrefsNatives;
-
     @Mock
     private Profile mProfile;
     @Mock
     private PrefService mPrefService;
-
-    private static final String URL = "http://www.google.com/";
-
     @Mock
     private ShareSheetCoordinator mShareSheetCoordinator;
+    @Mock
+    private Supplier<Tab> mTabProvider;
+    @Mock
+    private Tab mTab;
+    @Mock
+    private BottomSheetController mBottomSheetController;
+    @Mock
+    private WebContents mWebContents;
+    @Mock
+    private Tracker mTracker;
+    @Mock
+    private ShareParams.TargetChosenCallback mTargetChosenCallback;
 
     private Activity mActivity;
     private ChromeProvidedSharingOptionsProvider mChromeProvidedSharingOptionsProvider;
-
-    @Mock
-    private Supplier<Tab> mTabProvider;
-
-    @Mock
-    private Tab mTab;
-
-    @Mock
-    private BottomSheetController mBottomSheetController;
-
-    @Mock
-    private WebContents mWebContents;
-
-    @Mock
-    private Tracker mTracker;
     private UserActionTester mActionTester;
 
     @Before
@@ -346,7 +340,6 @@
         @LinkGeneration
         int linkGenerationStatus = LinkGeneration.LINK;
 
-        String detailMetrics = "LinkGeneration.DetailsMetrics";
         setUpChromeProvidedSharingOptionsProviderTest(
                 /*printingEnabled=*/false, linkGenerationStatus);
         List<PropertyModel> propertyModels =
@@ -356,17 +349,36 @@
         assertCorrectMetrics(propertyModels, linkGenerationStatus);
     }
 
+    @Test
+    @MediumTest
+    public void getPropertyModels_onClick_callsOnTargetChosen() {
+        setUpChromeProvidedSharingOptionsProviderTest(
+                /*printingEnabled=*/false, LinkGeneration.LINK);
+
+        List<PropertyModel> propertyModels =
+                mChromeProvidedSharingOptionsProvider.getPropertyModels(
+                        ImmutableSet.of(ContentType.LINK_PAGE_VISIBLE), /*isMultiWindow=*/false);
+        View.OnClickListener onClickListener =
+                propertyModels.get(0).get(ShareSheetItemViewProperties.CLICK_LISTENER);
+
+        onClickListener.onClick(null);
+        Mockito.verify(mTargetChosenCallback, Mockito.times(1))
+                .onTargetChosen(ChromeProvidedSharingOptionsProvider
+                                        .CHROME_PROVIDED_FEATURE_COMPONENT_NAME);
+    }
+
     private void setUpChromeProvidedSharingOptionsProviderTest(
             boolean printingEnabled, @LinkGeneration int linkGenerationStatus) {
         Mockito.when(mPrefService.getBoolean(anyString())).thenReturn(printingEnabled);
 
-        ShareParams shareParams = new ShareParams.Builder(null, /*title=*/"", /*url=*/"").build();
+        ShareParams shareParams = new ShareParams.Builder(null, /*title=*/"", /*url=*/"")
+                                          .setCallback(mTargetChosenCallback)
+                                          .build();
         mChromeProvidedSharingOptionsProvider = new ChromeProvidedSharingOptionsProvider(mActivity,
                 mTabProvider, mBottomSheetController,
                 new ShareSheetBottomSheetContent(
                         mActivity, null, mShareSheetCoordinator, shareParams),
-                new ShareParams.Builder(null, "", "").build(),
-                new ChromeShareExtras.Builder().build(),
+                shareParams,
                 /*TabPrinterDelegate=*/null,
                 /*settingsLauncher=*/null,
                 /*syncState=*/false,
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetCoordinatorTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetCoordinatorTest.java
index 02e5d78..b008c49 100644
--- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetCoordinatorTest.java
+++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetCoordinatorTest.java
@@ -5,16 +5,20 @@
 package org.chromium.chrome.browser.share.share_sheet;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anySet;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.when;
 
 import android.app.Activity;
+import android.view.View;
 
-import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -23,21 +27,26 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.robolectric.Robolectric;
 
-import org.chromium.base.test.BaseActivityTestRule;
+import org.chromium.base.supplier.Supplier;
+import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.CallbackHelper;
-import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.JniMocker;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
-import org.chromium.chrome.test.ChromeBrowserTestRule;
-import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.components.browser_ui.share.ShareParams;
+import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils;
+import org.chromium.components.dom_distiller.core.DomDistillerUrlUtilsJni;
+import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.modelutil.PropertyModel;
-import org.chromium.ui.test.util.DummyUiActivity;
+import org.chromium.url.JUnitTestGURLs;
 
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -47,40 +56,41 @@
 /**
  * Tests {@link ShareSheetCoordinator}.
  */
-@RunWith(ChromeJUnit4ClassRunner.class)
-@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+@RunWith(BaseRobolectricTestRunner.class)
+@Features.EnableFeatures({ChromeFeatureList.PREEMPTIVE_LINK_TO_TEXT_GENERATION})
 public final class ShareSheetCoordinatorTest {
-    @Rule
-    public final ChromeBrowserTestRule mBrowserTestRule = new ChromeBrowserTestRule();
-
-    @Rule
-    public BaseActivityTestRule<DummyUiActivity> mActivityTestRule =
-            new BaseActivityTestRule<>(DummyUiActivity.class);
+    private static final String MOCK_URL = JUnitTestGURLs.EXAMPLE_URL;
 
     @Rule
     public TestRule mFeatureProcessor = new Features.JUnitProcessor();
+    @Rule
+    public JniMocker mJniMocker = new JniMocker();
 
     @Mock
+    private DomDistillerUrlUtils.Natives mDistillerUrlUtilsJniMock;
+    @Mock
     private ActivityLifecycleDispatcher mLifecycleDispatcher;
-
     @Mock
     private BottomSheetController mController;
-
     @Mock
     private ShareSheetPropertyModelBuilder mPropertyModelBuilder;
-
     @Mock
-    private ShareParams mParams;
+    private ShareParams.TargetChosenCallback mTargetChosenCallback;
+    @Mock
+    private Supplier<Tab> mTabProvider;
+    @Mock
+    private WindowAndroid mWindow;
 
     private Activity mActivity;
+    private ShareParams mParams;
     private ShareSheetCoordinator mShareSheetCoordinator;
 
     @Before
     public void setUp() {
-        mActivityTestRule.launchActivity(null);
-        mActivity = mActivityTestRule.getActivity();
-
         MockitoAnnotations.initMocks(this);
+        mJniMocker.mock(DomDistillerUrlUtilsJni.TEST_HOOKS, mDistillerUrlUtilsJniMock);
+
+        mActivity = Robolectric.setupActivity(Activity.class);
         PropertyModel testModel1 = new PropertyModel.Builder(ShareSheetItemViewProperties.ALL_KEYS)
                                            .with(ShareSheetItemViewProperties.ICON, null)
                                            .with(ShareSheetItemViewProperties.LABEL, "testModel1")
@@ -94,16 +104,22 @@
 
         ArrayList<PropertyModel> thirdPartyPropertyModels =
                 new ArrayList<>(Arrays.asList(testModel1, testModel2));
+        when(mWindow.getActivity()).thenReturn(new WeakReference<>(mActivity));
         when(mPropertyModelBuilder.selectThirdPartyApps(
-                     any(), anySet(), any(), anyBoolean(), any(), anyLong(), anyInt()))
+                     any(), anySet(), any(), anyBoolean(), anyLong(), anyInt()))
                 .thenReturn(thirdPartyPropertyModels);
+        when(mDistillerUrlUtilsJniMock.getOriginalUrlFromDistillerUrl(anyString()))
+                .thenReturn(JUnitTestGURLs.getGURL(MOCK_URL));
 
-        mShareSheetCoordinator = new ShareSheetCoordinator(mController, mLifecycleDispatcher, null,
-                mPropertyModelBuilder, null, null, null, false, null, null);
+        mParams = new ShareParams.Builder(mWindow, "title", MOCK_URL)
+                          .setCallback(mTargetChosenCallback)
+                          .build();
+        mShareSheetCoordinator = new ShareSheetCoordinator(mController, mLifecycleDispatcher,
+                mTabProvider, mPropertyModelBuilder, null, null, null, false, null, null);
     }
 
     @Test
-    @MediumTest
+    @SmallTest
     public void disableFirstPartyFeatures() {
         mShareSheetCoordinator.disableFirstPartyFeaturesForTesting();
 
@@ -114,10 +130,9 @@
     }
 
     @Test
-    @MediumTest
+    @SmallTest
     public void testCreateThirdPartyPropertyModels() throws TimeoutException {
-        final AtomicReference<List<PropertyModel>> resultPropertyModels =
-                new AtomicReference<List<PropertyModel>>();
+        final AtomicReference<List<PropertyModel>> resultPropertyModels = new AtomicReference<>();
         CallbackHelper helper = new CallbackHelper();
         mShareSheetCoordinator.createThirdPartyPropertyModels(mActivity, mParams,
                 ShareSheetPropertyModelBuilder.ALL_CONTENT_TYPES_FOR_TEST,
@@ -137,4 +152,26 @@
                 mActivity.getResources().getString(R.string.sharing_more_icon_label),
                 propertyModels.get(2).get(ShareSheetItemViewProperties.LABEL));
     }
+
+    @Test
+    @SmallTest
+    public void testClickMoreRemovesCallback() throws TimeoutException {
+        final AtomicReference<List<PropertyModel>> resultPropertyModels = new AtomicReference<>();
+        CallbackHelper helper = new CallbackHelper();
+        mShareSheetCoordinator.createThirdPartyPropertyModels(mActivity, mParams,
+                ShareSheetPropertyModelBuilder.ALL_CONTENT_TYPES_FOR_TEST,
+                /*saveLastUsed=*/false, models -> {
+                    resultPropertyModels.set(models);
+                    helper.notifyCalled();
+                });
+        helper.waitForFirst();
+        List<PropertyModel> propertyModels = resultPropertyModels.get();
+
+        View.OnClickListener onClickListener =
+                propertyModels.get(2).get(ShareSheetItemViewProperties.CLICK_LISTENER);
+
+        assertNotNull("Callback should not be null before pressing More", mParams.getCallback());
+        onClickListener.onClick(null);
+        assertNull("Callback should be null after pressing More", mParams.getCallback());
+    }
 }
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetPropertyModelBuilderTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetPropertyModelBuilderTest.java
index f95dfbe..6ba5b6b 100644
--- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetPropertyModelBuilderTest.java
+++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetPropertyModelBuilderTest.java
@@ -280,8 +280,7 @@
 
         List<PropertyModel> propertyModels = mPropertyModelBuilder.selectThirdPartyApps(null,
                 ImmutableSet.of(ContentType.LINK_PAGE_VISIBLE), shareParams, /*saveLastUsed=*/false,
-                /*WindowAndroid=*/null, /*shareStartTime=*/0,
-                /*linkGenerationStatusForMetrics=*/LinkGeneration.MAX);
+                /*shareStartTime=*/0, /*linkGenerationStatusForMetrics=*/LinkGeneration.MAX);
 
         assertEquals("Incorrect number of property models.", 2, propertyModels.size());
         assertModelsAreInTheRightOrder(
@@ -296,8 +295,7 @@
 
         List<PropertyModel> propertyModels = mPropertyModelBuilder.selectThirdPartyApps(null,
                 ImmutableSet.of(ContentType.IMAGE), shareParams, /*saveLastUsed=*/false,
-                /*WindowAndroid=*/null, /*shareStartTime=*/0,
-                /*linkGenerationStatusForMetrics=*/LinkGeneration.MAX);
+                /*shareStartTime=*/0, /*linkGenerationStatusForMetrics=*/LinkGeneration.MAX);
 
         assertEquals("Incorrect number of property models.", 2, propertyModels.size());
         assertModelsAreInTheRightOrder(
@@ -312,7 +310,7 @@
 
         List<PropertyModel> propertyModels = mPropertyModelBuilder.selectThirdPartyApps(null,
                 ImmutableSet.of(ContentType.LINK_PAGE_VISIBLE, ContentType.IMAGE), shareParams,
-                /*saveLastUsed=*/false, /*WindowAndroid=*/null, /*shareStartTime=*/0,
+                /*saveLastUsed=*/false, /*shareStartTime=*/0,
                 /*linkGenerationStatusForMetrics=*/LinkGeneration.MAX);
 
         assertEquals("Incorrect number of property models.", 4, propertyModels.size());
diff --git a/chrome/browser/share/android/test_java_sources.gni b/chrome/browser/share/android/test_java_sources.gni
index 425204ef..33b670b 100644
--- a/chrome/browser/share/android/test_java_sources.gni
+++ b/chrome/browser/share/android/test_java_sources.gni
@@ -13,7 +13,6 @@
   "//chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfCoordinatorTest.java",
   "//chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ChromeProvidedSharingOptionsProviderTest.java",
   "//chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetBottomSheetContentTest.java",
-  "//chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetCoordinatorTest.java",
   "//chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetPropertyModelBuilderTest.java",
 ]
 
@@ -28,6 +27,7 @@
   "//chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetMediatorUnitTest.java",
   "//chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/send_tab_to_self/NotificationSharedPrefManagerTest.java",
   "//chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/send_tab_to_self/SendTabToSelfAndroidBridgeTest.java",
+  "//chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetCoordinatorTest.java",
 ]
 
 share_junit_test_java_deps = [
diff --git a/chrome/browser/sync/test/integration/single_client_sync_invalidations_test.cc b/chrome/browser/sync/test/integration/single_client_sync_invalidations_test.cc
index 2afcae7c..c1c9d90 100644
--- a/chrome/browser/sync/test/integration/single_client_sync_invalidations_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_sync_invalidations_test.cc
@@ -3,6 +3,8 @@
 // found in the LICENSE file.
 
 #include "base/test/scoped_feature_list.h"
+#include "base/time/time.h"
+#include "base/time/time_override.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/sync/sync_invalidations_service_factory.h"
 #include "chrome/browser/sync/test/integration/bookmarks_helper.h"
@@ -38,6 +40,12 @@
 
 const char kSyncedBookmarkURL[] = "http://www.mybookmark.com";
 
+MATCHER(HasBeenRecentlyUpdated, "") {
+  return syncer::ProtoTimeToTime(
+             arg.specifics().device_info().last_updated_timestamp()) >
+         base::Time::Now() - base::TimeDelta::FromMinutes(10);
+}
+
 MATCHER_P(HasCacheGuid, expected_cache_guid, "") {
   return arg.specifics().device_info().cache_guid() == expected_cache_guid;
 }
@@ -88,6 +96,51 @@
              .instance_id_token() == expected_token;
 }
 
+// This class helps to count the number of GU_TRIGGER events for the |type|
+// since the object has been created.
+class GetUpdatesTriggeredObserver : public fake_server::FakeServer::Observer {
+ public:
+  GetUpdatesTriggeredObserver(fake_server::FakeServer* fake_server,
+                              syncer::ModelType type)
+      : fake_server_(fake_server), type_(type) {
+    fake_server_->AddObserver(this);
+  }
+
+  ~GetUpdatesTriggeredObserver() override {
+    fake_server_->RemoveObserver(this);
+  }
+
+  void OnSuccessfulGetUpdates() override {
+    sync_pb::ClientToServerMessage message;
+    fake_server_->GetLastGetUpdatesMessage(&message);
+
+    if (message.get_updates().get_updates_origin() !=
+        sync_pb::SyncEnums::GU_TRIGGER) {
+      return;
+    }
+    for (const sync_pb::DataTypeProgressMarker& progress_marker :
+         message.get_updates().from_progress_marker()) {
+      if (progress_marker.data_type_id() !=
+          syncer::GetSpecificsFieldNumberFromModelType(type_)) {
+        continue;
+      }
+      if (progress_marker.get_update_triggers().datatype_refresh_nudges() > 0) {
+        num_nudged_get_updates_for_data_type_++;
+      }
+    }
+  }
+
+  size_t num_nudged_get_updates_for_data_type() const {
+    return num_nudged_get_updates_for_data_type_;
+  }
+
+ private:
+  fake_server::FakeServer* const fake_server_;
+  const syncer::ModelType type_;
+
+  size_t num_nudged_get_updates_for_data_type_ = 0;
+};
+
 sync_pb::DeviceInfoSpecifics CreateDeviceInfoSpecifics(
     const std::string& cache_guid,
     const std::string& fcm_registration_token) {
@@ -246,6 +299,65 @@
       ElementsAre(kRemoteFCMRegistrationToken));
 }
 
+IN_PROC_BROWSER_TEST_F(SingleClientWithUseSyncInvalidationsTest,
+                       PRE_ShouldNotSendAdditionalGetUpdates) {
+  base::subtle::ScopedTimeClockOverrides time_clock_overrides(
+      []() {
+        const base::TimeDelta time_delta = base::TimeDelta::FromDays(2);
+        return base::subtle::TimeNowIgnoringOverride() - time_delta;
+      },
+      nullptr, nullptr);
+
+  ASSERT_TRUE(SetupSync());
+}
+
+IN_PROC_BROWSER_TEST_F(SingleClientWithUseSyncInvalidationsTest,
+                       ShouldNotSendAdditionalGetUpdates) {
+  // Verify that DeviceInfo has been updated long time ago.
+  ASSERT_THAT(fake_server_->GetSyncEntitiesByModelType(syncer::DEVICE_INFO),
+              ElementsAre(testing::Not(HasBeenRecentlyUpdated())));
+
+  GetUpdatesTriggeredObserver observer(GetFakeServer(),
+                                       syncer::ModelType::AUTOFILL);
+  ASSERT_TRUE(SetupClients());
+  ASSERT_TRUE(GetClient(0)->AwaitEngineInitialization());
+  ASSERT_TRUE(GetClient(0)->AwaitSyncSetupCompletion());
+
+  // Wait until DeviceInfo is updated.
+  ASSERT_TRUE(ServerDeviceInfoMatchChecker(
+                  GetFakeServer(), ElementsAre(HasBeenRecentlyUpdated()))
+                  .Wait());
+
+  // Perform an additional sync cycle to be sure that there will be at least one
+  // more GetUpdates request if it was triggered.
+  const std::string kTitle1 = "Title 1";
+  AddFolder(0, GetBookmarkBarNode(0), 0, kTitle1);
+  ASSERT_TRUE(ServerBookmarksEqualityChecker(GetSyncService(0), GetFakeServer(),
+                                             {{kTitle1, GURL()}},
+                                             /*cryptographer=*/nullptr)
+                  .Wait());
+
+  const std::string kTitle2 = "Title 2";
+  AddFolder(0, GetBookmarkBarNode(0), 0, kTitle2);
+  ASSERT_TRUE(
+      ServerBookmarksEqualityChecker(GetSyncService(0), GetFakeServer(),
+                                     {{kTitle1, GURL()}, {kTitle2, GURL()}},
+                                     /*cryptographer=*/nullptr)
+          .Wait());
+
+  // There will be one TriggerRefresh request in tests due to
+  // ConfigurationRefresher. There shouldn't be any additional GU_TRIGGER
+  // with nudge DeviceInfo data type.
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  // On ChromeOS tests data types are configured twice and hence there are two
+  // expected TriggerRefresh calls during initialization. It happens due to
+  // SyncArcPackageHelper which eventually triggers reconfiguration.
+  EXPECT_EQ(2u, observer.num_nudged_get_updates_for_data_type());
+#else
+  EXPECT_EQ(1u, observer.num_nudged_get_updates_for_data_type());
+#endif
+}
+
 class SingleClientWithUseSyncInvalidationsForWalletAndOfferTest
     : public SyncTest {
  public:
diff --git a/chrome/browser/tabmodel/BUILD.gn b/chrome/browser/tabmodel/BUILD.gn
index fefa085..a956cf4 100644
--- a/chrome/browser/tabmodel/BUILD.gn
+++ b/chrome/browser/tabmodel/BUILD.gn
@@ -16,6 +16,7 @@
     "android/java/src/org/chromium/chrome/browser/tabmodel/IncognitoStateProvider.java",
     "android/java/src/org/chromium/chrome/browser/tabmodel/IncognitoTabHost.java",
     "android/java/src/org/chromium/chrome/browser/tabmodel/IncognitoTabHostRegistry.java",
+    "android/java/src/org/chromium/chrome/browser/tabmodel/IncognitoTabHostUtils.java",
     "android/java/src/org/chromium/chrome/browser/tabmodel/IncognitoTabModel.java",
     "android/java/src/org/chromium/chrome/browser/tabmodel/IncognitoTabModelImpl.java",
     "android/java/src/org/chromium/chrome/browser/tabmodel/IncognitoTabModelObserver.java",
diff --git a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/IncognitoTabHostUtils.java b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/IncognitoTabHostUtils.java
new file mode 100644
index 0000000..8b03486c
--- /dev/null
+++ b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/IncognitoTabHostUtils.java
@@ -0,0 +1,43 @@
+// Copyright 2021 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.tabmodel;
+
+/**
+ * Utilities concerning all incognito tabs in all {@link IncognitoTabHost}s.
+ */
+public class IncognitoTabHostUtils {
+    /**
+     * Determine whether there are any incognito tabs.
+     */
+    public static boolean doIncognitoTabsExist() {
+        for (IncognitoTabHost host : IncognitoTabHostRegistry.getInstance().getHosts()) {
+            if (host.hasIncognitoTabs()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Determine whether the incognito tab model is active.
+     */
+    public static boolean isIncognitoTabModelActive() {
+        for (IncognitoTabHost host : IncognitoTabHostRegistry.getInstance().getHosts()) {
+            if (host.isActiveModel()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Closes all incognito tabs.
+     */
+    public static void closeAllIncognitoTabs() {
+        for (IncognitoTabHost host : IncognitoTabHostRegistry.getInstance().getHosts()) {
+            host.closeAllIncognitoTabs();
+        }
+    }
+}
diff --git a/chrome/browser/translate/translate_manager_browsertest.cc b/chrome/browser/translate/translate_manager_browsertest.cc
index fddf235..6db512d 100644
--- a/chrome/browser/translate/translate_manager_browsertest.cc
+++ b/chrome/browser/translate/translate_manager_browsertest.cc
@@ -2073,9 +2073,8 @@
 }
 
 // Test that iframes can be translated.
-// TODO(https://crbug.com/1106446) disabled due to flakiness
 IN_PROC_BROWSER_TEST_F(TranslateManagerWithSubFrameSupportBrowserTest,
-                       DISABLED_TranslateIframe) {
+                       TranslateIframe) {
   base::HistogramTester histograms;
   SetTranslateScript(kTestValidScript);
 
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
index 71d5252d..2850876f 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
+++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -443,7 +443,7 @@
      <message name="IDS_AUTOFILL_PROFILE_EDITOR_COUNTRY" desc="Label for a spinner input field containing a list of countries or regions [CHAR_LIMIT=32]">
         Country/Region
       </message>
-      <message name="IDS_AUTOFILL_PROFILE_EDITOR_HONORIFIC_PREFIX" desc="Label for text input field containing a title that can be auto-filled by Chrome. [CHAR_LIMIT=32]" meaning="A 'Title' field in a web form could be a prefix like Ms., Mx., or Dr. or a position held, like Captain or Rabbi.">
+      <message name="IDS_AUTOFILL_PROFILE_EDITOR_HONORIFIC_PREFIX" desc="Label for text input field containing a title that can be auto-filled by Chrome. A 'Title' field in a web form could be a prefix like Ms., Mx., or Dr. or a position held, like Captain or Rabbi. [CHAR_LIMIT=32]" meaning="Honorific">
         Title
       </message>
       <message name="IDS_AUTOFILL_PROFILE_EDITOR_EMAIL_ADDRESS" desc="Label for text input field containing an e-mail address. [CHAR_LIMIT=32]">
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
index dc4ad773..7db1b58 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
@@ -351,17 +351,9 @@
   ASSERT_FALSE(IsWindowFullscreenForTabOrPending());
 }
 
-// Disabled due to flakiness.
-// TODO(crbug.com/976883): Fix and re-enable this.
 // Tests mouse lock and fullscreen modes can be escaped with ESC key.
-#if defined(OS_WIN)
-#define MAYBE_EscapingMouseLockAndFullscreen EscapingMouseLockAndFullscreen
-#else
-#define MAYBE_EscapingMouseLockAndFullscreen \
-  DISABLED_EscapingMouseLockAndFullscreen
-#endif
 IN_PROC_BROWSER_TEST_F(FullscreenControllerInteractiveTest,
-                       MAYBE_EscapingMouseLockAndFullscreen) {
+                       EscapingMouseLockAndFullscreen) {
   auto test_server_handle = embedded_test_server()->StartAndReturnHandle();
   ASSERT_TRUE(test_server_handle);
   ui_test_utils::NavigateToURL(
@@ -492,21 +484,15 @@
   ASSERT_TRUE(IsMouseLocked());
 }
 
+// Tests mouse lock is exited on page navigation.
 #if (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && defined(USE_AURA)
-// These are flaky on linux_aura.
-// http://crbug.com/163931
+// https://crbug.com/1191964
 #define MAYBE_TestTabExitsMouseLockOnNavigation \
     DISABLED_TestTabExitsMouseLockOnNavigation
-#define MAYBE_TestTabExitsMouseLockOnGoBack \
-    DISABLED_TestTabExitsMouseLockOnGoBack
 #else
 #define MAYBE_TestTabExitsMouseLockOnNavigation \
     TestTabExitsMouseLockOnNavigation
-#define MAYBE_TestTabExitsMouseLockOnGoBack \
-    TestTabExitsMouseLockOnGoBack
 #endif
-
-// Tests mouse lock is exited on page navigation.
 IN_PROC_BROWSER_TEST_F(FullscreenControllerInteractiveTest,
                        MAYBE_TestTabExitsMouseLockOnNavigation) {
   auto test_server_handle = embedded_test_server()->StartAndReturnHandle();
@@ -526,6 +512,13 @@
 }
 
 // Tests mouse lock is exited when navigating back.
+#if (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && defined(USE_AURA)
+// https://crbug.com/1192097
+#define MAYBE_TestTabExitsMouseLockOnGoBack \
+  DISABLED_TestTabExitsMouseLockOnGoBack
+#else
+#define MAYBE_TestTabExitsMouseLockOnGoBack TestTabExitsMouseLockOnGoBack
+#endif
 IN_PROC_BROWSER_TEST_F(FullscreenControllerInteractiveTest,
                        MAYBE_TestTabExitsMouseLockOnGoBack) {
   auto test_server_handle = embedded_test_server()->StartAndReturnHandle();
@@ -584,17 +577,8 @@
 }
 
 // Tests Mouse Lock and Fullscreen are exited upon reload.
-// http://crbug.com/137486
-// mac: http://crbug.com/103912
-#if defined(OS_WIN)
-#define MAYBE_ReloadExitsMouseLockAndFullscreen \
-  ReloadExitsMouseLockAndFullscreen
-#else
-#define MAYBE_ReloadExitsMouseLockAndFullscreen \
-  DISABLED_ReloadExitsMouseLockAndFullscreen
-#endif
 IN_PROC_BROWSER_TEST_F(FullscreenControllerInteractiveTest,
-                       MAYBE_ReloadExitsMouseLockAndFullscreen) {
+                       ReloadExitsMouseLockAndFullscreen) {
   auto test_server_handle = embedded_test_server()->StartAndReturnHandle();
   ASSERT_TRUE(test_server_handle);
   ui_test_utils::NavigateToURL(
diff --git a/chrome/browser/ui/passwords/bubble_controllers/save_update_with_account_store_bubble_controller.cc b/chrome/browser/ui/passwords/bubble_controllers/save_update_with_account_store_bubble_controller.cc
index 5403cea..cfceaa8a 100644
--- a/chrome/browser/ui/passwords/bubble_controllers/save_update_with_account_store_bubble_controller.cc
+++ b/chrome/browser/ui/passwords/bubble_controllers/save_update_with_account_store_bubble_controller.cc
@@ -20,7 +20,7 @@
 #include "components/password_manager/core/browser/password_form_metrics_recorder.h"
 #include "components/password_manager/core/browser/password_manager_features_util.h"
 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
-#include "components/password_manager/core/browser/password_store.h"
+#include "components/password_manager/core/browser/password_store_interface.h"
 #include "components/password_manager/core/common/password_manager_features.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
 #include "components/prefs/pref_service.h"
@@ -65,11 +65,14 @@
 
 void CleanStatisticsForSite(Profile* profile, const url::Origin& origin) {
   DCHECK(profile);
-  password_manager::PasswordStore* password_store =
+  password_manager::PasswordStoreInterface* password_store =
       PasswordStoreFactory::GetForProfile(profile,
                                           ServiceAccessType::IMPLICIT_ACCESS)
           .get();
-  password_store->RemoveSiteStats(origin.GetURL());
+  password_manager::SmartBubbleStatsStore* stats_store =
+      password_store->GetSmartBubbleStatsStore();
+  if (stats_store)
+    stats_store->RemoveSiteStats(origin.GetURL());
 }
 
 std::vector<password_manager::PasswordForm> DeepCopyForms(
@@ -328,11 +331,14 @@
                 interaction_stats_.dismissal_count)>::max())
           interaction_stats_.dismissal_count++;
         interaction_stats_.update_time = clock_->Now();
-        password_manager::PasswordStore* password_store =
+        password_manager::PasswordStoreInterface* password_store =
             PasswordStoreFactory::GetForProfile(
                 profile, ServiceAccessType::IMPLICIT_ACCESS)
                 .get();
-        password_store->AddSiteStats(interaction_stats_);
+        password_manager::SmartBubbleStatsStore* stats_store =
+            password_store->GetSmartBubbleStatsStore();
+        if (stats_store)
+          stats_store->AddSiteStats(interaction_stats_);
       }
     }
   }
diff --git a/chrome/browser/ui/views/dropdown_bar_host.cc b/chrome/browser/ui/views/dropdown_bar_host.cc
index 862d979d..4559046 100644
--- a/chrome/browser/ui/views/dropdown_bar_host.cc
+++ b/chrome/browser/ui/views/dropdown_bar_host.cc
@@ -133,6 +133,7 @@
 void DropdownBarHost::Hide(bool animate) {
   if (!IsVisible())
     return;
+
   if (animate && !disable_animations_during_testing_ &&
       !animation_->IsClosing()) {
     animation_->Hide();
@@ -201,6 +202,11 @@
 }
 
 void DropdownBarHost::AnimationEnded(const gfx::Animation* animation) {
+  // Ensure the position gets a final update.  This is important when ending the
+  // animation early (e.g. closing a tab with an open find bar), since otherwise
+  // the position will be out of date at the start of the next animation.
+  AnimationProgressed(animation);
+
   if (!animation_->IsShowing()) {
     // Animation has finished closing.
     host_->Hide();
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view.cc b/chrome/browser/ui/views/profiles/profile_menu_view.cc
index 6d8b13da..258d95c 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view.cc
+++ b/chrome/browser/ui/views/profiles/profile_menu_view.cc
@@ -180,30 +180,21 @@
   if (profile->IsOffTheRecord() || profile->IsGuestSession())
     return gfx::ImageSkia();
 
-  absl::optional<AvatarSyncErrorType> error = GetAvatarSyncErrorType(profile);
   bool is_sync_feature_enabled =
       IdentityManagerFactory::GetForProfile(profile)->HasPrimaryAccount(
           signin::ConsentLevel::kSync);
-  if (!error) {
-    // There's no error, so just show the sync on/off icon depending on whether
-    // sync-the-feature is enabled.
-    if (is_sync_feature_enabled) {
-      return ColoredImageForMenu(
-          kSyncCircleIcon, GetNativeTheme()->GetSystemColor(
-                               ui::NativeTheme::kColorId_AlertSeverityLow));
-    }
+  if (!is_sync_feature_enabled) {
+    // This is done regardless of GetAvatarSyncErrorType() because the icon
+    // should reflect that sync-the-feature is off. The error will still be
+    // highlighted by other parts of the UI.
     return ColoredImageForMenu(kSyncPausedCircleIcon, gfx::kGoogleGrey500);
   }
 
-  // There's an error. Usually a red sync-paused icon will be used, but some
-  // errors have special icons.
-  if ((error == AvatarSyncErrorType::kTrustedVaultKeyMissingForPasswordsError ||
-       error == AvatarSyncErrorType::
-                    kTrustedVaultRecoverabilityDegradedForPasswordsError) &&
-      !is_sync_feature_enabled) {
-    return ColoredImageForMenu(
-        kKeyCrossedIcon, GetNativeTheme()->GetSystemColor(
-                             ui::NativeTheme::kColorId_AlertSeverityHigh));
+  absl::optional<AvatarSyncErrorType> error = GetAvatarSyncErrorType(profile);
+  if (!error) {
+      return ColoredImageForMenu(
+          kSyncCircleIcon, GetNativeTheme()->GetSystemColor(
+                               ui::NativeTheme::kColorId_AlertSeverityLow));
   }
 
   ui::NativeTheme::ColorId color_id =
@@ -530,7 +521,7 @@
             : ui::NativeTheme::kColorId_SyncInfoContainerError,
         base::BindRepeating(&ProfileMenuView::OnSyncErrorButtonClicked,
                             base::Unretained(this), *error),
-        /*show_badge=*/true);
+        /*show_sync_badge=*/is_sync_feature_enabled);
     return;
   }
 
@@ -556,7 +547,7 @@
         ui::NativeTheme::kColorId_SyncInfoContainerNoPrimaryAccount,
         base::BindRepeating(&ProfileMenuView::OnSigninAccountButtonClicked,
                             base::Unretained(this), account_info),
-        /*show_badge=*/true);
+        /*show_sync_badge=*/true);
   } else {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
     // There is always an account on ChromeOS.
@@ -568,7 +559,7 @@
         ui::NativeTheme::kColorId_SyncInfoContainerNoPrimaryAccount,
         base::BindRepeating(&ProfileMenuView::OnSigninButtonClicked,
                             base::Unretained(this)),
-        /*show_badge=*/false);
+        /*show_sync_badge=*/false);
 #endif
   }
 }
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view_base.cc b/chrome/browser/ui/views/profiles/profile_menu_view_base.cc
index a2a02176..99fe8401 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view_base.cc
+++ b/chrome/browser/ui/views/profiles/profile_menu_view_base.cc
@@ -649,7 +649,7 @@
     const std::u16string& button_text,
     ui::NativeTheme::ColorId background_color_id,
     const base::RepeatingClosure& action,
-    bool show_badge) {
+    bool show_sync_badge) {
   const int kDescriptionIconSpacing =
       ChromeLayoutProvider::Get()->GetDistanceMetric(
           views::DISTANCE_RELATED_LABEL_HORIZONTAL);
@@ -687,7 +687,7 @@
            .SetDefault(views::kMarginsKey,
                        gfx::Insets(0, kDescriptionIconSpacing));
 
-  if (show_badge) {
+  if (show_sync_badge) {
     description_container->AddChildView(std::make_unique<SyncImageView>(this));
   } else {
     // If there is no image, the description is centered.
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view_base.h b/chrome/browser/ui/views/profiles/profile_menu_view_base.h
index cdb5579..55380425 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view_base.h
+++ b/chrome/browser/ui/views/profiles/profile_menu_view_base.h
@@ -126,7 +126,7 @@
       const std::u16string& button_text,
       ui::NativeTheme::ColorId background_color_id,
       const base::RepeatingClosure& action,
-      bool show_badge);
+      bool show_sync_badge);
   // Displays the sync info section as a rectangle with text. Clicking the
   // rectangle triggers |action|.
   void BuildSyncInfoWithoutCallToAction(const std::u16string& text,
diff --git a/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc
index cd4763a9..7682e7e 100644
--- a/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc
@@ -114,8 +114,12 @@
 void ArcTermsOfServiceScreenHandler::DeclareLocalizedValues(
     ::login::LocalizedValuesBuilder* builder) {
   builder->Add("arcTermsOfServiceScreenHeading", IDS_ARC_OOBE_TERMS_HEADING);
+  builder->Add("arcTermsOfServiceScreenHeadingForChild",
+               IDS_ARC_OOBE_TERMS_HEADING_CHILD);
   builder->Add("arcTermsOfServiceScreenDescription",
       IDS_ARC_OOBE_TERMS_DESCRIPTION);
+  builder->Add("arcTermsOfServiceScreenDescriptionForChild",
+               IDS_ARC_OOBE_TERMS_DESCRIPTION_CHILD);
   builder->Add("arcTermsOfServiceLoading", IDS_ARC_OOBE_TERMS_LOADING);
   builder->Add("arcTermsOfServiceErrorTitle", IDS_OOBE_GENERIC_FATAL_ERROR_TITLE);
   builder->Add("arcTermsOfServiceErrorMessage", IDS_ARC_OOBE_TERMS_LOAD_ERROR);
@@ -338,8 +342,8 @@
   action_taken_ = false;
 
   ShowScreen(kScreenId);
-
   arc_managed_ = arc::IsArcPlayStoreEnabledPreferenceManagedForProfile(profile);
+  is_child_account_ = user_manager::UserManager::Get()->IsLoggedInAsChildUser();
   CallJS("login.ArcTermsOfServiceScreen.setArcManaged", arc_managed_,
          is_child_account_);
 
diff --git a/chrome/browser/ui/webui/inspect_ui.cc b/chrome/browser/ui/webui/inspect_ui.cc
index c971958..e0de6f1 100644
--- a/chrome/browser/ui/webui/inspect_ui.cc
+++ b/chrome/browser/ui/webui/inspect_ui.cc
@@ -682,32 +682,30 @@
   Profile* profile = Profile::FromWebUI(web_ui());
   PrefService* prefs = profile->GetPrefs();
 
-  bool default_set;
-  if (!GetPrefValue(prefs::kDevToolsPortForwardingDefaultSet)->
-      GetAsBoolean(&default_set) || default_set) {
+  auto default_set =
+      GetPrefValue(prefs::kDevToolsPortForwardingDefaultSet)->GetIfBool();
+  if (!default_set || default_set.value())
     return;
-  }
 
   // This is the first chrome://inspect invocation on a fresh profile or after
   // upgrade from a version that did not have kDevToolsPortForwardingDefaultSet.
   prefs->SetBoolean(prefs::kDevToolsPortForwardingDefaultSet, true);
 
-  bool enabled;
+  auto enabled =
+      GetPrefValue(prefs::kDevToolsPortForwardingEnabled)->GetIfBool();
   const base::DictionaryValue* config;
-  if (!GetPrefValue(prefs::kDevToolsPortForwardingEnabled)->
-        GetAsBoolean(&enabled) ||
-      !GetPrefValue(prefs::kDevToolsPortForwardingConfig)->
-        GetAsDictionary(&config)) {
+  if (!enabled || !GetPrefValue(prefs::kDevToolsPortForwardingConfig)
+                       ->GetAsDictionary(&config)) {
     return;
   }
 
   // Do nothing if user already took explicit action.
-  if (enabled || !config->DictEmpty())
+  if (enabled.value() || !config->DictEmpty())
     return;
 
   base::DictionaryValue default_config;
-  default_config.SetString(kInspectUiPortForwardingDefaultPort,
-                           kInspectUiPortForwardingDefaultLocation);
+  default_config.SetStringPath(kInspectUiPortForwardingDefaultPort,
+                               kInspectUiPortForwardingDefaultLocation);
   prefs->Set(prefs::kDevToolsPortForwardingConfig, default_config);
 }
 
diff --git a/chrome/browser/ui/webui/signin/profile_picker_handler.cc b/chrome/browser/ui/webui/signin/profile_picker_handler.cc
index c80651527..d7c5343 100644
--- a/chrome/browser/ui/webui/signin/profile_picker_handler.cc
+++ b/chrome/browser/ui/webui/signin/profile_picker_handler.cc
@@ -12,6 +12,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/util/values/values_util.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_attributes_entry.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_avatar_icon_util.h"
@@ -171,22 +172,6 @@
   }
 }
 
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
-Profile* FindPrimaryProfile() {
-  const auto profiles =
-      g_browser_process->profile_manager()->GetLoadedProfiles();
-  const auto primary_profile_iter = std::find_if(
-      profiles.cbegin(), profiles.cend(),
-      [](const Profile* const profile) { return profile->IsMainProfile(); });
-
-  if (primary_profile_iter == profiles.cend()) {
-    return nullptr;
-  }
-
-  return *primary_profile_iter;
-}
-#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
-
 base::Value CreateProfileEntry(const ProfileAttributesEntry* entry,
                                int avatar_icon_size) {
   base::Value profile_entry(base::Value::Type::DICTIONARY);
@@ -208,10 +193,8 @@
   std::string icon_url = webui::GetBitmapDataUrl(icon.AsBitmap());
   profile_entry.SetStringKey("avatarIcon", icon_url);
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
-  Profile* primary_profile = FindPrimaryProfile();
-  profile_entry.SetBoolKey(
-      "isPrimaryLacrosProfile",
-      primary_profile && primary_profile->GetPath() == entry->GetPath());
+  profile_entry.SetBoolKey("isPrimaryLacrosProfile",
+                           Profile::IsMainProfilePath(entry->GetPath()));
 #else
   profile_entry.SetBoolKey("isPrimaryLacrosProfile", false);
 #endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
@@ -390,8 +373,7 @@
 
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
   if (!profiles::AreSecondaryProfilesAllowed()) {
-    Profile* primary_profile = FindPrimaryProfile();
-    if (primary_profile && primary_profile->GetPath() != *profile_path) {
+    if (Profile::IsMainProfilePath(*profile_path)) {
       LoginUIServiceFactory::GetForProfile(
           Profile::FromWebUI(web_ui())->GetOriginalProfile())
           ->SetProfileBlockingErrorMessage();
@@ -661,8 +643,7 @@
 
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
   // On Lacros, the primary profile should never be deleted.
-  Profile* primary_profile = FindPrimaryProfile();
-  CHECK(!primary_profile || primary_profile->GetPath() != *profile_path);
+  CHECK(!Profile::IsMainProfilePath(*profile_path));
 #endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
 
   RecordProfilePickerAction(ProfilePickerAction::kDeleteProfile);
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index b8d1a9e5..ba9ebea0 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -3221,10 +3221,10 @@
     "net.explicitly_allowed_network_ports";
 
 #if !defined(OS_ANDROID)
-// Pref name for whether force-installed web apps are able to query
+// Pref name for whether force-installed web apps (origins) are able to query
 // device attributes.
-const char kManagedWebAppsAccessToDeviceAttributesAllowed[] =
-    "policy.managed_web_apps_access_to_device_attributes_allowed";
+const char kDeviceAttributesAllowedForOrigins[] =
+    "policy.device_attributes_allowed_for_origins";
 #endif
 
 #if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 16f9027..813799a 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -1148,7 +1148,7 @@
 extern const char kExplicitlyAllowedNetworkPorts[];
 
 #if !defined(OS_ANDROID)
-extern const char kManagedWebAppsAccessToDeviceAttributesAllowed[];
+extern const char kDeviceAttributesAllowedForOrigins[];
 #endif
 
 #if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 49299a5a..1498a29b 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -4461,8 +4461,6 @@
     "../browser/profiles/incognito_mode_policy_handler_unittest.cc",
     "../browser/profiles/profile_attributes_storage_unittest.cc",
     "../browser/profiles/profile_downloader_unittest.cc",
-    "../browser/profiles/profile_info_cache_unittest.cc",
-    "../browser/profiles/profile_info_cache_unittest.h",
     "../browser/profiles/profile_manager_unittest.cc",
     "../browser/profiles/profiles_state_unittest.cc",
     "../browser/profiling_host/chrome_client_connection_manager_unittest.cc",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/batch/BlankCTATabInitialStateRule.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/batch/BlankCTATabInitialStateRule.java
index 87ea585..c9e4d1f1 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/batch/BlankCTATabInitialStateRule.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/batch/BlankCTATabInitialStateRule.java
@@ -11,9 +11,9 @@
 import org.chromium.base.test.util.Batch;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.firstrun.FirstRunStatus;
-import org.chromium.chrome.browser.incognito.IncognitoUtils;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabLaunchType;
+import org.chromium.chrome.browser.tabmodel.IncognitoTabHostUtils;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelUtils;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
@@ -95,7 +95,7 @@
     // quickly, at the cost of thoroughness. This should be adequate for most tests.
     private void resetTabStateFast() {
         TestThreadUtils.runOnUiThreadBlocking(() -> {
-            IncognitoUtils.closeAllIncognitoTabs();
+            IncognitoTabHostUtils.closeAllIncognitoTabs();
             // Close all but the first regular tab as these tests expect to start with a single
             // tab.
             TabModel regularTabModel =
@@ -117,7 +117,7 @@
             // tabs are closed.
             Tab newTab = sActivity.getTabCreator(false).launchUrl(
                     "about:blank", TabLaunchType.FROM_CHROME_UI);
-            IncognitoUtils.closeAllIncognitoTabs();
+            IncognitoTabHostUtils.closeAllIncognitoTabs();
 
             TabModel regularTabModel =
                     sActivity.getTabModelSelector().getModel(/*incognito=*/false);
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/AccountManagerTestRule.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/AccountManagerTestRule.java
index 8018d591..b60c787 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/AccountManagerTestRule.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/AccountManagerTestRule.java
@@ -106,12 +106,18 @@
     }
 
     /**
-     * Add an account to the fake AccountManagerFacade.
+     * Add an account to the fake AccountManagerFacade, if the {@link FakeAccountInfoService} is
+     * set up, add the corresponding {@link AccountInfo} to the {@link FakeAccountInfoService}.
      * @return The CoreAccountInfo for the account added.
      */
     public CoreAccountInfo addAccount(Account account) {
-        mFakeAccountManagerFacade.addAccount(account);
-        return toCoreAccountInfo(account.name);
+        if (mFakeAccountInfoService != null) {
+            return addAccount(
+                    account.name, /* fullName= */ "", /* givenName= */ "", /* avatar= */ null);
+        } else {
+            mFakeAccountManagerFacade.addAccount(account);
+            return toCoreAccountInfo(account.name);
+        }
     }
 
     /**
@@ -141,7 +147,9 @@
             String email, String fullName, String givenName, @Nullable Bitmap avatar) {
         assert mFakeAccountManagerFacade != null;
         mFakeAccountInfoService.addAccountInfo(email, fullName, givenName, avatar);
-        return addAccount(email);
+        final Account account = AccountUtils.createAccountFromName(email);
+        mFakeAccountManagerFacade.addAccount(account);
+        return toCoreAccountInfo(email);
     }
 
     /**
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index c2aa0e63..b6a542bb 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -4818,12 +4818,12 @@
     ]
   },
 
-  "ManagedWebAppsAccessToDeviceAttributesAllowed": {
+  "DeviceAttributesAllowedForOrigins": {
     "os": ["chromeos"],
     "policy_pref_mapping_tests": [
       {
-        "policies": { "ManagedWebAppsAccessToDeviceAttributesAllowed": true },
-        "prefs": { "policy.managed_web_apps_access_to_device_attributes_allowed": {} }
+        "policies": { "DeviceAttributesAllowedForOrigins": ["https://www.google.com"] },
+        "prefs": { "policy.device_attributes_allowed_for_origins": {"value" : ["https://www.google.com"] } }
       }
     ]
   },
diff --git a/chrome/test/data/webui/settings/chromeos/app_notifications_subpage_tests.js b/chrome/test/data/webui/settings/chromeos/app_notifications_subpage_tests.js
index ba7c770f..2a89b2f 100644
--- a/chrome/test/data/webui/settings/chromeos/app_notifications_subpage_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/app_notifications_subpage_tests.js
@@ -21,9 +21,12 @@
     flush();
   });
 
-  test('Page is loaded properly', function() {
+  test('Each app-notification-row displays correctly', function() {
     assertTrue(!!page);
     flush();
-    assertEquals('Notifications', page.$.testDiv.textContent.trim());
+    assertEquals(
+        'Chrome',
+        page.$.appNotificationsList.firstElementChild.$.appTitle.textContent
+            .trim());
   });
 });
\ No newline at end of file
diff --git a/chromecast/base/cast_features.cc b/chromecast/base/cast_features.cc
index 49382b4..da7d8c5c 100644
--- a/chromecast/base/cast_features.cc
+++ b/chromecast/base/cast_features.cc
@@ -213,7 +213,7 @@
                                           all_disable_features);
 
   // Override defaults from the DCS config.
-  for (const auto& kv : dcs_features.DictItems()) {
+  for (const auto kv : dcs_features.DictItems()) {
     // Each feature must have its own FieldTrial object. Since experiments are
     // controlled server-side for Chromecast, and this class is designed with a
     // client-side experimentation framework in mind, these parameters are
@@ -259,7 +259,7 @@
         // Build a map of the FieldTrial parameters and associate it to the
         // FieldTrial.
         base::FieldTrialParams params;
-        for (const auto& params_kv : kv.second.DictItems()) {
+        for (const auto params_kv : kv.second.DictItems()) {
           if (params_kv.second.is_string()) {
             params[params_kv.first] = params_kv.second.GetString();
           } else {
@@ -293,7 +293,7 @@
   base::Value persistent_dict(base::Value::Type::DICTIONARY);
 
   // |features| maps feature names to either a boolean or a dict of params.
-  for (const auto& feature : features.DictItems()) {
+  for (const auto feature : features.DictItems()) {
     if (feature.second.is_bool()) {
       persistent_dict.SetBoolKey(feature.first, feature.second.GetBool());
       continue;
diff --git a/chromecast/base/device_capabilities_impl.cc b/chromecast/base/device_capabilities_impl.cc
index 4aa23c7f..b1852f76 100644
--- a/chromecast/base/device_capabilities_impl.cc
+++ b/chromecast/base/device_capabilities_impl.cc
@@ -280,7 +280,7 @@
 
 void DeviceCapabilitiesImpl::MergeDictionary(const base::Value& dict_value) {
   DCHECK(dict_value.is_dict());
-  for (const auto& kv : dict_value.DictItems()) {
+  for (const auto kv : dict_value.DictItems()) {
     SetCapability(kv.first, kv.second.Clone());
   }
 }
diff --git a/chromecast/common/cast_redirect_manifest_handler.cc b/chromecast/common/cast_redirect_manifest_handler.cc
index 3525a3f..26698f7 100644
--- a/chromecast/common/cast_redirect_manifest_handler.cc
+++ b/chromecast/common/cast_redirect_manifest_handler.cc
@@ -33,7 +33,7 @@
   std::unique_ptr<Data> info(new Data);
   const base::DictionaryValue* dict;
   if (extension->manifest()->GetDictionary(kCastRedirect, &dict)) {
-    for (const auto& kv : dict->DictItems()) {
+    for (const auto kv : dict->DictItems()) {
       std::string path;
       if (kv.second.GetAsString(&path)) {
         info->redirects.emplace_back(kv.first, path);
diff --git a/chromecast/media/cma/backend/mixer/filter_group.cc b/chromecast/media/cma/backend/mixer/filter_group.cc
index 09c5f5be..b2931b861 100644
--- a/chromecast/media/cma/backend/mixer/filter_group.cc
+++ b/chromecast/media/cma/backend/mixer/filter_group.cc
@@ -131,7 +131,7 @@
   }
 
   float min, max;
-  for (const auto& item : volume_limits->DictItems()) {
+  for (const auto item : volume_limits->DictItems()) {
     if (ParseVolumeLimit(&item.second, &min, &max)) {
       AUDIO_LOG(INFO) << "Volume limits for device ID '" << item.first
                       << "' = [" << min << ", " << max << "]";
diff --git a/chromeos/components/sync_wifi/pending_network_configuration_tracker_impl.cc b/chromeos/components/sync_wifi/pending_network_configuration_tracker_impl.cc
index d64e253..93f2879 100644
--- a/chromeos/components/sync_wifi/pending_network_configuration_tracker_impl.cc
+++ b/chromeos/components/sync_wifi/pending_network_configuration_tracker_impl.cc
@@ -119,7 +119,7 @@
 std::vector<PendingNetworkConfigurationUpdate>
 PendingNetworkConfigurationTrackerImpl::GetPendingUpdates() {
   std::vector<PendingNetworkConfigurationUpdate> list;
-  for (const auto& entry : dict_.DictItems()) {
+  for (const auto entry : dict_.DictItems()) {
     list.push_back(ConvertToPendingUpdate(
         /*dict=*/&entry.second,
         NetworkIdentifier::DeserializeFromString(entry.first)));
diff --git a/chromeos/dbus/dbus_clients_browser.h b/chromeos/dbus/dbus_clients_browser.h
index e98902b..e9c5a2e 100644
--- a/chromeos/dbus/dbus_clients_browser.h
+++ b/chromeos/dbus/dbus_clients_browser.h
@@ -38,8 +38,10 @@
 class VirtualFileProviderClient;
 class VmPluginDispatcherClient;
 
-// D-Bus clients used only in the browser process.
-// TODO(jamescook): Move this under //chrome/browser. http://crbug.com/647367
+// Owns D-Bus clients.
+// TODO(jamescook): Rename this class. "Browser" refers to the browser process
+// versus ash process distinction from the mustash project, which was cancelled
+// in 2019.
 class COMPONENT_EXPORT(CHROMEOS_DBUS) DBusClientsBrowser {
  public:
   // Creates real implementations if |use_real_clients| is true and fakes
diff --git a/chromeos/dbus/dbus_thread_manager.cc b/chromeos/dbus/dbus_thread_manager.cc
index 8a44019..11133d9 100644
--- a/chromeos/dbus/dbus_thread_manager.cc
+++ b/chromeos/dbus/dbus_thread_manager.cc
@@ -44,11 +44,9 @@
 static DBusThreadManager* g_dbus_thread_manager = nullptr;
 static DBusThreadManagerSetter* g_setter = nullptr;
 
-DBusThreadManager::DBusThreadManager(ClientSet client_set) {
-  if (client_set == DBusThreadManager::kAll)
-    clients_browser_ = std::make_unique<DBusClientsBrowser>(use_real_clients_);
-  // NOTE: When there are clients only used by ash, create them here.
-}
+DBusThreadManager::DBusThreadManager()
+    : clients_browser_(
+          std::make_unique<DBusClientsBrowser>(use_real_clients_)) {}
 
 DBusThreadManager::~DBusThreadManager() {
   // Delete all D-Bus clients before shutting down the system bus.
@@ -210,15 +208,10 @@
 }
 
 // static
-void DBusThreadManager::Initialize(ClientSet client_set) {
-  CHECK(!g_dbus_thread_manager);
-  g_dbus_thread_manager = new DBusThreadManager(client_set);
-  g_dbus_thread_manager->InitializeClients();
-}
-
-// static
 void DBusThreadManager::Initialize() {
-  Initialize(kAll);
+  CHECK(!g_dbus_thread_manager);
+  g_dbus_thread_manager = new DBusThreadManager();
+  g_dbus_thread_manager->InitializeClients();
 }
 
 // static
diff --git a/chromeos/dbus/dbus_thread_manager.h b/chromeos/dbus/dbus_thread_manager.h
index cda37e9..28da8e0 100644
--- a/chromeos/dbus/dbus_thread_manager.h
+++ b/chromeos/dbus/dbus_thread_manager.h
@@ -54,26 +54,11 @@
 class COMPONENT_EXPORT(CHROMEOS_DBUS) DBusThreadManager
     : public DBusThreadManagerBase {
  public:
-  // Processes for which to create and initialize the D-Bus clients.
-  // TODO(jamescook): Move creation of clients into //ash and //chrome/browser.
-  // http://crbug.com/647367
-  enum ClientSet {
-    // Common clients needed by both ash and the browser.
-    kShared,
-
-    // Includes the client in |kShared| as well as the clients used only by
-    // the browser (and not ash).
-    kAll
-  };
   // Sets the global instance. Must be called before any calls to Get().
   // We explicitly initialize and shut down the global object, rather than
   // making it a Singleton, to ensure clean startup and shutdown.
   // This will initialize real or fake DBusClients depending on command-line
   // arguments and whether this process runs in a ChromeOS environment.
-  // Only D-Bus clients specified in |client_set| will be created.
-  static void Initialize(ClientSet client_set);
-
-  // Equivalent to Initialize(kAll).
   static void Initialize();
 
   // Returns a DBusThreadManagerSetter instance that allows tests to replace
@@ -131,8 +116,7 @@
   ShillThirdPartyVpnDriverClient* GetShillThirdPartyVpnDriverClient();
 
  private:
-  // Creates dbus clients based on |client_set|.
-  explicit DBusThreadManager(ClientSet client_set);
+  DBusThreadManager();
   DBusThreadManager(const DBusThreadManager&) = delete;
   const DBusThreadManager& operator=(const DBusThreadManager&) = delete;
   ~DBusThreadManager() override;
@@ -141,7 +125,7 @@
   // performs additional setup.
   void InitializeClients();
 
-  // Clients used only by the browser process. Null in other processes.
+  // Owns the clients.
   std::unique_ptr<DBusClientsBrowser> clients_browser_;
 };
 
diff --git a/chromeos/dbus/dbus_thread_manager_unittest.cc b/chromeos/dbus/dbus_thread_manager_unittest.cc
index 01ba809..12f30cf 100644
--- a/chromeos/dbus/dbus_thread_manager_unittest.cc
+++ b/chromeos/dbus/dbus_thread_manager_unittest.cc
@@ -42,64 +42,4 @@
   EXPECT_FALSE(DBusThreadManager::IsInitialized());
 }
 
-// Tests that clients can be created for the browser process.
-TEST(DBusThreadManagerTest, InitializeForBrowser) {
-  DBusThreadManager::Initialize(DBusThreadManager::kAll);
-  DBusThreadManager* manager = DBusThreadManager::Get();
-  ASSERT_TRUE(manager);
-
-  // Common clients were created.
-  EXPECT_TRUE(manager->GetModemMessagingClient());
-  EXPECT_TRUE(manager->GetShillDeviceClient());
-  EXPECT_TRUE(manager->GetShillIPConfigClient());
-  EXPECT_TRUE(manager->GetShillManagerClient());
-  EXPECT_TRUE(manager->GetShillProfileClient());
-  EXPECT_TRUE(manager->GetShillServiceClient());
-  EXPECT_TRUE(manager->GetShillThirdPartyVpnDriverClient());
-  EXPECT_TRUE(manager->GetSMSClient());
-  EXPECT_TRUE(manager->GetUpdateEngineClient());
-
-  // Clients for the browser were created.
-  EXPECT_TRUE(manager->GetAnomalyDetectorClient());
-  EXPECT_TRUE(manager->GetArcMidisClient());
-  EXPECT_TRUE(manager->GetArcObbMounterClient());
-  EXPECT_TRUE(manager->GetCrosDisksClient());
-  EXPECT_TRUE(manager->GetDebugDaemonClient());
-  EXPECT_TRUE(manager->GetEasyUnlockClient());
-  EXPECT_TRUE(manager->GetImageBurnerClient());
-  EXPECT_TRUE(manager->GetLorgnetteManagerClient());
-
-  DBusThreadManager::Shutdown();
-}
-
-// Tests that clients can be created for the ash process.
-TEST(DBusThreadManagerTest, InitializeForAsh) {
-  DBusThreadManager::Initialize(DBusThreadManager::kShared);
-  DBusThreadManager* manager = DBusThreadManager::Get();
-  ASSERT_TRUE(manager);
-
-  // Common clients were created.
-  EXPECT_TRUE(manager->GetModemMessagingClient());
-  EXPECT_TRUE(manager->GetShillDeviceClient());
-  EXPECT_TRUE(manager->GetShillIPConfigClient());
-  EXPECT_TRUE(manager->GetShillManagerClient());
-  EXPECT_TRUE(manager->GetShillProfileClient());
-  EXPECT_TRUE(manager->GetShillServiceClient());
-  EXPECT_TRUE(manager->GetShillThirdPartyVpnDriverClient());
-  EXPECT_TRUE(manager->GetSMSClient());
-
-  // Clients for other processes were not created.
-  EXPECT_FALSE(manager->GetAnomalyDetectorClient());
-  EXPECT_FALSE(manager->GetArcMidisClient());
-  EXPECT_FALSE(manager->GetArcObbMounterClient());
-  EXPECT_FALSE(manager->GetCrosDisksClient());
-  EXPECT_FALSE(manager->GetDebugDaemonClient());
-  EXPECT_FALSE(manager->GetEasyUnlockClient());
-  EXPECT_FALSE(manager->GetImageBurnerClient());
-  EXPECT_FALSE(manager->GetLorgnetteManagerClient());
-  EXPECT_FALSE(manager->GetUpdateEngineClient());
-
-  DBusThreadManager::Shutdown();
-}
-
 }  // namespace chromeos
diff --git a/chromeos/dbus/debug_daemon/debug_daemon_client.cc b/chromeos/dbus/debug_daemon/debug_daemon_client.cc
index d56f7522..f97448e 100644
--- a/chromeos/dbus/debug_daemon/debug_daemon_client.cc
+++ b/chromeos/dbus/debug_daemon/debug_daemon_client.cc
@@ -88,7 +88,7 @@
     }
 
     std::map<std::string, std::string> data;
-    for (const auto& entry : logs->DictItems())
+    for (const auto entry : logs->DictItems())
       data[entry.first] = entry.second.GetString();
     RunCallbackAndDestroy(std::move(data));
   }
diff --git a/chromeos/dbus/shill/fake_shill_profile_client.cc b/chromeos/dbus/shill/fake_shill_profile_client.cc
index 2597ece..5e329f88 100644
--- a/chromeos/dbus/shill/fake_shill_profile_client.cc
+++ b/chromeos/dbus/shill/fake_shill_profile_client.cc
@@ -56,7 +56,7 @@
   }
 
   base::Value entry_paths(base::Value::Type::LIST);
-  for (const auto& it : profile->entries.DictItems()) {
+  for (const auto it : profile->entries.DictItems()) {
     entry_paths.Append(it.first);
   }
 
diff --git a/chromeos/dbus/shill/fake_shill_service_client.cc b/chromeos/dbus/shill/fake_shill_service_client.cc
index f4f77371..4788ed5 100644
--- a/chromeos/dbus/shill/fake_shill_service_client.cc
+++ b/chromeos/dbus/shill/fake_shill_service_client.cc
@@ -613,7 +613,7 @@
 
 std::string FakeShillServiceClient::FindServiceMatchingGUID(
     const std::string& guid) {
-  for (const auto& service_pair : stub_services_.DictItems()) {
+  for (const auto service_pair : stub_services_.DictItems()) {
     const auto& service_path = service_pair.first;
     const auto& service_properties = service_pair.second;
 
@@ -633,7 +633,7 @@
   if (!template_type)
     return std::string();
 
-  for (const auto& service_pair : stub_services_.DictItems()) {
+  for (const auto service_pair : stub_services_.DictItems()) {
     const auto& service_path = service_pair.first;
     const auto& service_properties = service_pair.second;
 
diff --git a/chromeos/metrics/login_event_recorder.h b/chromeos/metrics/login_event_recorder.h
index 81a91f6..625eeff9 100644
--- a/chromeos/metrics/login_event_recorder.h
+++ b/chromeos/metrics/login_event_recorder.h
@@ -10,6 +10,7 @@
 #include "base/callback.h"
 #include "base/component_export.h"
 #include "base/memory/ref_counted.h"
+#include "base/time/time.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace base {
diff --git a/chromeos/network/network_configuration_handler.cc b/chromeos/network/network_configuration_handler.cc
index a02dec7d..3af9cb07 100644
--- a/chromeos/network/network_configuration_handler.cc
+++ b/chromeos/network/network_configuration_handler.cc
@@ -142,7 +142,7 @@
       return;
     }
 
-    for (const auto& iter : profile_entries->DictItems()) {
+    for (const auto iter : profile_entries->DictItems()) {
       std::string profile_path = StripQuotations(iter.first);
       std::string entry_path;
       if (iter.second.is_string()) {
diff --git a/chromeos/network/onc/onc_translator_onc_to_shill.cc b/chromeos/network/onc/onc_translator_onc_to_shill.cc
index db8ed30..b79c83a 100644
--- a/chromeos/network/onc/onc_translator_onc_to_shill.cc
+++ b/chromeos/network/onc/onc_translator_onc_to_shill.cc
@@ -231,7 +231,7 @@
 
   // Modified CopyFieldsAccordingToSignature to handle RemoteCertKU and
   // ServerCAPEMs and handle all other fields as strings.
-  for (const auto& it : onc_object_->DictItems()) {
+  for (const auto it : onc_object_->DictItems()) {
     std::string key = it.first;
     base::Value translated;
     if (key == ::onc::openvpn::kRemoteCertKU ||
@@ -448,7 +448,7 @@
 }
 
 void LocalTranslator::CopyFieldsAccordingToSignature() {
-  for (const auto& it : onc_object_->DictItems()) {
+  for (const auto it : onc_object_->DictItems()) {
     AddValueAccordingToSignature(it.first, it.second);
   }
 }
@@ -529,7 +529,7 @@
   translator.TranslateFields();
 
   // Recurse into nested objects.
-  for (const auto& it : onc_object.DictItems()) {
+  for (const auto it : onc_object.DictItems()) {
     if (!it.second.is_dict())
       continue;
 
diff --git a/chromeos/network/onc/variable_expander.cc b/chromeos/network/onc/variable_expander.cc
index 63d7ea3..0e8ee1e 100644
--- a/chromeos/network/onc/variable_expander.cc
+++ b/chromeos/network/onc/variable_expander.cc
@@ -128,7 +128,7 @@
     }
 
     case base::Value::Type::DICTIONARY: {
-      for (const auto& child : value->DictItems())
+      for (const auto child : value->DictItems())
         no_error &= ExpandValue(&child.second);
       break;
     }
diff --git a/chromeos/network/shill_property_handler.cc b/chromeos/network/shill_property_handler.cc
index 918298ac..843b456 100644
--- a/chromeos/network/shill_property_handler.cc
+++ b/chromeos/network/shill_property_handler.cc
@@ -345,7 +345,7 @@
     return;
   }
   NET_LOG(EVENT) << "ManagerPropertiesCallback: Success";
-  for (const auto& item : properties->DictItems()) {
+  for (const auto item : properties->DictItems()) {
     ManagerPropertyChanged(item.first, item.second);
   }
 
diff --git a/chromeos/printing/ppd_metadata_parser.cc b/chromeos/printing/ppd_metadata_parser.cc
index aab9504..2846d64 100644
--- a/chromeos/printing/ppd_metadata_parser.cc
+++ b/chromeos/printing/ppd_metadata_parser.cc
@@ -210,7 +210,7 @@
     return absl::nullopt;
   }
   ParsedManufacturers manufacturers;
-  for (const auto& iter : as_value.value().DictItems()) {
+  for (const auto iter : as_value.value().DictItems()) {
     std::string printers_metadata_basename;
     if (!iter.second.GetAsString(&printers_metadata_basename)) {
       continue;
@@ -236,7 +236,7 @@
 
   // Secondly, we iterate on the key-value pairs of the ppdIndex.
   // This yields a list of leaf values (dictionaries).
-  for (const auto& kv : ppd_index->DictItems()) {
+  for (const auto kv : ppd_index->DictItems()) {
     absl::optional<ParsedIndexValues> values = UnnestPpdMetadata(kv.second);
     if (values.has_value()) {
       parsed_index.insert_or_assign(kv.first, values.value());
@@ -257,7 +257,7 @@
   }
 
   ParsedUsbIndex parsed_usb_index;
-  for (const auto& kv : usb_index->DictItems()) {
+  for (const auto kv : usb_index->DictItems()) {
     int product_id;
     if (!base::StringToInt(kv.first, &product_id)) {
       continue;
@@ -341,7 +341,7 @@
   }
 
   ParsedReverseIndex parsed;
-  for (const auto& kv : makes_and_models->DictItems()) {
+  for (const auto kv : makes_and_models->DictItems()) {
     if (!kv.second.is_dict()) {
       continue;
     }
diff --git a/chromeos/services/device_sync/cryptauth_device.cc b/chromeos/services/device_sync/cryptauth_device.cc
index 3acc245..33c51c7 100644
--- a/chromeos/services/device_sync/cryptauth_device.cc
+++ b/chromeos/services/device_sync/cryptauth_device.cc
@@ -37,7 +37,7 @@
 
   std::map<multidevice::SoftwareFeature, multidevice::SoftwareFeatureState>
       feature_states;
-  for (const auto& feature_state_pair : dict->DictItems()) {
+  for (const auto feature_state_pair : dict->DictItems()) {
     int feature;
     if (!base::StringToInt(feature_state_pair.first, &feature) ||
         !feature_state_pair.second.is_int()) {
diff --git a/chromeos/services/device_sync/cryptauth_device_manager_impl.cc b/chromeos/services/device_sync/cryptauth_device_manager_impl.cc
index 0b4a32c..1239b09c 100644
--- a/chromeos/services/device_sync/cryptauth_device_manager_impl.cc
+++ b/chromeos/services/device_sync/cryptauth_device_manager_impl.cc
@@ -348,7 +348,7 @@
     cryptauth::ExternalDeviceInfo* external_device,
     bool old_unlock_key_value_from_prefs,
     bool old_mobile_hotspot_supported_from_prefs) {
-  for (const auto& it : software_features_dictionary.DictItems()) {
+  for (const auto it : software_features_dictionary.DictItems()) {
     std::string software_feature = it.first;
     if (SoftwareFeatureStringToEnum(software_feature) ==
         cryptauth::SoftwareFeature::UNKNOWN_FEATURE) {
diff --git a/chromeos/services/device_sync/cryptauth_device_manager_impl_unittest.cc b/chromeos/services/device_sync/cryptauth_device_manager_impl_unittest.cc
index 96d3a811..3bdb9d1 100644
--- a/chromeos/services/device_sync/cryptauth_device_manager_impl_unittest.cc
+++ b/chromeos/services/device_sync/cryptauth_device_manager_impl_unittest.cc
@@ -341,7 +341,7 @@
       std::vector<cryptauth::SoftwareFeature> supported_software_features;
       std::vector<cryptauth::SoftwareFeature> enabled_software_features;
 
-      for (const auto& it : software_features_from_prefs->DictItems()) {
+      for (const auto it : software_features_from_prefs->DictItems()) {
         ASSERT_TRUE(it.second.is_int());
 
         cryptauth::SoftwareFeature software_feature =
diff --git a/chromeos/services/device_sync/cryptauth_device_registry_impl.cc b/chromeos/services/device_sync/cryptauth_device_registry_impl.cc
index 6a3c81a..a1c4b2315 100644
--- a/chromeos/services/device_sync/cryptauth_device_registry_impl.cc
+++ b/chromeos/services/device_sync/cryptauth_device_registry_impl.cc
@@ -52,8 +52,7 @@
   const base::Value* dict = pref_service_->Get(prefs::kCryptAuthDeviceRegistry);
 
   CryptAuthDeviceRegistry::InstanceIdToDeviceMap instance_id_to_device_map;
-  for (const std::pair<const std::string&, const base::Value&>& id_device_pair :
-       dict->DictItems()) {
+  for (const auto id_device_pair : dict->DictItems()) {
     absl::optional<std::string> instance_id =
         util::DecodeFromString(id_device_pair.first);
     absl::optional<CryptAuthDevice> device =
diff --git a/components/autofill/ios/browser/suggestion_controller_java_script_feature.mm b/components/autofill/ios/browser/suggestion_controller_java_script_feature.mm
index eadf5e4..eae6c553 100644
--- a/components/autofill/ios/browser/suggestion_controller_java_script_feature.mm
+++ b/components/autofill/ios/browser/suggestion_controller_java_script_feature.mm
@@ -8,6 +8,7 @@
 
 #include "base/bind.h"
 #include "base/strings/sys_string_conversions.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #import "components/autofill/ios/browser/autofill_java_script_feature.h"
 
diff --git a/components/autofill_assistant/browser/dom_action.proto b/components/autofill_assistant/browser/dom_action.proto
index 6520f36..120accf 100644
--- a/components/autofill_assistant/browser/dom_action.proto
+++ b/components/autofill_assistant/browser/dom_action.proto
@@ -158,7 +158,7 @@
 // combination with |SendChangeEventProto|. If the element in |option| is
 // not an option of the element in |select|, an |OPTION_VALUE_NOT_FOUND| error
 // is returned. If the element in |select| is not an HTML <select> element, an
-// |OPTION_VALUE_NOT_FOUND| error is returned.
+// |INVALID_TARGET| error is returned.
 message SelectOptionElementProto {
   optional ClientIdProto select_id = 1;
   optional ClientIdProto option_id = 2;
@@ -172,7 +172,7 @@
   repeated string any_of_tag = 2;
 }
 
-// Check whether the element in |option_d| is selected in the element in
+// Check whether the element in |option_id| is selected in the element in
 // |select_id|.
 message CheckOptionElementProto {
   optional ClientIdProto select_id = 1;
diff --git a/components/autofill_assistant/browser/service.proto b/components/autofill_assistant/browser/service.proto
index ebbaf25..7252b97 100644
--- a/components/autofill_assistant/browser/service.proto
+++ b/components/autofill_assistant/browser/service.proto
@@ -1396,8 +1396,8 @@
 // Contain all arguments to perform a select option action. This action also
 // fires a "change" event on the element. If the option is not found, an
 // |OPTION_VALUE_NOT_FOUND| error is returned. If the action is used on an
-// element that is not an HTML <select> element, an |OPTION_VALUE_NOT_FOUND|
-// error is returned.
+// element that is not an HTML <select> element, an |INVALID_TARGET| error is
+// returned.
 message SelectOptionProto {
   // The drop down element on which to select an option.
   optional SelectorProto element = 2;
diff --git a/components/browser_ui/styles/android/java/res/values-night/styles.xml b/components/browser_ui/styles/android/java/res/values-night/styles.xml
index cd3d8a6..9f6b8314c 100644
--- a/components/browser_ui/styles/android/java/res/values-night/styles.xml
+++ b/components/browser_ui/styles/android/java/res/values-night/styles.xml
@@ -6,25 +6,27 @@
 <resources xmlns:tools="http://schemas.android.com/tools">
     <style name="Base.ColorOverlay" parent="">
         <!-- Attributes that point to the same color/attr in dark and light modes. -->
+        <item name="colorOnPrimaryContainer">@color/baseline_primary_900</item>
         <item name="colorPrimaryContainer">@color/baseline_primary_100</item>
         <item name="android:textColorPrimary">?attr/colorOnBackground</item>
         <item name="android:textColorSecondary">?attr/colorOnSurfaceVariant</item>
 
         <!-- Adaptive attributes -->
-        <item name="colorPrimary">@color/modern_blue_300</item>
-        <item name="colorError">@color/google_red_300</item>
-        <item name="android:colorBackground">@color/modern_grey_900</item>
-        <item name="colorSurface">@color/modern_grey_900</item>
-        <item name="colorOnBackground">@color/modern_white</item>
-        <item name="colorOnPrimary">@color/modern_blue_800</item>
-        <item name="colorOnPrimaryContainer">@color/baseline_primary_900</item>
-        <item name="colorOnSurface">@color/modern_grey_100</item>
-        <item name="colorOnSurfaceVariant">@color/white_alpha_70</item>
-        <item name="colorOnSurfaceInverse">@color/modern_grey_800</item>
-        <item name="elevationOverlayEnabled">true</item>
-        <item name="elevationOverlayColor">@color/modern_grey_200</item>
-        <item name="elevationOverlayAccentColor">?attr/colorPrimary</item>
+        <item name="android:colorBackground">@color/baseline_neutral_900</item>
+        <item name="colorError">@color/baseline_error_200</item>
+        <item name="colorOnBackground">@color/baseline_neutral_100</item>
+        <item name="colorOnPrimary">@color/baseline_primary_800</item>
+        <item name="colorOnSurface">@color/baseline_neutral_100</item>
+        <item name="colorOnSurfaceInverse">@color/baseline_neutral_800</item>
+        <item name="colorOnSurfaceVariant">@color/baseline_neutral_variant_200</item>
         <item name="colorOutline">@color/baseline_neutral_variant_400</item>
+        <item name="colorPrimary">@color/baseline_primary_200</item>
+        <item name="colorSurface">@color/baseline_neutral_900</item>
+        <item name="colorSurfaceVariant">@color/baseline_neutral_variant_700</item>
+
+        <item name="elevationOverlayAccentColor">?attr/colorPrimary</item>
+        <item name="elevationOverlayColor">@color/baseline_neutral_200</item>
+        <item name="elevationOverlayEnabled">true</item>
 
         <item name="colorSwitchThumbNormal">?attr/colorOnSurface</item>
         <item name="colorSwitchThumbDisabled">?attr/colorFixedOnSurfaceAlpha38OverSurface</item>
diff --git a/components/browser_ui/styles/android/java/res/values/styles.xml b/components/browser_ui/styles/android/java/res/values/styles.xml
index 6679658a..31305c87 100644
--- a/components/browser_ui/styles/android/java/res/values/styles.xml
+++ b/components/browser_ui/styles/android/java/res/values/styles.xml
@@ -190,25 +190,28 @@
 
     <style name="Base.ColorOverlay" parent="">
         <!-- Attributes that point to the same color/attr in dark and light modes. -->
+        <item name="colorOnPrimaryContainer">@color/baseline_primary_900</item>
         <item name="colorPrimaryContainer">@color/baseline_primary_100</item>
         <item name="android:textColorPrimary">?attr/colorOnBackground</item>
         <item name="android:textColorSecondary">?attr/colorOnSurfaceVariant</item>
 
+
         <!-- Adaptive attributes -->
-        <item name="colorPrimary">@color/modern_blue_600</item>
-        <item name="colorError">@color/google_red_600</item>
-        <item name="android:colorBackground">@color/modern_white</item>
-        <item name="colorSurface">@color/modern_white</item>
+        <item name="android:colorBackground">@color/baseline_neutral_0</item>
+        <item name="colorError">@color/baseline_error_600</item>
+        <item name="colorOnBackground">@color/baseline_neutral_900</item>
+        <item name="colorOnPrimary">@color/baseline_primary_0</item>
+        <item name="colorOnSurface">@color/baseline_neutral_900</item>
+        <item name="colorOnSurfaceInverse">@color/baseline_neutral_50</item>
+        <item name="colorOnSurfaceVariant">@color/baseline_neutral_variant_700</item>
+        <item name="colorOutline">@color/baseline_neutral_variant_500</item>
+        <item name="colorPrimary">@color/baseline_primary_600</item>
+        <item name="colorSurface">@color/baseline_neutral_0</item>
         <item name="colorSurfaceVariant">@color/baseline_neutral_variant_100</item>
-        <item name="colorOnBackground">@color/modern_grey_900</item>
-        <item name="colorOnPrimary">@color/modern_white</item>
-        <item name="colorOnPrimaryContainer">@color/baseline_primary_900</item>
-        <item name="colorOnSurface">@color/modern_grey_900</item>
-        <item name="colorOnSurfaceVariant">@color/modern_grey_700</item>
-        <item name="colorOnSurfaceInverse">@color/modern_white</item>
-        <item name="elevationOverlayEnabled">true</item>
-        <item name="elevationOverlayColor">@color/modern_grey_600</item>
+
         <item name="elevationOverlayAccentColor">?attr/colorPrimary</item>
+        <item name="elevationOverlayColor">@color/baseline_neutral_600</item>
+        <item name="elevationOverlayEnabled">true</item>
 
         <item name="colorSwitchThumbNormal">?attr/colorSurface</item>
         <item name="colorSwitchThumbDisabled">?attr/colorSurface</item>
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamQuicTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamQuicTest.java
index 5e640ea..4d41c31 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamQuicTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamQuicTest.java
@@ -389,10 +389,11 @@
         callback.blockForDone();
         assertTrue(stream.isDone());
         assertNotNull(callback.mError);
-        assertTrue(callback.mError instanceof QuicException);
-        QuicException quicException = (QuicException) callback.mError;
-        // Checks that detailed quic error code is not QUIC_NO_ERROR == 0.
-        assertTrue("actual error " + quicException.getQuicDetailedErrorCode(),
-                0 < quicException.getQuicDetailedErrorCode());
+        if (callback.mError instanceof QuicException) {
+            QuicException quicException = (QuicException) callback.mError;
+            // Checks that detailed quic error code is not QUIC_NO_ERROR == 0.
+            assertTrue("actual error " + quicException.getQuicDetailedErrorCode(),
+                    0 < quicException.getQuicDetailedErrorCode());
+        }
     }
 }
diff --git a/components/cronet/ios/test/cronet_prefs_test.mm b/components/cronet/ios/test/cronet_prefs_test.mm
index 9b81c8b2..107b83cc 100644
--- a/components/cronet/ios/test/cronet_prefs_test.mm
+++ b/components/cronet/ios/test/cronet_prefs_test.mm
@@ -116,11 +116,11 @@
   ASSERT_TRUE(prefs_file_content);
   ASSERT_TRUE(
       [prefs_file_content containsString:@"{\"http_server_properties\":"])
-      << "Unable to find 'http_server_properties' in the JSON prefs.";
+      << "Unable to find 'http_server_properties' in the JSON prefs: "
+      << prefs_file_content.UTF8String;
   ASSERT_TRUE([prefs_file_content containsString:@"\"supports_quic\":"])
-      << "Unable to find 'supports_quic' in the JSON prefs.";
-  ASSERT_TRUE([prefs_file_content containsString:@"\"server_info\":"])
-      << "Unable to find 'server_info' in the JSON prefs.";
+      << "Unable to find 'supports_quic' in the JSON prefs: "
+      << prefs_file_content.UTF8String;
 
   // Delete the prefs file to avoid side effects with other tests.
   [[NSFileManager defaultManager] removeItemAtPath:prefs_file_name error:nil];
diff --git a/components/download/internal/background_service/ios/background_download_service_impl.cc b/components/download/internal/background_service/ios/background_download_service_impl.cc
index 5fd2af2b..1d43967 100644
--- a/components/download/internal/background_service/ios/background_download_service_impl.cc
+++ b/components/download/internal/background_service/ios/background_download_service_impl.cc
@@ -118,7 +118,16 @@
 
 void BackgroundDownloadServiceImpl::OnModelReady(bool success) {
   init_success_ = success;
-  // TODO(xingliu): Ping clients for service status.
+  if (!success) {
+    for (const auto& client_it : *clients_.get())
+
+      client_it.second->OnServiceUnavailable();
+    return;
+  }
+
+  // TODO(xingliu): Create list of metadata and call OnServiceInitialized().
+  for (const auto& client_it : *clients_.get())
+    client_it.second->OnServiceUnavailable();
 }
 
 void BackgroundDownloadServiceImpl::OnModelHardRecoverComplete(bool success) {}
@@ -141,7 +150,10 @@
                       std::move(callback));
   download_helper_->StartDownload(
       entry->guid, entry->request_params, entry->scheduling_params,
-      base::BindRepeating(&BackgroundDownloadServiceImpl::OnDownloadFinished,
+      base::BindOnce(&BackgroundDownloadServiceImpl::OnDownloadFinished,
+                     weak_ptr_factory_.GetWeakPtr(), entry->client,
+                     entry->guid),
+      base::BindRepeating(&BackgroundDownloadServiceImpl::OnDownloadUpdated,
                           weak_ptr_factory_.GetWeakPtr(), entry->client,
                           entry->guid));
 }
@@ -178,4 +190,16 @@
   client->OnDownloadSucceeded(guid, completion_info);
 }
 
-}  // namespace download
\ No newline at end of file
+void BackgroundDownloadServiceImpl::OnDownloadUpdated(
+    DownloadClient download_client,
+    const std::string& guid,
+    int64_t bytes_downloaded) {
+  auto it = clients_->find(download_client);
+  if (it == clients_->end())
+    return;
+  download::Client* client = it->second.get();
+  client->OnDownloadUpdated(guid, /*bytes_uploaded*/ 0u,
+                            static_cast<uint64_t>(bytes_downloaded));
+}
+
+}  // namespace download
diff --git a/components/download/internal/background_service/ios/background_download_service_impl.h b/components/download/internal/background_service/ios/background_download_service_impl.h
index 8bff3095..07497e6 100644
--- a/components/download/internal/background_service/ios/background_download_service_impl.h
+++ b/components/download/internal/background_service/ios/background_download_service_impl.h
@@ -66,6 +66,10 @@
                           bool success,
                           const base::FilePath& file_path);
 
+  void OnDownloadUpdated(DownloadClient download_client,
+                         const std::string& guid,
+                         int64_t bytes_downloaded);
+
   std::unique_ptr<Configuration> config_;
   ServiceConfigImpl service_config_;
   // TODO(xingliu): Ping clients for all events.
diff --git a/components/download/internal/background_service/ios/background_download_service_impl_unittest.cc b/components/download/internal/background_service/ios/background_download_service_impl_unittest.cc
index 83a1b38..5c28b33 100644
--- a/components/download/internal/background_service/ios/background_download_service_impl_unittest.cc
+++ b/components/download/internal/background_service/ios/background_download_service_impl_unittest.cc
@@ -17,6 +17,7 @@
 #include "testing/platform_test.h"
 
 using ::base::test::RunCallback;
+using ::base::test::RunOnceCallback;
 using ::testing::_;
 using ::testing::NiceMock;
 using ServiceStatus = download::BackgroundDownloadService::ServiceStatus;
@@ -43,7 +44,8 @@
               (const std::string& guid,
                const RequestParams&,
                const SchedulingParams&,
-               CompletionCallback),
+               CompletionCallback,
+               UpdateCallback),
               (override));
 };
 
@@ -98,6 +100,7 @@
 
 TEST_F(BackgroundDownloadServiceImplTest, InitFailure) {
   EXPECT_EQ(ServiceStatus::STARTING_UP, service()->GetStatus());
+  EXPECT_CALL(*client_, OnServiceUnavailable());
   store_->TriggerInit(/*success=*/false, empty_entries());
   EXPECT_EQ(ServiceStatus::UNAVAILABLE, service()->GetStatus());
 }
@@ -115,8 +118,8 @@
 TEST_F(BackgroundDownloadServiceImplTest, StartDownloadHelperFailure) {
   store_->TriggerInit(/*success=*/true, empty_entries());
   EXPECT_CALL(start_callback_, Run(kGuid, StartResult::ACCEPTED));
-  EXPECT_CALL(*download_helper_, StartDownload(_, _, _, _))
-      .WillOnce(RunCallback<3>(/*success=*/false, base::FilePath()));
+  EXPECT_CALL(*download_helper_, StartDownload(_, _, _, _, _))
+      .WillOnce(RunOnceCallback<3>(/*success=*/false, base::FilePath()));
   EXPECT_CALL(*client_,
               OnDownloadFailed(kGuid, CompletionInfoIs(base::FilePath()),
                                download::Client::FailureReason::UNKNOWN));
@@ -130,8 +133,9 @@
 TEST_F(BackgroundDownloadServiceImplTest, StartDownloadSuccess) {
   store_->TriggerInit(/*success=*/true, empty_entries());
   EXPECT_CALL(start_callback_, Run(kGuid, StartResult::ACCEPTED));
-  EXPECT_CALL(*download_helper_, StartDownload(_, _, _, _))
-      .WillOnce(RunCallback<3>(/*success=*/true, base::FilePath(kFilePath)));
+  EXPECT_CALL(*download_helper_, StartDownload(_, _, _, _, _))
+      .WillOnce(
+          RunOnceCallback<3>(/*success=*/true, base::FilePath(kFilePath)));
   EXPECT_CALL(
       *client_,
       OnDownloadSucceeded(kGuid, CompletionInfoIs(base::FilePath(kFilePath))));
@@ -142,5 +146,19 @@
   task_environment_.RunUntilIdle();
 }
 
+// Verifies Client::OnDownloadUpdated() is called.
+TEST_F(BackgroundDownloadServiceImplTest, OnDownloadUpdated) {
+  store_->TriggerInit(/*success=*/true, empty_entries());
+  EXPECT_CALL(start_callback_, Run(kGuid, StartResult::ACCEPTED));
+  EXPECT_CALL(*download_helper_, StartDownload(_, _, _, _, _))
+      .WillOnce(RunCallback<4>(10u));
+  EXPECT_CALL(*client_, OnDownloadUpdated(kGuid, 0u, 10u));
+  auto download_params = CreateDownloadParams(kURL);
+  service()->StartDownload(std::move(download_params));
+  store_->TriggerUpdate(/*success=*/true);
+  EXPECT_EQ(kGuid, store_->LastUpdatedEntry()->guid);
+  task_environment_.RunUntilIdle();
+}
+
 }  // namespace
 }  // namespace download
diff --git a/components/download/internal/background_service/ios/background_download_task_helper.h b/components/download/internal/background_service/ios/background_download_task_helper.h
index 62e2faf..46802a65 100644
--- a/components/download/internal/background_service/ios/background_download_task_helper.h
+++ b/components/download/internal/background_service/ios/background_download_task_helper.h
@@ -28,7 +28,9 @@
   // Callback with whether download is succeeded and the file path of the
   // succeeded download.
   using CompletionCallback =
-      base::RepeatingCallback<void(bool, const base::FilePath&)>;
+      base::OnceCallback<void(bool, const base::FilePath&)>;
+  // Callback with number of bytes downloaded.
+  using UpdateCallback = base::RepeatingCallback<void(int64_t)>;
   static std::unique_ptr<BackgroundDownloadTaskHelper> Create(
       const base::FilePath& download_dir);
 
@@ -42,7 +44,8 @@
   virtual void StartDownload(const std::string& guid,
                              const RequestParams& request_params,
                              const SchedulingParams& scheduling_params,
-                             CompletionCallback completion_callback) = 0;
+                             CompletionCallback completion_callback,
+                             UpdateCallback update_callback) = 0;
 };
 
 }  // namespace download
diff --git a/components/download/internal/background_service/ios/background_download_task_helper.mm b/components/download/internal/background_service/ios/background_download_task_helper.mm
index 11ecce9..d562cc1 100644
--- a/components/download/internal/background_service/ios/background_download_task_helper.mm
+++ b/components/download/internal/background_service/ios/background_download_task_helper.mm
@@ -22,25 +22,39 @@
 
 using CompletionCallback =
     download::BackgroundDownloadTaskHelper::CompletionCallback;
+using UpdateCallback = download::BackgroundDownloadTaskHelper::UpdateCallback;
 
 @interface BackgroundDownloadDelegate : NSObject <NSURLSessionDownloadDelegate>
 - (instancetype)initWithDownloadDirectory:(base::FilePath)downloadDir
-                        completionHandler:(CompletionCallback)completionHandler;
+                                     guid:(std::string)guid
+                        completionHandler:(CompletionCallback)completionHandler
+                            updateHandler:(UpdateCallback)updateHandler;
 @end
 
 @implementation BackgroundDownloadDelegate {
   base::FilePath _downloadDir;
+  std::string _guid;
   CompletionCallback _completionCallback;
+  UpdateCallback _updateCallback;
 }
 
 - (instancetype)initWithDownloadDirectory:(base::FilePath)downloadDir
-                        completionHandler:
-                            (CompletionCallback)completionHandler {
+                                     guid:(std::string)guid
+                        completionHandler:(CompletionCallback)completionHandler
+                            updateHandler:(UpdateCallback)updateHandler {
   _downloadDir = downloadDir;
-  _completionCallback = completionHandler;
+  _guid = guid;
+  _completionCallback = std::move(completionHandler);
+  _updateCallback = updateHandler;
   return self;
 }
 
+- (void)invokeCompletionHandler:(bool)success
+                       filePath:(base::FilePath)filePath {
+  if (_completionCallback)
+    std::move(_completionCallback).Run(success, filePath);
+}
+
 #pragma mark - NSURLSessionDownloadDelegate
 
 - (void)URLSession:(NSURLSession*)session
@@ -60,7 +74,8 @@
   DVLOG(1) << __func__ << ",byte written: " << bytesWritten
            << ", totalBytesWritten:" << totalBytesWritten
            << ", totalBytesExpectedToWrite:" << totalBytesExpectedToWrite;
-  NOTIMPLEMENTED();
+  if (_updateCallback)
+    _updateCallback.Run(totalBytesWritten);
 }
 
 - (void)URLSession:(NSURLSession*)session
@@ -68,14 +83,14 @@
     didFinishDownloadingToURL:(NSURL*)location {
   DVLOG(1) << __func__;
   if (!location) {
-    _completionCallback.Run(/*success=*/false, base::FilePath());
+    [self invokeCompletionHandler:/*success=*/false filePath:base::FilePath()];
     return;
   }
 
   // Make sure the target directory exists.
   if (!base::CreateDirectory(_downloadDir)) {
     LOG(ERROR) << "Failed to create dir:" << _downloadDir;
-    _completionCallback.Run(/*success=*/false, base::FilePath());
+    [self invokeCompletionHandler:/*success=*/false filePath:base::FilePath()];
     return;
   }
 
@@ -83,16 +98,14 @@
   // service's target directory.
   const base::FilePath tempPath =
       base::mac::NSStringToFilePath([location path]);
-  // TODO(xingliu): Rename the file to use the guid of the download.
-  base::FilePath newFile = _downloadDir.Append(base::NumberToString(
-      base::Time::Now().ToDeltaSinceWindowsEpoch().InMilliseconds()));
+  base::FilePath newFile = _downloadDir.AppendASCII(_guid);
   if (!base::Move(tempPath, newFile)) {
     LOG(ERROR) << "Failed to move file from:" << tempPath
                << ", to:" << _downloadDir;
-    _completionCallback.Run(/*success=*/false, base::FilePath());
+    [self invokeCompletionHandler:/*success=*/false filePath:base::FilePath()];
     return;
   }
-  _completionCallback.Run(/*success=*/true, newFile);
+  [self invokeCompletionHandler:/*success=*/true filePath:newFile];
 }
 
 #pragma mark - NSURLSessionDelegate
@@ -103,7 +116,6 @@
   VLOG(1) << __func__;
   // TODO(xingliu): Check whether we can resume for a few times if the user
   // terminated the app in multitask window or failed downloads.
-  NOTIMPLEMENTED();
 }
 @end
 
@@ -121,7 +133,8 @@
   void StartDownload(const std::string& guid,
                      const RequestParams& request_params,
                      const SchedulingParams& scheduling_params,
-                     CompletionCallback completion_callback) override {
+                     CompletionCallback completion_callback,
+                     UpdateCallback update_callback) override {
     // TODO(xingliu): Implement handleEventsForBackgroundURLSession and invoke
     // the callback passed from it.
     NSURLSessionConfiguration* configuration = [NSURLSessionConfiguration
@@ -135,7 +148,9 @@
             SchedulingParams::BatteryRequirements::BATTERY_INSENSITIVE;
     BackgroundDownloadDelegate* delegate = [[BackgroundDownloadDelegate alloc]
         initWithDownloadDirectory:download_dir_
-                completionHandler:completion_callback];
+                             guid:guid
+                completionHandler:std::move(completion_callback)
+                    updateHandler:update_callback];
     NSURLSession* session = [NSURLSession sessionWithConfiguration:configuration
                                                           delegate:delegate
                                                      delegateQueue:nil];
diff --git a/components/download/internal/background_service/ios/background_download_task_helper_unittest.mm b/components/download/internal/background_service/ios/background_download_task_helper_unittest.mm
index 5dc4c78..dda06a4 100644
--- a/components/download/internal/background_service/ios/background_download_task_helper_unittest.mm
+++ b/components/download/internal/background_service/ios/background_download_task_helper_unittest.mm
@@ -11,6 +11,7 @@
 #import "base/files/scoped_temp_dir.h"
 #import "base/run_loop.h"
 #import "base/test/bind.h"
+#import "base/test/gmock_callback_support.h"
 #import "base/test/task_environment.h"
 #import "components/download/public/background_service/download_params.h"
 #import "net/test/embedded_test_server/embedded_test_server.h"
@@ -60,7 +61,8 @@
           ASSERT_TRUE(base::ReadFileToString(file_path, &content));
           EXPECT_EQ(kDefaultResponseContent, content);
           loop.Quit();
-        }));
+        }),
+        base::DoNothing());
     loop.Run();
     DCHECK(request_sent_);
     auto it = request_sent_->headers.find(net::HttpRequestHeaders::kIfMatch);
@@ -69,6 +71,7 @@
   }
 
   const HttpRequest* request_sent() const { return request_sent_.get(); }
+  const base::ScopedTempDir& dir() const { return dir_; }
 
  private:
   std::unique_ptr<HttpResponse> DefaultResponse(const HttpRequest& request) {
@@ -91,6 +94,7 @@
 // Verifies download can be finished.
 TEST_F(BackgroundDownloadTaskHelperTest, DownloadComplete) {
   Download("/test");
+  EXPECT_TRUE(base::PathExists(dir().GetPath().AppendASCII(kGuid)));
 }
 
 }  // namespace download
diff --git a/components/favicon/core/favicon_database.cc b/components/favicon/core/favicon_database.cc
index 940014c..fda4982 100644
--- a/components/favicon/core/favicon_database.cc
+++ b/components/favicon/core/favicon_database.cc
@@ -1061,7 +1061,9 @@
 
   // Clear databases which are too old to process.
   DCHECK_LT(kDeprecatedVersionNumber, kCurrentVersionNumber);
-  sql::MetaTable::RazeIfDeprecated(&db_, kDeprecatedVersionNumber);
+  sql::MetaTable::RazeIfIncompatible(
+      &db_, /*lowest_supported_version=*/kDeprecatedVersionNumber + 1,
+      kCurrentVersionNumber);
 
   // TODO(shess): Sqlite.Version.Thumbnail shows versions 22, 23, and
   // 25.  Future versions are not destroyed because that could lead to
diff --git a/components/full_restore/full_restore_read_and_save_unittest.cc b/components/full_restore/full_restore_read_and_save_unittest.cc
index ccc967b1..be23021 100644
--- a/components/full_restore/full_restore_read_and_save_unittest.cc
+++ b/components/full_restore/full_restore_read_and_save_unittest.cc
@@ -86,6 +86,10 @@
     return arc_read_handler->task_id_to_window_id_;
   }
 
+  void ClearRestoreData() {
+    read_handler_->profile_path_to_restore_data_.clear();
+  }
+
  private:
   FullRestoreReadHandler* read_handler_;
 };
@@ -176,6 +180,8 @@
   void ReadFromFile(const base::FilePath& file_path) {
     FullRestoreReadHandler* read_handler =
         FullRestoreReadHandler::GetInstance();
+    FullRestoreReadHandlerTestApi(read_handler).ClearRestoreData();
+
     base::RunLoop run_loop;
 
     read_handler->ReadFromFile(
diff --git a/components/full_restore/full_restore_read_handler.cc b/components/full_restore/full_restore_read_handler.cc
index bb814568..9bcc62d 100644
--- a/components/full_restore/full_restore_read_handler.cc
+++ b/components/full_restore/full_restore_read_handler.cc
@@ -102,6 +102,23 @@
 
 void FullRestoreReadHandler::ReadFromFile(const base::FilePath& profile_path,
                                           Callback callback) {
+  auto it = profile_path_to_restore_data_.find(profile_path);
+  if (it != profile_path_to_restore_data_.end()) {
+    // If the restore data has been read from the file, just use it, and don't
+    // need to read it again.
+    //
+    // We must use post task here, because FullRestoreAppLaunchHandler calls
+    // ReadFromFile in FullRestoreService construct function, and the callback
+    // in FullRestoreAppLaunchHandler calls the init function of
+    // FullRestoreService. If we don't use post task, and call the callback
+    // function directly, it could cause deadloop.
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::BindOnce(std::move(callback),
+                       (it->second ? it->second->Clone() : nullptr)));
+    return;
+  }
+
   auto file_handler =
       base::MakeRefCounted<FullRestoreFileHandler>(profile_path);
   file_handler->owning_task_runner()->PostTaskAndReplyWithResult(
@@ -377,6 +394,8 @@
         }
       }
     }
+  } else {
+    profile_path_to_restore_data_[profile_path] = nullptr;
   }
 
   std::move(callback).Run(std::move(restore_data));
diff --git a/components/full_restore/full_restore_read_handler.h b/components/full_restore/full_restore_read_handler.h
index bf83b710..d4f1dd2e 100644
--- a/components/full_restore/full_restore_read_handler.h
+++ b/components/full_restore/full_restore_read_handler.h
@@ -26,6 +26,8 @@
 namespace chromeos {
 namespace full_restore {
 class FullRestoreAppLaunchHandlerBrowserTest;
+class FullRestoreAppLaunchHandlerSystemWebAppsBrowserTest;
+class FullRestoreServiceTestHavingFullRestoreFile;
 }
 }
 
@@ -142,6 +144,10 @@
  private:
   friend class ArcReadHandler;
   friend class ::chromeos::full_restore::FullRestoreAppLaunchHandlerBrowserTest;
+  friend class ::chromeos::full_restore::
+      FullRestoreAppLaunchHandlerSystemWebAppsBrowserTest;
+  friend class ::chromeos::full_restore::
+      FullRestoreServiceTestHavingFullRestoreFile;
   friend class FullRestoreReadHandlerTestApi;
 
   // Gets the app launch information from `profile_path` for `app_id` and
diff --git a/components/full_restore/full_restore_save_handler.cc b/components/full_restore/full_restore_save_handler.cc
index 02b51b8c..2b21b17 100644
--- a/components/full_restore/full_restore_save_handler.cc
+++ b/components/full_restore/full_restore_save_handler.cc
@@ -6,6 +6,7 @@
 
 #include "ash/constants/app_types.h"
 #include "base/bind.h"
+#include "base/callback_helpers.h"
 #include "base/files/file_path.h"
 #include "base/no_destructor.h"
 #include "base/sequenced_task_runner.h"
@@ -13,6 +14,7 @@
 #include "components/full_restore/app_launch_info.h"
 #include "components/full_restore/full_restore_file_handler.h"
 #include "components/full_restore/full_restore_info.h"
+#include "components/full_restore/full_restore_read_handler.h"
 #include "components/full_restore/full_restore_utils.h"
 #include "components/full_restore/restore_data.h"
 #include "components/full_restore/window_info.h"
@@ -271,7 +273,7 @@
 
   pending_save_profile_paths_.insert(profile_path);
 
-  MaybeStartSaveTimer();
+  MaybeStartSaveTimer(profile_path);
 }
 
 void FullRestoreSaveHandler::ModifyWindowId(const base::FilePath& profile_path,
@@ -287,7 +289,7 @@
 
   pending_save_profile_paths_.insert(profile_path);
 
-  MaybeStartSaveTimer();
+  MaybeStartSaveTimer(profile_path);
 }
 
 void FullRestoreSaveHandler::ModifyWindowInfo(
@@ -304,7 +306,7 @@
 
   pending_save_profile_paths_.insert(profile_path);
 
-  MaybeStartSaveTimer();
+  MaybeStartSaveTimer(profile_path);
 }
 
 void FullRestoreSaveHandler::ModifyThemeColor(
@@ -322,7 +324,7 @@
 
   pending_save_profile_paths_.insert(profile_path);
 
-  MaybeStartSaveTimer();
+  MaybeStartSaveTimer(profile_path);
 }
 
 void FullRestoreSaveHandler::RemoveApp(const base::FilePath& profile_path,
@@ -335,7 +337,7 @@
 
   pending_save_profile_paths_.insert(profile_path);
 
-  MaybeStartSaveTimer();
+  MaybeStartSaveTimer(profile_path);
 }
 
 void FullRestoreSaveHandler::RemoveAppRestoreData(
@@ -350,7 +352,7 @@
 
   pending_save_profile_paths_.insert(profile_path);
 
-  MaybeStartSaveTimer();
+  MaybeStartSaveTimer(profile_path);
 }
 
 void FullRestoreSaveHandler::RemoveWindowInfo(
@@ -365,14 +367,14 @@
 
   pending_save_profile_paths_.insert(profile_path);
 
-  MaybeStartSaveTimer();
+  MaybeStartSaveTimer(profile_path);
 }
 
 void FullRestoreSaveHandler::ClearRestoreData(
     const base::FilePath& profile_path) {
   pending_save_profile_paths_.insert(profile_path);
 
-  MaybeStartSaveTimer();
+  MaybeStartSaveTimer(profile_path);
 }
 
 int32_t FullRestoreSaveHandler::GetArcSessionId() {
@@ -401,7 +403,19 @@
   app_id_to_app_launch_infos_.clear();
 }
 
-void FullRestoreSaveHandler::MaybeStartSaveTimer() {
+void FullRestoreSaveHandler::MaybeStartSaveTimer(
+    const base::FilePath& profile_path) {
+  if (!base::Contains(been_read_profile_paths_, profile_path)) {
+    // FullRestoreSaveHandler might be called to save the help app before
+    // FullRestoreAppLaunchHandler reads the full restore data from the full
+    // restore file during the system startup phase, e.g. when a new user login.
+    // So call FullRestoreReadHandler to read the file before saving the new
+    // data.
+    FullRestoreReadHandler::GetInstance()->ReadFromFile(profile_path,
+                                                        base::DoNothing());
+    been_read_profile_paths_.insert(profile_path);
+  }
+
   if (!save_timer_.IsRunning() && save_running_.empty()) {
     save_timer_.Start(FROM_HERE, kSaveDelay,
                       base::BindOnce(&FullRestoreSaveHandler::Save,
diff --git a/components/full_restore/full_restore_save_handler.h b/components/full_restore/full_restore_save_handler.h
index e14992f..864e21f 100644
--- a/components/full_restore/full_restore_save_handler.h
+++ b/components/full_restore/full_restore_save_handler.h
@@ -158,7 +158,7 @@
   using AppLaunchInfos = std::map<base::FilePath, std::list<AppLaunchInfoPtr>>;
 
   // Starts the timer that invokes Save (if timer isn't already running).
-  void MaybeStartSaveTimer();
+  void MaybeStartSaveTimer(const base::FilePath& profile_path);
 
   // Passes |profile_path_to_restore_data_| to the backend for saving.
   void Save();
@@ -177,6 +177,14 @@
   // Removes AppRestoreData for |window_id|.
   void RemoveAppRestoreData(int window_id);
 
+  // FullRestoreSaveHandler might be called to save the help app before
+  // FullRestoreAppLaunchHandler reads the full restore data from the full
+  // restore file during the system startup phase, e.g. when a new user login.
+  // So call FullRestoreReadHandler to read the file before saving the new data.
+  // `been_read_profile_paths_` is used to save the profile paths, whose full
+  // restore file has been read by FullRestoreReadHandler.
+  std::set<base::FilePath> been_read_profile_paths_;
+
   // Records whether there are new updates for saving between each saving delay.
   // |pending_save_profile_paths_| is cleared when Save is invoked.
   std::set<base::FilePath> pending_save_profile_paths_;
diff --git a/components/grpc_support/bidirectional_stream_unittest.cc b/components/grpc_support/bidirectional_stream_unittest.cc
index 5a56113a..63ef5ca 100644
--- a/components/grpc_support/bidirectional_stream_unittest.cc
+++ b/components/grpc_support/bidirectional_stream_unittest.cc
@@ -712,7 +712,9 @@
   ASSERT_EQ(TestBidirectionalStreamCallback::ON_FAILED, test.response_step);
   ASSERT_TRUE(test.net_error == net::ERR_QUIC_PROTOCOL_ERROR ||
               test.net_error == net::ERR_QUIC_HANDSHAKE_FAILED ||
-              test.net_error == net::ERR_CONNECTION_REFUSED);
+              test.net_error == net::ERR_CONNECTION_REFUSED ||
+              test.net_error == net::ERR_QUIC_GOAWAY_REQUEST_CAN_BE_RETRIED)
+      << net::ErrorToString(test.net_error);
   bidirectional_stream_destroy(test.stream);
 }
 
diff --git a/components/history/core/browser/top_sites_database.cc b/components/history/core/browser/top_sites_database.cc
index cc2d038d..bd3324f 100644
--- a/components/history/core/browser/top_sites_database.cc
+++ b/components/history/core/browser/top_sites_database.cc
@@ -322,7 +322,9 @@
 
   // Clear databases which are too old to process.
   DCHECK_LT(kDeprecatedVersionNumber, kVersionNumber);
-  sql::MetaTable::RazeIfDeprecated(db_.get(), kDeprecatedVersionNumber);
+  sql::MetaTable::RazeIfIncompatible(
+      db_.get(), /*lowest_supported_version=*/kDeprecatedVersionNumber + 1,
+      kVersionNumber);
 
   // Scope initialization in a transaction so we can't be partially
   // initialized.
diff --git a/components/nacl/broker/nacl_broker_listener.cc b/components/nacl/broker/nacl_broker_listener.cc
index ddbe1ff..9c4e7c6a 100644
--- a/components/nacl/broker/nacl_broker_listener.cc
+++ b/components/nacl/broker/nacl_broker_listener.cc
@@ -30,6 +30,8 @@
 #include "mojo/public/cpp/system/message_pipe.h"
 #include "sandbox/win/src/sandbox_policy.h"
 
+#include <windows.h>
+
 namespace {
 
 void SendReply(IPC::Channel* channel, int32_t pid, bool result) {
diff --git a/components/neterror/resources/offline.js b/components/neterror/resources/offline.js
index 895cd76..e6c6791 100644
--- a/components/neterror/resources/offline.js
+++ b/components/neterror/resources/offline.js
@@ -1856,7 +1856,7 @@
     this.canvasCtx.save();
 
     if (IS_RTL) {
-      this.canvasCtx.translate(this.canvas.width / 2, 0);
+      this.canvasCtx.translate(this.canvasDimensions.WIDTH, 0);
       this.canvasCtx.scale(-1, 1);
     }
 
@@ -1916,7 +1916,7 @@
     this.canvasCtx.save();
 
     if (IS_RTL) {
-      this.canvasCtx.translate(this.canvas.width / 2, 0);
+      this.canvasCtx.translate(this.canvasDimensions.WIDTH, 0);
       this.canvasCtx.scale(-1, 1);
     }
 
@@ -2908,6 +2908,7 @@
 
   this.config = DistanceMeter.config;
   this.maxScoreUnits = this.config.MAX_DISTANCE_UNITS;
+  this.canvasWidth = canvasWidth;
   this.init(canvasWidth);
 }
 
@@ -3015,12 +3016,12 @@
     if (IS_RTL) {
       if (opt_highScore) {
         this.canvasCtx.translate(
-            (this.canvas.width / 2) -
+            this.canvasWidth -
                 (DistanceMeter.dimensions.WIDTH * (this.maxScoreUnits + 3)),
             this.y);
       } else {
         this.canvasCtx.translate(
-            this.canvas.width / 2 - DistanceMeter.dimensions.WIDTH, this.y);
+            this.canvasWidth - DistanceMeter.dimensions.WIDTH, this.y);
       }
       this.canvasCtx.scale(-1, 1);
     } else {
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc
index f95c3ec..e2f9c6b 100644
--- a/components/omnibox/browser/omnibox_field_trial.cc
+++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -656,8 +656,13 @@
   const base::Feature* feature =
       is_incognito ? &omnibox::kOnDeviceHeadProviderIncognito
                    : &omnibox::kOnDeviceHeadProviderNonIncognito;
-  return base::GetFieldTrialParamValueByFeature(
+  std::string constraint = base::GetFieldTrialParamValueByFeature(
       *feature, kOnDeviceHeadModelLocaleConstraint);
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
+  if (constraint.empty())
+    constraint = "500000";
+#endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
+  return constraint;
 }
 
 int OmniboxFieldTrial::OnDeviceHeadSuggestMaxScoreForNonUrlInput(
diff --git a/components/password_manager/core/browser/form_fetcher_impl.cc b/components/password_manager/core/browser/form_fetcher_impl.cc
index a52454cf..84c41351 100644
--- a/components/password_manager/core/browser/form_fetcher_impl.cc
+++ b/components/password_manager/core/browser/form_fetcher_impl.cc
@@ -121,7 +121,9 @@
 // processor cycles.
 #if !defined(OS_IOS) && !defined(OS_ANDROID)
   // The statistics is needed for the "Save password?" bubble.
-  password_store->GetSiteStats(form_digest_.url.GetOrigin(), this);
+  password_manager::SmartBubbleStatsStore* stats_store =
+      password_store->GetSmartBubbleStatsStore();
+  stats_store->GetSiteStats(form_digest_.url.GetOrigin(), this);
 
   // The desktop bubble needs this information.
   password_store->GetMatchingInsecureCredentials(form_digest_.signon_realm,
diff --git a/components/password_manager/core/browser/mock_password_store.h b/components/password_manager/core/browser/mock_password_store.h
index 92ae4927..1c81c289 100644
--- a/components/password_manager/core/browser/mock_password_store.h
+++ b/components/password_manager/core/browser/mock_password_store.h
@@ -28,6 +28,14 @@
 
   MOCK_METHOD(void, RemoveLogin, (const PasswordForm&), (override));
   MOCK_METHOD(void,
+              RemoveLoginsByURLAndTime,
+              (const base::RepeatingCallback<bool(const GURL&)>&,
+               base::Time,
+               base::Time,
+               base::OnceClosure,
+               base::OnceCallback<void(bool)>),
+              (override));
+  MOCK_METHOD(void,
               Unblocklist,
               (const PasswordFormDigest&, base::OnceClosure),
               (override));
@@ -90,10 +98,20 @@
               (const std::u16string&),
               (override));
   MOCK_METHOD(DatabaseCleanupResult, DeleteUndecryptableLogins, (), (override));
+  void SetUnsyncedCredentialsDeletionNotifier(
+      std::unique_ptr<UnsyncedCredentialsDeletionNotifier> deletion_notifier)
+      override {
+    NOTIMPLEMENTED();
+  }
   MOCK_METHOD(void,
               NotifyLoginsChanged,
               (const PasswordStoreChangeList&),
               (override));
+  void NotifyDeletionsHaveSynced(bool) override { NOTIMPLEMENTED(); }
+  void NotifyUnsyncedCredentialsWillBeDeleted(
+      std::vector<PasswordForm>) override {
+    NOTIMPLEMENTED();
+  }
   MOCK_METHOD(std::vector<InteractionsStats>,
               GetSiteStatsImpl,
               (const GURL& origin_domain),
diff --git a/components/password_manager/core/browser/mock_password_store_interface.h b/components/password_manager/core/browser/mock_password_store_interface.h
index 8d4fa45..e4ce95cb 100644
--- a/components/password_manager/core/browser/mock_password_store_interface.h
+++ b/components/password_manager/core/browser/mock_password_store_interface.h
@@ -32,7 +32,7 @@
               (override));
   MOCK_METHOD(void,
               RemoveLoginsCreatedBetween,
-              (base::Time, base::Time, base::OnceClosure),
+              (base::Time, base::Time, base::OnceCallback<void(bool)>),
               (override));
   MOCK_METHOD(void,
               DisableAutoSignInForOrigins,
diff --git a/components/password_manager/core/browser/password_store.cc b/components/password_manager/core/browser/password_store.cc
index 28bb77f8..4ee2bce 100644
--- a/components/password_manager/core/browser/password_store.cc
+++ b/components/password_manager/core/browser/password_store.cc
@@ -129,15 +129,18 @@
     base::OnceClosure completion,
     base::OnceCallback<void(bool)> sync_completion) {
   DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
-  ScheduleTask(base::BindOnce(&PasswordStore::RemoveLoginsByURLAndTimeInternal,
-                              this, url_filter, delete_begin, delete_end,
-                              std::move(completion),
-                              std::move(sync_completion)));
+  // TODO(crbug.com/1226042): Pass NotifyLoginsChanged as a callback since
+  // PasswordStoreImpl won't call PasswordStore::NotifyLoginsChanged directly
+  // after it inherits PasswordStoreSync.
+  backend_->RemoveLoginsByURLAndTimeAsync(
+      base::NullCallback(), url_filter, delete_begin, delete_end,
+      std::move(completion), std::move(sync_completion));
 }
 
-void PasswordStore::RemoveLoginsCreatedBetween(base::Time delete_begin,
-                                               base::Time delete_end,
-                                               base::OnceClosure completion) {
+void PasswordStore::RemoveLoginsCreatedBetween(
+    base::Time delete_begin,
+    base::Time delete_end,
+    base::OnceCallback<void(bool)> completion) {
   DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
   ScheduleTask(
       base::BindOnce(&PasswordStore::RemoveLoginsCreatedBetweenInternal, this,
@@ -231,36 +234,6 @@
   return this;
 }
 
-void PasswordStore::AddSiteStats(const InteractionsStats& stats) {
-  DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
-  ScheduleTask(base::BindOnce(&PasswordStore::AddSiteStatsImpl, this, stats));
-}
-
-void PasswordStore::RemoveSiteStats(const GURL& origin_domain) {
-  DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
-  ScheduleTask(
-      base::BindOnce(&PasswordStore::RemoveSiteStatsImpl, this, origin_domain));
-}
-
-void PasswordStore::GetSiteStats(const GURL& origin_domain,
-                                 PasswordStoreConsumer* consumer) {
-  DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
-  PostStatsTaskAndReplyToConsumerWithResult(
-      consumer,
-      base::BindOnce(&PasswordStore::GetSiteStatsImpl, this, origin_domain));
-}
-
-void PasswordStore::RemoveStatisticsByOriginAndTime(
-    const base::RepeatingCallback<bool(const GURL&)>& origin_filter,
-    base::Time delete_begin,
-    base::Time delete_end,
-    base::OnceClosure completion) {
-  DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
-  ScheduleTask(base::BindOnce(
-      &PasswordStore::RemoveStatisticsByOriginAndTimeInternal, this,
-      origin_filter, delete_begin, delete_end, std::move(completion)));
-}
-
 void PasswordStore::ReportMetrics(const std::string& sync_username,
                                   bool custom_passphrase_sync_enabled,
                                   bool is_under_advanced_protection) {
@@ -350,12 +323,6 @@
                               std::move(completion)));
 }
 
-void PasswordStore::ClearStore(base::OnceCallback<void(bool)> completion) {
-  DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
-  ScheduleTask(base::BindOnce(&PasswordStore::ClearStoreInternal, this,
-                              std::move(completion)));
-}
-
 void PasswordStore::AddObserver(Observer* observer) {
   observers_->AddObserver(observer);
 }
@@ -394,22 +361,40 @@
           base::Unretained(this)));
 }
 
-void PasswordStore::SetUnsyncedCredentialsDeletionNotifier(
-    std::unique_ptr<PasswordStore::UnsyncedCredentialsDeletionNotifier>
-        notifier) {
-  DCHECK(!deletion_notifier_);
-  DCHECK(notifier);
-  deletion_notifier_ = std::move(notifier);
-}
-
-void PasswordStore::SetSyncTaskTimeoutForTest(base::TimeDelta timeout) {
-  sync_task_timeout_ = timeout;
-}
-
 PasswordStore::~PasswordStore() {
   DCHECK(shutdown_called_);
 }
 
+void PasswordStore::AddSiteStats(const InteractionsStats& stats) {
+  DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+  ScheduleTask(base::BindOnce(&PasswordStore::AddSiteStatsImpl, this, stats));
+}
+
+void PasswordStore::RemoveSiteStats(const GURL& origin_domain) {
+  DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+  ScheduleTask(
+      base::BindOnce(&PasswordStore::RemoveSiteStatsImpl, this, origin_domain));
+}
+
+void PasswordStore::GetSiteStats(const GURL& origin_domain,
+                                 PasswordStoreConsumer* consumer) {
+  DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+  PostStatsTaskAndReplyToConsumerWithResult(
+      consumer,
+      base::BindOnce(&PasswordStore::GetSiteStatsImpl, this, origin_domain));
+}
+
+void PasswordStore::RemoveStatisticsByOriginAndTime(
+    const base::RepeatingCallback<bool(const GURL&)>& origin_filter,
+    base::Time delete_begin,
+    base::Time delete_end,
+    base::OnceClosure completion) {
+  DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+  ScheduleTask(base::BindOnce(
+      &PasswordStore::RemoveStatisticsByOriginAndTimeInternal, this,
+      origin_filter, delete_begin, delete_end, std::move(completion)));
+}
+
 scoped_refptr<base::SequencedTaskRunner>
 PasswordStore::CreateBackgroundTaskRunner() const {
   return base::ThreadPool::CreateSequencedTaskRunner(
@@ -425,41 +410,12 @@
   }
 }
 
-void PasswordStore::NotifyDeletionsHaveSynced(bool success) {
-  DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
-  // Either all deletions have been committed to the Sync server, or Sync is
-  // telling us that it won't commit them (because Sync was turned off
-  // permanently). In either case, run the corresponding callbacks now (on the
-  // main task runner).
-  DCHECK(!success || !GetMetadataStore()->HasUnsyncedDeletions());
-  for (auto& callback : deletions_have_synced_callbacks_) {
-    main_task_runner_->PostTask(FROM_HERE,
-                                base::BindOnce(std::move(callback), success));
-  }
-  deletions_have_synced_timeout_.Cancel();
-  deletions_have_synced_callbacks_.clear();
-}
-
 void PasswordStore::InvokeAndNotifyAboutInsecureCredentialsChange(
     base::OnceCallback<PasswordStoreChangeList()> callback) {
   DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
   NotifyLoginsChanged(std::move(callback).Run());
 }
 
-void PasswordStore::NotifyUnsyncedCredentialsWillBeDeleted(
-    std::vector<PasswordForm> unsynced_credentials) {
-  DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
-  DCHECK(IsAccountStore());
-  // |deletion_notifier_| only gets set for desktop.
-  if (deletion_notifier_) {
-    main_task_runner_->PostTask(
-        FROM_HERE,
-        base::BindOnce(
-            &PasswordStore::UnsyncedCredentialsDeletionNotifier::Notify,
-            deletion_notifier_->GetWeakPtr(), std::move(unsynced_credentials)));
-  }
-}
-
 void PasswordStore::OnInitCompleted(bool success) {
   DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
   init_status_ = success ? InitStatus::kSuccess : InitStatus::kFailure;
@@ -566,47 +522,10 @@
   CommitTransaction();
 }
 
-void PasswordStore::RemoveLoginsByURLAndTimeInternal(
-    const base::RepeatingCallback<bool(const GURL&)>& url_filter,
-    base::Time delete_begin,
-    base::Time delete_end,
-    base::OnceClosure completion,
-    base::OnceCallback<void(bool)> sync_completion) {
-  DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
-  TRACE_EVENT0("passwords", "PasswordStore::RemoveLoginsByURLAndTimeInternal");
-  BeginTransaction();
-  PasswordStoreChangeList changes =
-      RemoveLoginsByURLAndTimeImpl(url_filter, delete_begin, delete_end);
-  NotifyLoginsChanged(changes);
-  // Sync metadata get updated in NotifyLoginsChanged(). Therefore,
-  // CommitTransaction() must be called after NotifyLoginsChanged(), because
-  // sync codebase needs to update metadata atomically together with the login
-  // data.
-  CommitTransaction();
-
-  if (completion)
-    main_task_runner_->PostTask(FROM_HERE, std::move(completion));
-
-  if (sync_completion) {
-    deletions_have_synced_callbacks_.push_back(std::move(sync_completion));
-    // Start a timeout for sync, or restart it if it was already running.
-    deletions_have_synced_timeout_.Reset(base::BindOnce(
-        &PasswordStore::NotifyDeletionsHaveSynced, this, /*success=*/false));
-    background_task_runner_->PostDelayedTask(
-        FROM_HERE, deletions_have_synced_timeout_.callback(),
-        sync_task_timeout_);
-
-    // Do an immediate check for the case where there are already no unsynced
-    // deletions.
-    if (!GetMetadataStore()->HasUnsyncedDeletions())
-      NotifyDeletionsHaveSynced(/*success=*/true);
-  }
-}
-
 void PasswordStore::RemoveLoginsCreatedBetweenInternal(
     base::Time delete_begin,
     base::Time delete_end,
-    base::OnceClosure completion) {
+    base::OnceCallback<void(bool)> completion) {
   DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
   TRACE_EVENT0("passwords",
                "PasswordStore::RemoveLoginsCreatedBetweenInternal");
@@ -619,8 +538,10 @@
   // sync codebase needs to update metadata atomically together with the login
   // data.
   CommitTransaction();
-  if (completion)
-    main_task_runner_->PostTask(FROM_HERE, std::move(completion));
+  if (completion) {
+    main_task_runner_->PostTask(
+        FROM_HERE, base::BindOnce(std::move(completion), !changes.empty()));
+  }
 }
 
 void PasswordStore::RemoveStatisticsByOriginAndTimeInternal(
@@ -672,18 +593,6 @@
     main_task_runner_->PostTask(FROM_HERE, std::move(completion));
 }
 
-void PasswordStore::ClearStoreInternal(
-    base::OnceCallback<void(bool)> completion) {
-  DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
-  bool should_clear = !IsEmpty();
-  if (should_clear)
-    DeleteAndRecreateDatabaseFile();
-  if (completion) {
-    main_task_runner_->PostTask(
-        FROM_HERE, base::BindOnce(std::move(completion), should_clear));
-  }
-}
-
 std::vector<std::unique_ptr<PasswordForm>> PasswordStore::GetLoginsImpl(
     const PasswordFormDigest& form) {
   DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
diff --git a/components/password_manager/core/browser/password_store.h b/components/password_manager/core/browser/password_store.h
index 98c5c01..dfec5c7 100644
--- a/components/password_manager/core/browser/password_store.h
+++ b/components/password_manager/core/browser/password_store.h
@@ -60,7 +60,7 @@
 // TODO(crbug.com/1217071): Move PasswordStoreSync to local backend.
 class PasswordStore : protected PasswordStoreSync,
                       public PasswordStoreInterface,
-                      public SmartBubbleStatsStore {
+                      protected SmartBubbleStatsStore {
  public:
   // Used to notify that unsynced credentials are about to be deleted.
   class UnsyncedCredentialsDeletionNotifier {
@@ -108,9 +108,10 @@
       base::OnceClosure completion,
       base::OnceCallback<void(bool)> sync_completion =
           base::NullCallback()) override;
-  void RemoveLoginsCreatedBetween(base::Time delete_begin,
-                                  base::Time delete_end,
-                                  base::OnceClosure completion) override;
+  void RemoveLoginsCreatedBetween(
+      base::Time delete_begin,
+      base::Time delete_end,
+      base::OnceCallback<void(bool)> completion) override;
   void DisableAutoSignInForOrigins(
       const base::RepeatingCallback<bool(const GURL&)>& origin_filter,
       base::OnceClosure completion) override;
@@ -128,16 +129,6 @@
   void RemoveObserver(Observer* observer) override;
   SmartBubbleStatsStore* GetSmartBubbleStatsStore() override;
 
-  // SmartBubbleStatsStore:
-  void AddSiteStats(const InteractionsStats& stats) override;
-  void RemoveSiteStats(const GURL& origin_domain) override;
-  void GetSiteStats(const GURL& origin_domain,
-                    PasswordStoreConsumer* consumer) override;
-  void RemoveStatisticsByOriginAndTime(
-      const base::RepeatingCallback<bool(const GURL&)>& origin_filter,
-      base::Time delete_begin,
-      base::Time delete_end,
-      base::OnceClosure completion) override;
 
   // Reports usage metrics for the database. |sync_username|, and
   // |custom_passphrase_sync_enabled|, and |is_under_advanced_protection|
@@ -182,12 +173,6 @@
                              base::Time remove_end,
                              base::OnceClosure completion);
 
-  // Deletes and re-creates the whole PasswordStore, unless it is already empty
-  // anyway. If |completion| is not null, it will be posted to the
-  // |main_task_runner_| once the process is complete. The bool parameter
-  // indicates whether any data was actually cleared.
-  void ClearStore(base::OnceCallback<void(bool)> completion);
-
   // Schedules the given |task| to be run on the PasswordStore's TaskRunner.
   bool ScheduleTask(base::OnceClosure task);
 
@@ -197,10 +182,9 @@
   CreateSyncControllerDelegate();
 
   // Sets |deletion_notifier_|. Must not pass a nullptr.
-  void SetUnsyncedCredentialsDeletionNotifier(
-      std::unique_ptr<UnsyncedCredentialsDeletionNotifier> deletion_notifier);
-
-  void SetSyncTaskTimeoutForTest(base::TimeDelta timeout);
+  virtual void SetUnsyncedCredentialsDeletionNotifier(
+      std::unique_ptr<UnsyncedCredentialsDeletionNotifier>
+          deletion_notifier) = 0;
 
  protected:
   using LoginsTask = base::OnceCallback<LoginsResult()>;
@@ -224,6 +208,17 @@
 
   ~PasswordStore() override;
 
+  // SmartBubbleStatsStore:
+  void AddSiteStats(const InteractionsStats& stats) override;
+  void RemoveSiteStats(const GURL& origin_domain) override;
+  void GetSiteStats(const GURL& origin_domain,
+                    PasswordStoreConsumer* consumer) override;
+  void RemoveStatisticsByOriginAndTime(
+      const base::RepeatingCallback<bool(const GURL&)>& origin_filter,
+      base::Time delete_begin,
+      base::Time delete_end,
+      base::OnceClosure completion) override;
+
   // Create a TaskRunner to be saved in |background_task_runner_|.
   virtual scoped_refptr<base::SequencedTaskRunner> CreateBackgroundTaskRunner()
       const;
@@ -322,11 +317,6 @@
   // been changed.
   void NotifyLoginsChanged(const PasswordStoreChangeList& changes) override;
 
-  void NotifyDeletionsHaveSynced(bool success) override;
-
-  void NotifyUnsyncedCredentialsWillBeDeleted(
-      std::vector<PasswordForm> unsynced_credentials) override;
-
   // Invokes callback and notifies observers if there was a change to the list
   // of insecure passwords. It also informs Sync about the updated password
   // forms to sync up the changes about insecure credentials.
@@ -396,15 +386,10 @@
   void RemoveLoginInternal(const PasswordForm& form);
   void UpdateLoginWithPrimaryKeyInternal(const PasswordForm& new_form,
                                          const PasswordForm& old_primary_key);
-  void RemoveLoginsByURLAndTimeInternal(
-      const base::RepeatingCallback<bool(const GURL&)>& url_filter,
+  void RemoveLoginsCreatedBetweenInternal(
       base::Time delete_begin,
       base::Time delete_end,
-      base::OnceClosure completion,
-      base::OnceCallback<void(bool)> sync_completion);
-  void RemoveLoginsCreatedBetweenInternal(base::Time delete_begin,
-                                          base::Time delete_end,
-                                          base::OnceClosure completion);
+      base::OnceCallback<void(bool)> completion);
   void RemoveStatisticsByOriginAndTimeInternal(
       const base::RepeatingCallback<bool(const GURL&)>& origin_filter,
       base::Time delete_begin,
@@ -425,8 +410,6 @@
                                      base::Time remove_end,
                                      base::OnceClosure completion);
 
-  void ClearStoreInternal(base::OnceCallback<void(bool)> completion);
-
   // Finds all PasswordForms with a signon_realm that is equal to, or is a
   // PSL-match to that of |form|, and takes care of notifying the consumer with
   // the results when done.
@@ -504,22 +487,10 @@
 
   PrefService* prefs_ = nullptr;
 
-  std::unique_ptr<UnsyncedCredentialsDeletionNotifier> deletion_notifier_;
-
-  // A list of callbacks that should be run once all pending deletions have been
-  // sent to the Sync server. Note that the vector itself lives on the
-  // background thread, but the callbacks must be run on the main thread!
-  std::vector<base::OnceCallback<void(bool)>> deletions_have_synced_callbacks_;
-  // Timeout closure that runs if sync takes too long to propagate deletions.
-  base::CancelableOnceClosure deletions_have_synced_timeout_;
-
   bool shutdown_called_ = false;
 
   InitStatus init_status_ = InitStatus::kUnknown;
 
-  // This is usually constant, only changed in tests.
-  base::TimeDelta sync_task_timeout_ = base::TimeDelta::FromSeconds(30);
-
   DISALLOW_COPY_AND_ASSIGN(PasswordStore);
 };
 
diff --git a/components/password_manager/core/browser/password_store_backend.h b/components/password_manager/core/browser/password_store_backend.h
index 349d3336..2a41ddbb 100644
--- a/components/password_manager/core/browser/password_store_backend.h
+++ b/components/password_manager/core/browser/password_store_backend.h
@@ -77,7 +77,9 @@
       OptionalStoreChangeListReply callback,
       const base::RepeatingCallback<bool(const GURL&)>& url_filter,
       base::Time delete_begin,
-      base::Time delete_end) {}
+      base::Time delete_end,
+      base::OnceClosure completion,
+      base::OnceCallback<void(bool)> sync_completion) = 0;
   virtual void RemoveLoginsCreatedBetweenAsync(
       OptionalStoreChangeListReply callback,
       base::Time delete_begin,
diff --git a/components/password_manager/core/browser/password_store_impl.cc b/components/password_manager/core/browser/password_store_impl.cc
index 55ecfcf..f2a79d11 100644
--- a/components/password_manager/core/browser/password_store_impl.cc
+++ b/components/password_manager/core/browser/password_store_impl.cc
@@ -19,6 +19,8 @@
 
 namespace {
 
+constexpr base::TimeDelta kSyncTaskTimeout = base::TimeDelta::FromSeconds(30);
+
 // Generates PasswordStoreChangeList for affected forms during
 // InsecureCredentials update.
 PasswordStoreChangeList BuildPasswordChangeListForInsecureCredentialsUpdate(
@@ -47,6 +49,14 @@
       base::BindOnce(&PasswordStoreImpl::DestroyOnBackgroundSequence, this));
 }
 
+void PasswordStoreImpl::SetUnsyncedCredentialsDeletionNotifier(
+    std::unique_ptr<PasswordStore::UnsyncedCredentialsDeletionNotifier>
+        notifier) {
+  DCHECK(!deletion_notifier_);
+  DCHECK(notifier);
+  deletion_notifier_ = std::move(notifier);
+}
+
 void PasswordStoreImpl::ReportMetricsImpl(const std::string& sync_username,
                                           bool custom_passphrase_sync_enabled,
                                           BulkCheckDone bulk_check_done) {
@@ -343,6 +353,35 @@
     sync_bridge_->ActOnPasswordStoreChanges(changes);
 }
 
+void PasswordStoreImpl::NotifyDeletionsHaveSynced(bool success) {
+  DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
+  // Either all deletions have been committed to the Sync server, or Sync is
+  // telling us that it won't commit them (because Sync was turned off
+  // permanently). In either case, run the corresponding callbacks now (on the
+  // main task runner).
+  DCHECK(!success || !GetMetadataStore()->HasUnsyncedDeletions());
+  for (auto& callback : deletions_have_synced_callbacks_) {
+    main_task_runner()->PostTask(FROM_HERE,
+                                 base::BindOnce(std::move(callback), success));
+  }
+  deletions_have_synced_timeout_.Cancel();
+  deletions_have_synced_callbacks_.clear();
+}
+
+void PasswordStoreImpl::NotifyUnsyncedCredentialsWillBeDeleted(
+    std::vector<PasswordForm> unsynced_credentials) {
+  DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
+  DCHECK(IsAccountStore());
+  // |deletion_notifier_| only gets set for desktop.
+  if (deletion_notifier_) {
+    main_task_runner()->PostTask(
+        FROM_HERE,
+        base::BindOnce(
+            &PasswordStoreImpl::UnsyncedCredentialsDeletionNotifier::Notify,
+            deletion_notifier_->GetWeakPtr(), std::move(unsynced_credentials)));
+  }
+}
+
 bool PasswordStoreImpl::BeginTransaction() {
   if (login_db_)
     return login_db_->BeginTransaction();
@@ -459,6 +498,23 @@
       std::move(callback));
 }
 
+void PasswordStoreImpl::RemoveLoginsByURLAndTimeAsync(
+    OptionalStoreChangeListReply callback,
+    const base::RepeatingCallback<bool(const GURL&)>& url_filter,
+    base::Time delete_begin,
+    base::Time delete_end,
+    base::OnceClosure completion,
+    base::OnceCallback<void(bool)> sync_completion) {
+  // TODO(crbug.com/1226042): Use PostTaskAndReplyWithResult instead of
+  // PostTask.
+  background_task_runner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          IgnoreResult(&PasswordStoreImpl::RemoveLoginsByURLAndTimeInternal),
+          this, url_filter, delete_begin, delete_end, std::move(completion),
+          std::move(sync_completion)));
+}
+
 bool PasswordStoreImpl::InitOnBackgroundSequence(
     base::RepeatingClosure sync_enabled_or_disabled_cb) {
   DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
@@ -573,4 +629,40 @@
   return changes;
 }
 
+PasswordStoreChangeList PasswordStoreImpl::RemoveLoginsByURLAndTimeInternal(
+    const base::RepeatingCallback<bool(const GURL&)>& url_filter,
+    base::Time delete_begin,
+    base::Time delete_end,
+    base::OnceClosure completion,
+    base::OnceCallback<void(bool)> sync_completion) {
+  BeginTransaction();
+  PasswordStoreChangeList changes =
+      RemoveLoginsByURLAndTimeImpl(url_filter, delete_begin, delete_end);
+  NotifyLoginsChanged(changes);
+  // Sync metadata get updated in NotifyLoginsChanged(). Therefore,
+  // CommitTransaction() must be called after NotifyLoginsChanged(), because
+  // sync codebase needs to update metadata atomically together with the login
+  // data.
+  CommitTransaction();
+
+  if (completion)
+    main_task_runner()->PostTask(FROM_HERE, std::move(completion));
+
+  if (sync_completion) {
+    deletions_have_synced_callbacks_.push_back(std::move(sync_completion));
+    // Start a timeout for sync, or restart it if it was already running.
+    deletions_have_synced_timeout_.Reset(
+        base::BindOnce(&PasswordStoreImpl::NotifyDeletionsHaveSynced, this,
+                       /*success=*/false));
+    background_task_runner()->PostDelayedTask(
+        FROM_HERE, deletions_have_synced_timeout_.callback(), kSyncTaskTimeout);
+
+    // Do an immediate check for the case where there are already no unsynced
+    // deletions.
+    if (!GetMetadataStore()->HasUnsyncedDeletions())
+      NotifyDeletionsHaveSynced(/*success=*/true);
+  }
+  return changes;
+}
+
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/password_store_impl.h b/components/password_manager/core/browser/password_store_impl.h
index 65c19d4..4d52f00 100644
--- a/components/password_manager/core/browser/password_store_impl.h
+++ b/components/password_manager/core/browser/password_store_impl.h
@@ -37,6 +37,9 @@
   ~PasswordStoreImpl() override;
 
   // Implements PasswordStore interface.
+  void SetUnsyncedCredentialsDeletionNotifier(
+      std::unique_ptr<UnsyncedCredentialsDeletionNotifier> deletion_notifier)
+      override;
   void ReportMetricsImpl(const std::string& sync_username,
                          bool custom_passphrase_sync_enabled,
                          BulkCheckDone bulk_check_done) override;
@@ -98,6 +101,9 @@
       base::span<const InsecureCredential> credentials) override;
   PasswordStoreChangeList RemoveLoginSync(const PasswordForm& form) override;
   void NotifyLoginsChanged(const PasswordStoreChangeList& changes) override;
+  void NotifyDeletionsHaveSynced(bool success) override;
+  void NotifyUnsyncedCredentialsWillBeDeleted(
+      std::vector<PasswordForm> unsynced_credentials) override;
   bool BeginTransaction() override;
   void RollbackTransaction() override;
   bool CommitTransaction() override;
@@ -131,6 +137,13 @@
                         const PasswordForm& form) override;
   void RemoveLoginAsync(OptionalStoreChangeListReply callback,
                         const PasswordForm& form) override;
+  void RemoveLoginsByURLAndTimeAsync(
+      OptionalStoreChangeListReply callback,
+      const base::RepeatingCallback<bool(const GURL&)>& url_filter,
+      base::Time delete_begin,
+      base::Time delete_end,
+      base::OnceClosure completion,
+      base::OnceCallback<void(bool)> sync_completion) override;
 
   // Opens |login_db_| and creates |sync_bridge_| on the background sequence.
   bool InitOnBackgroundSequence(
@@ -152,6 +165,12 @@
   PasswordStoreChangeList AddLoginInternal(const PasswordForm& form);
   PasswordStoreChangeList UpdateLoginInternal(const PasswordForm& form);
   PasswordStoreChangeList RemoveLoginInternal(const PasswordForm& form);
+  PasswordStoreChangeList RemoveLoginsByURLAndTimeInternal(
+      const base::RepeatingCallback<bool(const GURL&)>& url_filter,
+      base::Time delete_begin,
+      base::Time delete_end,
+      base::OnceClosure completion,
+      base::OnceCallback<void(bool)> sync_completion);
 
   // The login SQL database. The LoginDatabase instance is received via the
   // in an uninitialized state, so as to allow injecting mocks, then Init() is
@@ -161,6 +180,15 @@
 
   std::unique_ptr<PasswordSyncBridge> sync_bridge_;
 
+  std::unique_ptr<UnsyncedCredentialsDeletionNotifier> deletion_notifier_;
+
+  // A list of callbacks that should be run once all pending deletions have been
+  // sent to the Sync server. Note that the vector itself lives on the
+  // background thread, but the callbacks must be run on the main thread!
+  std::vector<base::OnceCallback<void(bool)>> deletions_have_synced_callbacks_;
+  // Timeout closure that runs if sync takes too long to propagate deletions.
+  base::CancelableOnceClosure deletions_have_synced_timeout_;
+
   DISALLOW_COPY_AND_ASSIGN(PasswordStoreImpl);
 };
 
diff --git a/components/password_manager/core/browser/password_store_interface.h b/components/password_manager/core/browser/password_store_interface.h
index 20146da9..d0e8808 100644
--- a/components/password_manager/core/browser/password_store_interface.h
+++ b/components/password_manager/core/browser/password_store_interface.h
@@ -91,10 +91,12 @@
 
   // Removes all logins created in the given date range. If `completion` is not
   // null, it will be run after deletions have been completed and notification
-  // have been sent out.
-  virtual void RemoveLoginsCreatedBetween(base::Time delete_begin,
-                                          base::Time delete_end,
-                                          base::OnceClosure completion) = 0;
+  // have been sent out. If any logins were removed 'true' will be passed to a
+  // completion, 'false' otherwise.
+  virtual void RemoveLoginsCreatedBetween(
+      base::Time delete_begin,
+      base::Time delete_end,
+      base::OnceCallback<void(bool)> completion) = 0;
 
   // Sets the 'skip_zero_click' flag for all credentials that match
   // `origin_filter`. `completion` will be run after these modifications are
diff --git a/components/password_manager/core/browser/password_store_unittest.cc b/components/password_manager/core/browser/password_store_unittest.cc
index 1428129..c6038c8 100644
--- a/components/password_manager/core/browser/password_store_unittest.cc
+++ b/components/password_manager/core/browser/password_store_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/test/bind.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
@@ -346,9 +347,9 @@
 
   EXPECT_CALL(mock_observer, OnLoginsChanged(_, testing::SizeIs(1u)));
   base::RunLoop run_loop;
-  store->RemoveLoginsCreatedBetween(base::Time::FromDoubleT(0),
-                                    base::Time::FromDoubleT(2),
-                                    run_loop.QuitClosure());
+  store->RemoveLoginsCreatedBetween(
+      base::Time::FromDoubleT(0), base::Time::FromDoubleT(2),
+      base::BindLambdaForTesting([&run_loop](bool) { run_loop.Quit(); }));
   run_loop.Run();
   testing::Mock::VerifyAndClearExpectations(&mock_observer);
 
@@ -384,9 +385,9 @@
 
   MockInsecureCredentialsConsumer consumer;
   base::RunLoop run_loop;
-  store->RemoveLoginsCreatedBetween(base::Time::FromDoubleT(0),
-                                    base::Time::FromDoubleT(2),
-                                    run_loop.QuitClosure());
+  store->RemoveLoginsCreatedBetween(
+      base::Time::FromDoubleT(0), base::Time::FromDoubleT(2),
+      base::BindLambdaForTesting([&run_loop](bool) { run_loop.Quit(); }));
   run_loop.Run();
 
   EXPECT_CALL(consumer, OnGetInsecureCredentials(testing::IsEmpty()));
diff --git a/components/password_manager/core/browser/sync/password_model_type_controller.cc b/components/password_manager/core/browser/sync/password_model_type_controller.cc
index 099e571a..64b47bfb 100644
--- a/components/password_manager/core/browser/sync/password_model_type_controller.cc
+++ b/components/password_manager/core/browser/sync/password_model_type_controller.cc
@@ -210,7 +210,8 @@
   if (features_util::IsOptedInForAccountStorage(pref_service_, sync_service_)) {
     RecordClearedOnStartup(ClearedOnStartup::kOptedInSoNoNeedToClear);
   } else {
-    account_password_store_for_cleanup->ClearStore(
+    account_password_store_for_cleanup->RemoveLoginsCreatedBetween(
+        base::Time(), base::Time::Max(),
         base::BindOnce(&PasswordStoreClearDone));
   }
 }
diff --git a/components/password_manager/core/browser/test_password_store.cc b/components/password_manager/core/browser/test_password_store.cc
index 094b803..22ec549 100644
--- a/components/password_manager/core/browser/test_password_store.cc
+++ b/components/password_manager/core/browser/test_password_store.cc
@@ -210,6 +210,16 @@
       std::move(callback));
 }
 
+void TestPasswordStore::RemoveLoginsByURLAndTimeAsync(
+    OptionalStoreChangeListReply callback,
+    const base::RepeatingCallback<bool(const GURL&)>& url_filter,
+    base::Time delete_begin,
+    base::Time delete_end,
+    base::OnceClosure completion,
+    base::OnceCallback<void(bool)> sync_completion) {
+  NOTIMPLEMENTED();
+}
+
 PasswordStoreChangeList TestPasswordStore::AddLoginImpl(
     const PasswordForm& form,
     AddLoginError* error) {
@@ -447,6 +457,11 @@
   NOTIMPLEMENTED();
 }
 
+void TestPasswordStore::SetUnsyncedCredentialsDeletionNotifier(
+    std::unique_ptr<UnsyncedCredentialsDeletionNotifier> deletion_notifier) {
+  NOTIMPLEMENTED();
+}
+
 PasswordStoreChangeList TestPasswordStore::AddLoginSync(
     const PasswordForm& form,
     AddLoginError* error) {
@@ -480,6 +495,15 @@
   return {};
 }
 
+void TestPasswordStore::NotifyDeletionsHaveSynced(bool success) {
+  NOTIMPLEMENTED();
+}
+
+void TestPasswordStore::NotifyUnsyncedCredentialsWillBeDeleted(
+    std::vector<PasswordForm> unsynced_credentials) {
+  NOTIMPLEMENTED();
+}
+
 bool TestPasswordStore::BeginTransaction() {
   return true;
 }
diff --git a/components/password_manager/core/browser/test_password_store.h b/components/password_manager/core/browser/test_password_store.h
index 5a44298..2b73922 100644
--- a/components/password_manager/core/browser/test_password_store.h
+++ b/components/password_manager/core/browser/test_password_store.h
@@ -96,6 +96,13 @@
                         const PasswordForm& form) override;
   void RemoveLoginAsync(OptionalStoreChangeListReply callback,
                         const PasswordForm& form) override;
+  void RemoveLoginsByURLAndTimeAsync(
+      OptionalStoreChangeListReply callback,
+      const base::RepeatingCallback<bool(const GURL&)>& url_filter,
+      base::Time delete_begin,
+      base::Time delete_end,
+      base::OnceClosure completion,
+      base::OnceCallback<void(bool)> sync_completion) override;
   // PasswordStore interface
   PasswordStoreChangeList AddLoginImpl(const PasswordForm& form,
                                        AddLoginError* error) override;
@@ -142,7 +149,9 @@
   std::vector<FieldInfo> GetAllFieldInfoImpl() override;
   void RemoveFieldInfoByTimeImpl(base::Time remove_begin,
                                  base::Time remove_end) override;
-
+  void SetUnsyncedCredentialsDeletionNotifier(
+      std::unique_ptr<UnsyncedCredentialsDeletionNotifier> deletion_notifier)
+      override;
   // PasswordStoreSync interface.
   // TODO(crbug.bom/1226042): Remove this after PasswordStore no longer
   // inherits PasswordStoreSync.
@@ -156,6 +165,9 @@
       const PasswordForm& form,
       base::span<const InsecureCredential> credentials) override;
   PasswordStoreChangeList RemoveLoginSync(const PasswordForm& form) override;
+  void NotifyDeletionsHaveSynced(bool success) override;
+  void NotifyUnsyncedCredentialsWillBeDeleted(
+      std::vector<PasswordForm> unsynced_credentials) override;
   bool BeginTransaction() override;
   void RollbackTransaction() override;
   bool CommitTransaction() override;
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 6f53c3bf..5527550 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -15083,35 +15083,25 @@
       For detailed information on valid input patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns. <ph name="WILDCARD_VALUE">*</ph> is not an accepted value for this policy. This policy only matches based on origin, so any path in the URL pattern is ignored.''',
     },
     {
-      'name': 'ManagedWebAppsAccessToDeviceAttributesAllowed',
+      'name': 'DeviceAttributesAllowedForOrigins',
       'owners': ['file://components/policy/resources/OWNERS', 'anqing@chromium.org'],
-      'type': 'main',
-      'schema': { 'type': 'boolean' },
+      'type': 'list',
+      'schema': {
+        'type': 'array',
+        'items': { 'type': 'string' },
+      },
       'supported_on': ['chrome_os:93-'],
       'features': {
         'dynamic_refresh': True,
         'per_profile': True,
       },
-      'items': [
-        {
-          'value': True,
-          'caption': 'Allow force-installed web applications to query for device attributes.',
-        },
-        {
-          'value': False,
-          'caption': 'Prevent force-installed web applications from querying for device attributes.',
-        },
-      ],
-      'example_value': True,
-      'default': True,
+      'example_value': ['https://www.google.com', 'https://www.example.com'],
       'id': 865,
-      'caption': '''Allow force-installed web applications to query for device attributes.''',
+      'caption': '''Allow origins to query for device attributes''',
       'tags': [],
-      'desc': '''Setting the policy to allow force-installed web applications to get device attributes (e.g. serial number, hostname) by using Device Attributes web API.
+      'desc': '''Setting the policy to allow some origins of force-installed web applications to get device attributes (e.g. serial number, hostname) by using Device Attributes API.
 
-      If this policy is set to true or not configured, the Device Attributes web API will be allowed to force-installed web applications.
-
-      If this policy is set to false, the Device Attributes web API will be disallowed.''',
+      Device Attributes API is a list of web APIs, please see https://wicg.github.io/WebApiDevice/device_attributes. They are only available to origins which correspond to force-installed web applications via <ph name="WEB_APP_INSTALL_FORCE_LIST_POLICY_NAME">WebAppInstallForceList</ph> or the one configured in the Kiosk session.'''
     },
     {
       'name': 'QuicAllowed',
@@ -20820,7 +20810,7 @@
           'caption': '''Default behavior for LBS.''',
         },
         {
-          'name': 'Strict',
+          'name': 'IESiteListMode',
           'value': 1,
           'caption': '''More compatible with Microsoft IE/Edge enterprise mode sitelists.''',
         },
@@ -20836,15 +20826,17 @@
       'tags': [],
       'desc': '''This policy controls how <ph name="PRODUCT_NAME">Google Chrome</ph> interprets sitelist/greylist policies for the Legacy Browser Support feature. It affects the following policies: <ph name="URL_LIST_POLICY_NAME">BrowserSwitcherUrlList</ph>, <ph name="URL_GREYLIST_POLICY_NAME">BrowserSwitcherUrlGreylist</ph>, <ph name="USE_IE_SITELIST_POLICY_NAME">BrowserSwitcherUseIeSitelist</ph>, <ph name="EXTERNAL_SITELIST_POLICY_NAME">BrowserSwitcherExternalSitelistUrl</ph>, and <ph name="EXTERNAL_GREYLIST_POLICY_NAME">BrowserSwitcherExternalGreylistUrl</ph>.
 
-      If 'Default' (0) or unset, URL matching is less strict. Rules that do not contain "/" look for a substring anywhere in the URL's hostname.
+      If 'Default' (0) or unset, URL matching is less strict. Rules that do not contain "/" look for a substring anywhere in the URL's hostname. Matching the path component of a URL is case-sensitive.
 
-      If 'Strict' (1), URL matching is more strict. Rules that do not contain "/" only match at the end of the hostname. They must also be at a domain name boundary. This is more compatible with <ph name="MS_IE_PRODUCT_NAME">Microsoft® Internet Explorer®</ph> and <ph name="MS_EDGE_PRODUCT_NAME">Microsoft® Edge®</ph>.
+      If 'IESiteListMode' (1), URL matching is more strict. Rules that do not contain "/" only match at the end of the hostname. They must also be at a domain name boundary. Matching the path component of a URL is case-insensitive. This is more compatible with <ph name="MS_IE_PRODUCT_NAME">Microsoft® Internet Explorer®</ph> and <ph name="MS_EDGE_PRODUCT_NAME">Microsoft® Edge®</ph>.
 
-      For example, with the rule "example.com":
+      For example, with the rules "example.com" and "acme.com/abc":
 
-      "http://example.com/" and "http://subdomain.example.com/" match regardless of parsing mode.
+      "http://example.com/", "http://subdomain.example.com/" and "http://acme.com/abc" match regardless of parsing mode.
 
-      "http://notexample.com/", "http://example.com.invalid.com/" and "http://example.comabc/" only match in 'Default' mode.''',
+      "http://notexample.com/", "http://example.com.invalid.com/", "http://example.comabc/" only match in 'Default' mode.
+
+      "http://acme.com/ABC" only matches in 'IESiteListMode'.''',
     },
     {
       'id': 519,
diff --git a/components/previous_session_info/previous_session_info.h b/components/previous_session_info/previous_session_info.h
index 47a78a2..d39326102 100644
--- a/components/previous_session_info/previous_session_info.h
+++ b/components/previous_session_info/previous_session_info.h
@@ -11,6 +11,10 @@
 
 #include "url/gurl.h"
 
+namespace base {
+class TimeDelta;
+}
+
 namespace previous_session_info_constants {
 // - The (Integer) representing UIApplicationState.
 extern NSString* const kPreviousSessionInfoApplicationState;
diff --git a/components/previous_session_info/previous_session_info.mm b/components/previous_session_info/previous_session_info.mm
index 6f3ef6a..fab250bb 100644
--- a/components/previous_session_info/previous_session_info.mm
+++ b/components/previous_session_info/previous_session_info.mm
@@ -11,6 +11,7 @@
 #include "base/ios/ios_util.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/system/sys_info.h"
+#include "base/time/time.h"
 #include "base/timer/timer.h"
 #import "components/previous_session_info/previous_session_info_private.h"
 #include "components/version_info/version_info.h"
diff --git a/components/safe_browsing/content/browser/base_blocking_page.h b/components/safe_browsing/content/browser/base_blocking_page.h
index 2129e3d..1f820c97 100644
--- a/components/safe_browsing/content/browser/base_blocking_page.h
+++ b/components/safe_browsing/content/browser/base_blocking_page.h
@@ -49,6 +49,10 @@
   // Checks the threat type to decide if we should report ThreatDetails.
   static bool ShouldReportThreatDetails(SBThreatType threat_type);
 
+  // Populates the report details for |unsafe_resources|.
+  static security_interstitials::MetricsHelper::ReportDetails GetReportingInfo(
+      const UnsafeResourceList& unsafe_resources);
+
  protected:
   // Don't instantiate this class directly, use ShowBlockingPage instead.
   BaseBlockingPage(
@@ -102,9 +106,6 @@
 
   void set_proceeded(bool proceeded);
 
-  static security_interstitials::MetricsHelper::ReportDetails GetReportingInfo(
-      const UnsafeResourceList& unsafe_resources);
-
   void SetThreatDetailsProceedDelayForTesting(int64_t delay);
 
   static std::unique_ptr<
diff --git a/components/shared_highlighting/core/common/disabled_sites.cc b/components/shared_highlighting/core/common/disabled_sites.cc
index bb1d2944..dcc278656 100644
--- a/components/shared_highlighting/core/common/disabled_sites.cc
+++ b/components/shared_highlighting/core/common/disabled_sites.cc
@@ -39,6 +39,11 @@
       domain = domain.substr(7);
     }
 
+    if (base::FeatureList::IsEnabled(kSharedHighlightingAmp) &&
+        domain.compare("google.com") == 0) {
+      return true;
+    }
+
     auto* it = kBlocklist.find(domain);
     if (it != kBlocklist.end()) {
       return !re2::RE2::FullMatch(url.path(), it->second.data());
diff --git a/components/shared_highlighting/core/common/disabled_sites_unittest.cc b/components/shared_highlighting/core/common/disabled_sites_unittest.cc
index 9cd99242..8833025 100644
--- a/components/shared_highlighting/core/common/disabled_sites_unittest.cc
+++ b/components/shared_highlighting/core/common/disabled_sites_unittest.cc
@@ -22,6 +22,9 @@
 }
 
 TEST(DisabledSitesTest, SpecificPages) {
+  base::test::ScopedFeatureList feature;
+  feature.InitAndDisableFeature(kSharedHighlightingAmp);
+
   // Paths starting with /amp/ are disabled.
   EXPECT_FALSE(ShouldOfferLinkToText(GURL("https://www.google.com/amp/")));
   EXPECT_FALSE(ShouldOfferLinkToText(GURL("https://www.google.com/amp/foo")));
@@ -47,10 +50,21 @@
   base::test::ScopedFeatureList feature;
   feature.InitAndDisableFeature(kSharedHighlightingUseBlocklist);
 
-  EXPECT_TRUE(ShouldOfferLinkToText(GURL("https://www.youtube.com")));
   EXPECT_TRUE(ShouldOfferLinkToText(GURL("https://www.google.com/amp/")));
+  EXPECT_TRUE(ShouldOfferLinkToText(GURL("https://www.youtube.com")));
   EXPECT_TRUE(ShouldOfferLinkToText(GURL("https://www.example.com")));
 }
 
+TEST(DisabledSitesTest, AmpFeatureEnabled) {
+  base::test::ScopedFeatureList feature;
+  feature.InitWithFeatures(
+      {kSharedHighlightingUseBlocklist, kSharedHighlightingAmp}, {});
+
+  EXPECT_TRUE(ShouldOfferLinkToText(GURL("https://www.google.com/amp/")));
+  EXPECT_TRUE(ShouldOfferLinkToText(GURL("https://www.google.com/amp/foo")));
+  EXPECT_TRUE(ShouldOfferLinkToText(GURL("https://google.com/amp/")));
+  EXPECT_TRUE(ShouldOfferLinkToText(GURL("https://google.com/amp/foo")));
+}
+
 }  // namespace
 }  // namespace shared_highlighting
diff --git a/components/site_engagement/content/site_engagement_score.cc b/components/site_engagement/content/site_engagement_score.cc
index fb9c170d..4440733 100644
--- a/components/site_engagement/content/site_engagement_score.cc
+++ b/components/site_engagement/content/site_engagement_score.cc
@@ -321,17 +321,14 @@
 }
 
 bool SiteEngagementScore::UpdateScoreDict(base::DictionaryValue* score_dict) {
-  double raw_score_orig = 0;
-  double points_added_today_orig = 0;
-  double last_engagement_time_internal_orig = 0;
-  double last_shortcut_launch_time_internal_orig = 0;
+  double raw_score_orig = score_dict->FindDoubleKey(kRawScoreKey).value_or(0);
+  double points_added_today_orig =
+      score_dict->FindDoubleKey(kPointsAddedTodayKey).value_or(0);
+  double last_engagement_time_internal_orig =
+      score_dict->FindDoubleKey(kLastEngagementTimeKey).value_or(0);
+  double last_shortcut_launch_time_internal_orig =
+      score_dict->FindDoubleKey(kLastShortcutLaunchTimeKey).value_or(0);
 
-  score_dict->GetDouble(kRawScoreKey, &raw_score_orig);
-  score_dict->GetDouble(kPointsAddedTodayKey, &points_added_today_orig);
-  score_dict->GetDouble(kLastEngagementTimeKey,
-                        &last_engagement_time_internal_orig);
-  score_dict->GetDouble(kLastShortcutLaunchTimeKey,
-                        &last_shortcut_launch_time_internal_orig);
   bool changed =
       DoublesConsideredDifferent(raw_score_orig, raw_score_, kScoreDelta) ||
       DoublesConsideredDifferent(points_added_today_orig, points_added_today_,
@@ -371,14 +368,21 @@
   if (!score_dict_)
     return;
 
-  score_dict_->GetDouble(kRawScoreKey, &raw_score_);
-  score_dict_->GetDouble(kPointsAddedTodayKey, &points_added_today_);
+  raw_score_ = score_dict_->FindDoubleKey(kRawScoreKey).value_or(0);
+  points_added_today_ =
+      score_dict_->FindDoubleKey(kPointsAddedTodayKey).value_or(0);
 
-  double internal_time;
-  if (score_dict_->GetDouble(kLastEngagementTimeKey, &internal_time))
-    last_engagement_time_ = base::Time::FromInternalValue(internal_time);
-  if (score_dict_->GetDouble(kLastShortcutLaunchTimeKey, &internal_time))
-    last_shortcut_launch_time_ = base::Time::FromInternalValue(internal_time);
+  absl::optional<double> maybe_last_engagement_time =
+      score_dict_->FindDoubleKey(kLastEngagementTimeKey);
+  if (maybe_last_engagement_time.has_value())
+    last_engagement_time_ =
+        base::Time::FromInternalValue(maybe_last_engagement_time.value());
+
+  absl::optional<double> maybe_last_shortcut_launch_time =
+      score_dict_->FindDoubleKey(kLastShortcutLaunchTimeKey);
+  if (maybe_last_shortcut_launch_time.has_value())
+    last_shortcut_launch_time_ =
+        base::Time::FromInternalValue(maybe_last_shortcut_launch_time.value());
 }
 
 double SiteEngagementScore::DecayedScore() const {
diff --git a/components/sync/driver/glue/sync_engine_impl.cc b/components/sync/driver/glue/sync_engine_impl.cc
index dfa96bb..8b6ef2c 100644
--- a/components/sync/driver/glue/sync_engine_impl.cc
+++ b/components/sync/driver/glue/sync_engine_impl.cc
@@ -8,6 +8,7 @@
 
 #include "base/base64.h"
 #include "base/bind.h"
+#include "base/callback_forward.h"
 #include "base/callback_helpers.h"
 #include "base/command_line.h"
 #include "base/feature_list.h"
diff --git a/components/sync/driver/sync_service_impl.cc b/components/sync/driver/sync_service_impl.cc
index 6bfcba51..a7d8b3c52 100644
--- a/components/sync/driver/sync_service_impl.cc
+++ b/components/sync/driver/sync_service_impl.cc
@@ -36,6 +36,7 @@
 #include "components/sync/driver/sync_auth_manager.h"
 #include "components/sync/driver/sync_driver_switches.h"
 #include "components/sync/driver/sync_type_preference_provider.h"
+#include "components/sync/engine/configure_reason.h"
 #include "components/sync/engine/engine_components_factory_impl.h"
 #include "components/sync/engine/net/http_bridge.h"
 #include "components/sync/engine/net/http_post_provider_factory.h"
@@ -221,6 +222,13 @@
         sync_client_->GetSyncInvalidationsService();
     if (sync_invalidations_service) {
       sync_invalidations_service->SetActive(IsSignedIn());
+      // Trigger a refresh when additional data types get enabled for
+      // invalidations. This is needed to get the latest data after subscribing
+      // for the updates.
+      sync_invalidations_service
+          ->SetCommittedAdditionalInterestedDataTypesCallback(
+              base::BindRepeating(&SyncServiceImpl::TriggerRefresh,
+                                  weak_factory_.GetWeakPtr()));
     }
   }
 
@@ -1282,9 +1290,7 @@
             switches::kUseSyncInvalidationsForWalletAndOffer))) {
     types.RemoveAll({AUTOFILL_WALLET_DATA, AUTOFILL_WALLET_OFFER});
   }
-  invalidations_service->SetInterestedDataTypes(
-      types, base::BindRepeating(&SyncServiceImpl::TriggerRefresh,
-                                 sync_enabled_weak_factory_.GetWeakPtr()));
+  invalidations_service->SetInterestedDataTypes(types);
 }
 
 SyncCycleSnapshot SyncServiceImpl::GetLastCycleSnapshotForDebugging() const {
diff --git a/components/sync/driver/sync_service_impl_unittest.cc b/components/sync/driver/sync_service_impl_unittest.cc
index 335d7363..279dddf 100644
--- a/components/sync/driver/sync_service_impl_unittest.cc
+++ b/components/sync/driver/sync_service_impl_unittest.cc
@@ -1182,10 +1182,10 @@
   InitializeForNthSync();
 
   EXPECT_CALL(*sync_invalidations_service(),
-              SetInterestedDataTypes(ContainsSessions(), _));
+              SetInterestedDataTypes(ContainsSessions()));
   service()->SetInvalidationsForSessionsEnabled(true);
   EXPECT_CALL(*sync_invalidations_service(),
-              SetInterestedDataTypes(Not(ContainsSessions()), _));
+              SetInterestedDataTypes(Not(ContainsSessions())));
   service()->SetInvalidationsForSessionsEnabled(false);
 }
 
diff --git a/components/sync/driver/sync_service_utils.cc b/components/sync/driver/sync_service_utils.cc
index 324e6903..bd1f2d86 100644
--- a/components/sync/driver/sync_service_utils.cc
+++ b/components/sync/driver/sync_service_utils.cc
@@ -96,6 +96,14 @@
     return false;
   }
 
+  const ModelTypeSet encrypted_types =
+      service->GetUserSettings()->GetEncryptedDataTypes();
+  if (Intersection(service->GetActiveDataTypes(), encrypted_types).Empty()) {
+    // No point in offering the user a new encryption method if they are not
+    // syncing any encrypted types.
+    return false;
+  }
+
   switch (service->GetUserSettings()->GetPassphraseType()) {
     case PassphraseType::kImplicitPassphrase:
     case PassphraseType::kFrozenImplicitPassphrase:
diff --git a/components/sync/engine/cycle/data_type_tracker.cc b/components/sync/engine/cycle/data_type_tracker.cc
index 57cc7189..e27fc27 100644
--- a/components/sync/engine/cycle/data_type_tracker.cc
+++ b/components/sync/engine/cycle/data_type_tracker.cc
@@ -25,6 +25,9 @@
     base::TimeDelta::FromMilliseconds(2000);
 constexpr base::TimeDelta kVeryBigLocalChangeNudgeDelay = kDefaultPollInterval;
 
+constexpr base::TimeDelta kDefaultLocalChangeNudgeDelayForSessions =
+    base::TimeDelta::FromSeconds(11);
+
 const size_t kDefaultMaxPayloadsPerType = 10;
 
 base::TimeDelta GetDefaultLocalChangeNudgeDelay(ModelType model_type) {
@@ -34,9 +37,13 @@
       // Accompany types rely on nudges from other types, and hence have long
       // nudge delays.
       return kVeryBigLocalChangeNudgeDelay;
+    case SESSIONS:
+      // Sessions is the type that causes the most commit traffic. It gets a
+      // custom nudge delay, tuned for a reasonable trade-off between traffic
+      // and freshness.
+      return kDefaultLocalChangeNudgeDelayForSessions;
     case BOOKMARKS:
     case PREFERENCES:
-    case SESSIONS:
       // Types with sometimes automatic changes get longer delays to allow more
       // coalescing.
       return kBigLocalChangeNudgeDelay;
diff --git a/components/sync/engine/cycle/nudge_tracker_unittest.cc b/components/sync/engine/cycle/nudge_tracker_unittest.cc
index 6b34fc8..2ddcadf 100644
--- a/components/sync/engine/cycle/nudge_tracker_unittest.cc
+++ b/components/sync/engine/cycle/nudge_tracker_unittest.cc
@@ -813,17 +813,26 @@
   EXPECT_EQ(nudge_tracker_.RecordLocalChange(TYPED_URLS),
             nudge_tracker_.RecordLocalChange(EXTENSIONS));
 
-  // Bookmarks, preferences and sessions have bigger delays.
+  // Bookmarks and preferences sometimes have automatic changes (not directly
+  // caused by a user actions), so they have bigger delays.
   EXPECT_GT(nudge_tracker_.RecordLocalChange(BOOKMARKS),
             nudge_tracker_.RecordLocalChange(TYPED_URLS));
   EXPECT_EQ(nudge_tracker_.RecordLocalChange(BOOKMARKS),
             nudge_tracker_.RecordLocalChange(PREFERENCES));
-  EXPECT_EQ(nudge_tracker_.RecordLocalChange(BOOKMARKS),
-            nudge_tracker_.RecordLocalChange(SESSIONS));
 
-  // Autofill has the longer delay of all.
-  EXPECT_GT(nudge_tracker_.RecordLocalChange(AUTOFILL),
+  // Sessions has an even bigger delay.
+  EXPECT_GT(nudge_tracker_.RecordLocalChange(SESSIONS),
             nudge_tracker_.RecordLocalChange(BOOKMARKS));
+
+  // Autofill and UserEvents are "accompany types" that rely on nudges from
+  // other types. They have the longest delay of all, which really only acts as
+  // a last-resort fallback.
+  EXPECT_GT(nudge_tracker_.RecordLocalChange(AUTOFILL),
+            nudge_tracker_.RecordLocalChange(SESSIONS));
+  EXPECT_GT(nudge_tracker_.RecordLocalChange(AUTOFILL),
+            base::TimeDelta::FromHours(1));
+  EXPECT_EQ(nudge_tracker_.RecordLocalChange(AUTOFILL),
+            nudge_tracker_.RecordLocalChange(USER_EVENTS));
 }
 
 // Test that custom nudge delays are used over the defaults.
diff --git a/components/sync/invalidations/interested_data_types_handler.h b/components/sync/invalidations/interested_data_types_handler.h
index 3bcc8660a..d50c990 100644
--- a/components/sync/invalidations/interested_data_types_handler.h
+++ b/components/sync/invalidations/interested_data_types_handler.h
@@ -6,6 +6,7 @@
 #define COMPONENTS_SYNC_INVALIDATIONS_INTERESTED_DATA_TYPES_HANDLER_H_
 
 #include "base/callback.h"
+#include "components/sync/base/model_type.h"
 
 namespace syncer {
 
@@ -17,7 +18,12 @@
   virtual ~InterestedDataTypesHandler() = default;
 
   // Called on each change of interested data types.
-  virtual void OnInterestedDataTypesChanged(base::OnceClosure callback) = 0;
+  virtual void OnInterestedDataTypesChanged() = 0;
+
+  // Called to provide an interface to invoke GetUpdates after any additional
+  // interested data types get committed.
+  virtual void SetCommittedAdditionalInterestedDataTypesCallback(
+      base::RepeatingCallback<void(const ModelTypeSet&)> callback) = 0;
 };
 
 }  // namespace syncer
diff --git a/components/sync/invalidations/interested_data_types_manager.cc b/components/sync/invalidations/interested_data_types_manager.cc
index 259cbc6..98f8274 100644
--- a/components/sync/invalidations/interested_data_types_manager.cc
+++ b/components/sync/invalidations/interested_data_types_manager.cc
@@ -6,8 +6,6 @@
 
 #include <utility>
 
-#include "base/bind.h"
-#include "base/callback_helpers.h"
 #include "base/feature_list.h"
 #include "components/sync/base/model_type.h"
 #include "components/sync/invalidations/interested_data_types_handler.h"
@@ -18,33 +16,44 @@
 InterestedDataTypesManager::InterestedDataTypesManager() = default;
 
 InterestedDataTypesManager::~InterestedDataTypesManager() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!interested_data_types_handler_);
 }
 
 void InterestedDataTypesManager::SetInterestedDataTypesHandler(
     InterestedDataTypesHandler* handler) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!interested_data_types_handler_ || !handler);
   interested_data_types_handler_ = handler;
 }
 
 absl::optional<ModelTypeSet>
 InterestedDataTypesManager::GetInterestedDataTypes() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return data_types_;
 }
 
 void InterestedDataTypesManager::SetInterestedDataTypes(
-    const ModelTypeSet& data_types,
-    SyncInvalidationsService::InterestedDataTypesAppliedCallback callback) {
-  ModelTypeSet new_data_types =
-      Difference(data_types, data_types_.value_or(ModelTypeSet()));
+    const ModelTypeSet& data_types) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(interested_data_types_handler_);
+
   data_types_ = data_types;
-  if (interested_data_types_handler_) {
-    // Do not send an additional GetUpdates request when invalidations are
-    // disabled.
-    interested_data_types_handler_->OnInterestedDataTypesChanged(
-        base::FeatureList::IsEnabled(switches::kUseSyncInvalidations)
-            ? base::BindOnce(std::move(callback), new_data_types)
-            : base::DoNothing());
+  interested_data_types_handler_->OnInterestedDataTypesChanged();
+}
+
+void InterestedDataTypesManager::
+    SetCommittedAdditionalInterestedDataTypesCallback(
+        SyncInvalidationsService::InterestedDataTypesAppliedCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(interested_data_types_handler_);
+
+  // Do not send an additional GetUpdates request when invalidations are
+  // disabled.
+  if (base::FeatureList::IsEnabled(switches::kUseSyncInvalidations)) {
+    interested_data_types_handler_
+        ->SetCommittedAdditionalInterestedDataTypesCallback(
+            std::move(callback));
   }
 }
 
diff --git a/components/sync/invalidations/interested_data_types_manager.h b/components/sync/invalidations/interested_data_types_manager.h
index 0d340e7..60203dee 100644
--- a/components/sync/invalidations/interested_data_types_manager.h
+++ b/components/sync/invalidations/interested_data_types_manager.h
@@ -7,6 +7,7 @@
 
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
+#include "base/sequence_checker.h"
 #include "components/sync/base/model_type.h"
 #include "components/sync/invalidations/sync_invalidations_service.h"
 
@@ -32,11 +33,13 @@
 
   // Set interested data types. The first call of the method initializes this
   // object.
-  void SetInterestedDataTypes(
-      const ModelTypeSet& data_types,
+  void SetInterestedDataTypes(const ModelTypeSet& data_types);
+
+  void SetCommittedAdditionalInterestedDataTypesCallback(
       SyncInvalidationsService::InterestedDataTypesAppliedCallback callback);
 
  private:
+  SEQUENCE_CHECKER(sequence_checker_);
   InterestedDataTypesHandler* interested_data_types_handler_ = nullptr;
 
   absl::optional<ModelTypeSet> data_types_;
diff --git a/components/sync/invalidations/interested_data_types_manager_unittest.cc b/components/sync/invalidations/interested_data_types_manager_unittest.cc
index c75d667..f694cdc 100644
--- a/components/sync/invalidations/interested_data_types_manager_unittest.cc
+++ b/components/sync/invalidations/interested_data_types_manager_unittest.cc
@@ -16,45 +16,48 @@
 
 class MockDataTypesHandler : public InterestedDataTypesHandler {
  public:
+  MOCK_METHOD(void, OnInterestedDataTypesChanged, (), (override));
   MOCK_METHOD(void,
-              OnInterestedDataTypesChanged,
-              (base::OnceClosure callback),
+              SetCommittedAdditionalInterestedDataTypesCallback,
+              (base::RepeatingCallback<void(const ModelTypeSet&)> callback),
               (override));
 };
 
 class InterestedDataTypesManagerTest : public testing::Test {
+ public:
+  InterestedDataTypesManagerTest() {
+    manager_.SetInterestedDataTypesHandler(&handler_);
+  }
+
+  ~InterestedDataTypesManagerTest() override {
+    manager_.SetInterestedDataTypesHandler(nullptr);
+  }
+
  protected:
+  testing::NiceMock<MockDataTypesHandler> handler_;
   InterestedDataTypesManager manager_;
 };
 
 TEST_F(InterestedDataTypesManagerTest, ShouldReturnGivenDataTypes) {
-  manager_.SetInterestedDataTypes(ModelTypeSet(BOOKMARKS, PREFERENCES),
-                                  base::DoNothing());
+  manager_.SetInterestedDataTypes(ModelTypeSet(BOOKMARKS, PREFERENCES));
   EXPECT_EQ(ModelTypeSet(BOOKMARKS, PREFERENCES),
             manager_.GetInterestedDataTypes());
-  manager_.SetInterestedDataTypes(ModelTypeSet(PREFERENCES, PASSWORDS),
-                                  base::DoNothing());
+  manager_.SetInterestedDataTypes(ModelTypeSet(PREFERENCES, PASSWORDS));
   EXPECT_EQ(ModelTypeSet(PREFERENCES, PASSWORDS),
             manager_.GetInterestedDataTypes());
 }
 
 TEST_F(InterestedDataTypesManagerTest, ShouldNotifyOnChange) {
-  testing::NiceMock<MockDataTypesHandler> handler;
-  manager_.SetInterestedDataTypesHandler(&handler);
-  EXPECT_CALL(handler, OnInterestedDataTypesChanged);
-  manager_.SetInterestedDataTypes(ModelTypeSet(PASSWORDS, AUTOFILL),
-                                  base::DoNothing());
-  manager_.SetInterestedDataTypesHandler(nullptr);
+  EXPECT_CALL(handler_, OnInterestedDataTypesChanged);
+  manager_.SetInterestedDataTypes(ModelTypeSet(PASSWORDS, AUTOFILL));
 }
 
 TEST_F(InterestedDataTypesManagerTest,
        ShouldInitializeOnFirstSetInterestedDataTypes) {
   EXPECT_FALSE(manager_.GetInterestedDataTypes().has_value());
-  manager_.SetInterestedDataTypes(ModelTypeSet(BOOKMARKS, PREFERENCES),
-                                  base::DoNothing());
+  manager_.SetInterestedDataTypes(ModelTypeSet(BOOKMARKS, PREFERENCES));
   EXPECT_TRUE(manager_.GetInterestedDataTypes().has_value());
-  manager_.SetInterestedDataTypes(ModelTypeSet(BOOKMARKS, PREFERENCES, NIGORI),
-                                  base::DoNothing());
+  manager_.SetInterestedDataTypes(ModelTypeSet(BOOKMARKS, PREFERENCES, NIGORI));
   EXPECT_TRUE(manager_.GetInterestedDataTypes().has_value());
 }
 
diff --git a/components/sync/invalidations/mock_sync_invalidations_service.h b/components/sync/invalidations/mock_sync_invalidations_service.h
index ccf556d..ef0cb86b 100644
--- a/components/sync/invalidations/mock_sync_invalidations_service.h
+++ b/components/sync/invalidations/mock_sync_invalidations_service.h
@@ -37,10 +37,10 @@
               GetInterestedDataTypes,
               (),
               (const));
+  MOCK_METHOD(void, SetInterestedDataTypes, (const ModelTypeSet& data_types));
   MOCK_METHOD(void,
-              SetInterestedDataTypes,
-              (const ModelTypeSet& data_types,
-               InterestedDataTypesAppliedCallback callback));
+              SetCommittedAdditionalInterestedDataTypesCallback,
+              (InterestedDataTypesAppliedCallback callback));
 };
 
 }  // namespace syncer
diff --git a/components/sync/invalidations/sync_invalidations_service.h b/components/sync/invalidations/sync_invalidations_service.h
index 69b56664..2e11947 100644
--- a/components/sync/invalidations/sync_invalidations_service.h
+++ b/components/sync/invalidations/sync_invalidations_service.h
@@ -27,7 +27,7 @@
   // Data types which are newly marked as interesting will be passed to the
   // callback.
   using InterestedDataTypesAppliedCallback =
-      base::OnceCallback<void(const ModelTypeSet&)>;
+      base::RepeatingCallback<void(const ModelTypeSet&)>;
 
   // Start or stop listening to invalidations.
   virtual void SetActive(bool active) = 0;
@@ -56,8 +56,8 @@
   // GetInterestedDataTypes() will return base::nullptr until
   // SetInterestedDataTypes() has been called at least once.
   virtual absl::optional<ModelTypeSet> GetInterestedDataTypes() const = 0;
-  virtual void SetInterestedDataTypes(
-      const ModelTypeSet& data_types,
+  virtual void SetInterestedDataTypes(const ModelTypeSet& data_types) = 0;
+  virtual void SetCommittedAdditionalInterestedDataTypesCallback(
       InterestedDataTypesAppliedCallback callback) = 0;
 };
 
diff --git a/components/sync/invalidations/sync_invalidations_service_impl.cc b/components/sync/invalidations/sync_invalidations_service_impl.cc
index 56ab5107..7461fea 100644
--- a/components/sync/invalidations/sync_invalidations_service_impl.cc
+++ b/components/sync/invalidations/sync_invalidations_service_impl.cc
@@ -80,9 +80,15 @@
 }
 
 void SyncInvalidationsServiceImpl::SetInterestedDataTypes(
-    const ModelTypeSet& data_types,
-    InterestedDataTypesAppliedCallback callback) {
-  data_types_manager_.SetInterestedDataTypes(data_types, std::move(callback));
+    const ModelTypeSet& data_types) {
+  data_types_manager_.SetInterestedDataTypes(data_types);
+}
+
+void SyncInvalidationsServiceImpl::
+    SetCommittedAdditionalInterestedDataTypesCallback(
+        InterestedDataTypesAppliedCallback callback) {
+  data_types_manager_.SetCommittedAdditionalInterestedDataTypesCallback(
+      std::move(callback));
 }
 
 void SyncInvalidationsServiceImpl::Shutdown() {
diff --git a/components/sync/invalidations/sync_invalidations_service_impl.h b/components/sync/invalidations/sync_invalidations_service_impl.h
index 0df1f70..aab9e33 100644
--- a/components/sync/invalidations/sync_invalidations_service_impl.h
+++ b/components/sync/invalidations/sync_invalidations_service_impl.h
@@ -41,8 +41,8 @@
   void SetInterestedDataTypesHandler(
       InterestedDataTypesHandler* handler) override;
   absl::optional<ModelTypeSet> GetInterestedDataTypes() const override;
-  void SetInterestedDataTypes(
-      const ModelTypeSet& data_types,
+  void SetInterestedDataTypes(const ModelTypeSet& data_types) override;
+  void SetCommittedAdditionalInterestedDataTypesCallback(
       InterestedDataTypesAppliedCallback callback) override;
 
   // KeyedService overrides.
diff --git a/components/sync/test/fake_server/fake_server.cc b/components/sync/test/fake_server/fake_server.cc
index 714ede8..9286004 100644
--- a/components/sync/test/fake_server/fake_server.cc
+++ b/components/sync/test/fake_server/fake_server.cc
@@ -329,6 +329,12 @@
       response->error_code() == sync_pb::SyncEnums::SUCCESS) {
     DCHECK(!response->has_client_command());
     *response->mutable_client_command() = client_command_;
+
+    if (message.has_get_updates()) {
+      for (Observer& observer : observers_) {
+        observer.OnSuccessfulGetUpdates();
+      }
+    }
   }
 
   return http_status_code;
diff --git a/components/sync/test/fake_server/fake_server.h b/components/sync/test/fake_server/fake_server.h
index 25d79dd..36c8ccd 100644
--- a/components/sync/test/fake_server/fake_server.h
+++ b/components/sync/test/fake_server/fake_server.h
@@ -56,12 +56,15 @@
  public:
   class Observer {
    public:
-    virtual ~Observer() {}
+    virtual ~Observer() = default;
 
     // Called after FakeServer has processed a successful commit. The types
     // updated as part of the commit are passed in |committed_model_types|.
     virtual void OnCommit(const std::string& committer_invalidator_client_id,
-                          syncer::ModelTypeSet committed_model_types) = 0;
+                          syncer::ModelTypeSet committed_model_types) {}
+
+    // Called after FakeServer has processed a successful get updates request.
+    virtual void OnSuccessfulGetUpdates() {}
   };
 
   FakeServer();
diff --git a/components/sync_device_info/device_info_sync_bridge.cc b/components/sync_device_info/device_info_sync_bridge.cc
index 15a264d..ba8bcf1b 100644
--- a/components/sync_device_info/device_info_sync_bridge.cc
+++ b/components/sync_device_info/device_info_sync_bridge.cc
@@ -338,23 +338,19 @@
   return local_device_info_provider_.get();
 }
 
-void DeviceInfoSyncBridge::RefreshLocalDeviceInfoIfNeeded(
-    base::OnceClosure callback) {
+void DeviceInfoSyncBridge::RefreshLocalDeviceInfoIfNeeded() {
   // Device info cannot be synced if the provider is not initialized. When it
   // gets initialized, local device info will be sent.
   if (!local_device_info_provider_->GetLocalDeviceInfo()) {
-    if (!callback.is_null()) {
-      device_info_synced_callback_list_.push_back(std::move(callback));
-    }
     return;
   }
 
-  if (ReconcileLocalAndStored()) {
-    // The device info has been changed.
-    if (!callback.is_null()) {
-      device_info_synced_callback_list_.push_back(std::move(callback));
-    }
-  }
+  ReconcileLocalAndStored();
+}
+
+void DeviceInfoSyncBridge::SetCommittedAdditionalInterestedDataTypesCallback(
+    base::RepeatingCallback<void(const ModelTypeSet&)> callback) {
+  new_interested_data_types_callback_ = std::move(callback);
 }
 
 void DeviceInfoSyncBridge::OnSyncStarting(
@@ -762,8 +758,9 @@
   DCHECK(iter != all_data_.end());
 
   // Convert |iter->second| to a DeviceInfo for comparison.
-  if (StoredDeviceInfoStillAccurate(SpecificsToModel(*iter->second).get(),
-                                    current_info)) {
+  std::unique_ptr<DeviceInfo> previous_device_info =
+      SpecificsToModel(*iter->second);
+  if (StoredDeviceInfoStillAccurate(previous_device_info.get(), current_info)) {
     if (pulse_timer_.IsRunning()) {
       // No need to update the |pulse_timer| since nothing has changed.
       return false;
@@ -779,6 +776,16 @@
     }
   }
 
+  // Initiate an additional GetUpdates request if there are new data types
+  // enabled (on successful commit).
+  const ModelTypeSet new_data_types =
+      Difference(current_info->interested_data_types(),
+                 previous_device_info->interested_data_types());
+  if (new_interested_data_types_callback_ && !new_data_types.Empty()) {
+    device_info_synced_callback_list_.push_back(
+        base::BindOnce(new_interested_data_types_callback_, new_data_types));
+  }
+
   // Either the local data was updated, or it's time for a pulse update.
   SendLocalData();
   return true;
diff --git a/components/sync_device_info/device_info_sync_bridge.h b/components/sync_device_info/device_info_sync_bridge.h
index d2dcb4e8..ec9104082 100644
--- a/components/sync_device_info/device_info_sync_bridge.h
+++ b/components/sync_device_info/device_info_sync_bridge.h
@@ -10,6 +10,7 @@
 #include <string>
 #include <vector>
 
+#include "base/callback_list.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
@@ -51,11 +52,17 @@
   // Refresh local copy of device info in memory, and informs sync of the
   // change. Used when the caller knows a property of local device info has
   // changed (e.g. SharingInfo), and must be sync-ed to other devices as soon as
-  // possible, without waiting for the periodic commits. |callback| will be
-  // called when device info is synced. The device info will be compared with
-  // the local copy. If the data has been updated, then it will be committed.
-  // Otherwise nothing happens and the |callback| will be never called.
-  void RefreshLocalDeviceInfoIfNeeded(base::OnceClosure callback);
+  // possible, without waiting for the periodic commits. The device info will be
+  // compared with the local copy. If the data has been updated, then it will be
+  // committed. Otherwise nothing happens.
+  void RefreshLocalDeviceInfoIfNeeded();
+
+  // The |callback| will be invoked on each successful commit with newly enabled
+  // data types list. This is needed to invoke an additional GetUpdates request
+  // for the data types which have been just enabled and subscribed for new
+  // invalidations.
+  void SetCommittedAdditionalInterestedDataTypesCallback(
+      base::RepeatingCallback<void(const ModelTypeSet&)> callback);
 
   // ModelTypeSyncBridge implementation.
   void OnSyncStarting(const DataTypeActivationRequest& request) override;
@@ -175,6 +182,11 @@
 
   std::vector<base::OnceClosure> device_info_synced_callback_list_;
 
+  // Called when a new interested data type list has been committed. Only newly
+  // enabled data types will be passed. May be empty.
+  base::RepeatingCallback<void(const ModelTypeSet&)>
+      new_interested_data_types_callback_;
+
   const std::unique_ptr<DeviceInfoPrefs> device_info_prefs_;
 
   base::WeakPtrFactory<DeviceInfoSyncBridge> weak_ptr_factory_{this};
diff --git a/components/sync_device_info/device_info_sync_bridge_unittest.cc b/components/sync_device_info/device_info_sync_bridge_unittest.cc
index cc7293b7..8dcfea8 100644
--- a/components/sync_device_info/device_info_sync_bridge_unittest.cc
+++ b/components/sync_device_info/device_info_sync_bridge_unittest.cc
@@ -567,9 +567,7 @@
 
   void ForcePulse() { bridge()->ForcePulseForTest(); }
 
-  void RefreshLocalDeviceInfo() {
-    bridge()->RefreshLocalDeviceInfoIfNeeded(base::DoNothing());
-  }
+  void RefreshLocalDeviceInfo() { bridge()->RefreshLocalDeviceInfoIfNeeded(); }
 
   void CommitToStoreAndWait(std::unique_ptr<WriteBatch> batch) {
     base::RunLoop loop;
@@ -1455,37 +1453,43 @@
   EnableSyncAndMergeInitialData(SyncMode::kFull);
 }
 
-TEST_F(DeviceInfoSyncBridgeTest, ShouldNotifyWhenDeviceInfoIsSynced) {
-  InitializeAndMergeInitialData(SyncMode::kFull);
+TEST_F(DeviceInfoSyncBridgeTest,
+       ShouldNotifyWhenAdditionalInterestedDataTypesSynced) {
+  InitializeAndPump();
+  local_device()->UpdateInterestedDataTypes({syncer::BOOKMARKS});
+  EnableSyncAndMergeInitialData(SyncMode::kFull);
 
-  base::MockOnceClosure callback;
-  ASSERT_THAT(local_device()->GetLocalDeviceInfo()->fcm_registration_token(),
-              IsEmpty());
-  local_device()->UpdateFCMRegistrationToken(
-      SyncInvalidationsInstanceIdTokenForSuffix(kLocalSuffix));
-  bridge()->RefreshLocalDeviceInfoIfNeeded(callback.Get());
+  base::MockRepeatingCallback<void(const ModelTypeSet&)> callback;
+  bridge()->SetCommittedAdditionalInterestedDataTypesCallback(callback.Get());
+  local_device()->UpdateInterestedDataTypes(
+      {syncer::BOOKMARKS, syncer::SESSIONS});
 
-  std::string guid = local_device()->GetLocalDeviceInfo()->guid();
-  EXPECT_CALL(*processor(), IsEntityUnsynced(guid)).WillOnce(Return(true));
-  EXPECT_CALL(callback, Run()).Times(0);
-  bridge()->ApplySyncChanges(bridge()->CreateMetadataChangeList(),
-                             EntityChangeList());
+  bridge()->RefreshLocalDeviceInfoIfNeeded();
 
+  const std::string guid = local_device()->GetLocalDeviceInfo()->guid();
   EXPECT_CALL(*processor(), IsEntityUnsynced(guid)).WillOnce(Return(false));
-  EXPECT_CALL(callback, Run());
+
+  EXPECT_CALL(callback, Run(ModelTypeSet(syncer::SESSIONS)));
   bridge()->ApplySyncChanges(bridge()->CreateMetadataChangeList(),
                              EntityChangeList());
 }
 
-TEST_F(DeviceInfoSyncBridgeTest, ShouldNotNotifyWhenDeviceInfoIsUnchanged) {
-  InitializeAndMergeInitialData(SyncMode::kFull);
+TEST_F(DeviceInfoSyncBridgeTest,
+       ShouldNotNotifyWithoutAdditionalInterestedDataTypes) {
+  InitializeAndPump();
+  local_device()->UpdateInterestedDataTypes(
+      {syncer::BOOKMARKS, syncer::SESSIONS});
+  EnableSyncAndMergeInitialData(SyncMode::kFull);
 
-  base::MockOnceClosure callback;
-  bridge()->RefreshLocalDeviceInfoIfNeeded(callback.Get());
+  base::MockRepeatingCallback<void(const ModelTypeSet&)> callback;
+  bridge()->SetCommittedAdditionalInterestedDataTypesCallback(callback.Get());
+  local_device()->UpdateInterestedDataTypes({syncer::BOOKMARKS});
+
+  bridge()->RefreshLocalDeviceInfoIfNeeded();
 
   std::string guid = local_device()->GetLocalDeviceInfo()->guid();
   EXPECT_CALL(*processor(), IsEntityUnsynced(guid)).WillOnce(Return(false));
-  EXPECT_CALL(callback, Run()).Times(0);
+  EXPECT_CALL(callback, Run).Times(0);
   bridge()->ApplySyncChanges(bridge()->CreateMetadataChangeList(),
                              EntityChangeList());
 }
diff --git a/components/sync_device_info/device_info_sync_service.h b/components/sync_device_info/device_info_sync_service.h
index f77a3baa..4a54d2c0 100644
--- a/components/sync_device_info/device_info_sync_service.h
+++ b/components/sync_device_info/device_info_sync_service.h
@@ -38,11 +38,8 @@
   // has changed (e.g. SharingInfo), and must be sync-ed to other devices as
   // soon as possible, without waiting for the periodic commits. The device info
   // will be compared to the local copy. If the device info has been actually
-  // changed, then it will be committed and the |callback| will be called when
-  // device info is synced. Otherwise nothing happens and the |callback| will
-  // never be called.
-  virtual void RefreshLocalDeviceInfo(
-      base::OnceClosure callback = base::DoNothing()) = 0;
+  // changed, then it will be committed. Otherwise nothing happens.
+  virtual void RefreshLocalDeviceInfo() = 0;
 };
 
 }  // namespace syncer
diff --git a/components/sync_device_info/device_info_sync_service_impl.cc b/components/sync_device_info/device_info_sync_service_impl.cc
index 3693e3e..ce55a57 100644
--- a/components/sync_device_info/device_info_sync_service_impl.cc
+++ b/components/sync_device_info/device_info_sync_service_impl.cc
@@ -50,13 +50,20 @@
   }
 }
 
-DeviceInfoSyncServiceImpl::~DeviceInfoSyncServiceImpl() {}
+DeviceInfoSyncServiceImpl::~DeviceInfoSyncServiceImpl() = default;
 
 LocalDeviceInfoProvider*
 DeviceInfoSyncServiceImpl::GetLocalDeviceInfoProvider() {
   return bridge_->GetLocalDeviceInfoProvider();
 }
 
+void DeviceInfoSyncServiceImpl::
+    SetCommittedAdditionalInterestedDataTypesCallback(
+        base::RepeatingCallback<void(const ModelTypeSet&)> callback) {
+  bridge_->SetCommittedAdditionalInterestedDataTypesCallback(
+      std::move(callback));
+}
+
 DeviceInfoTracker* DeviceInfoSyncServiceImpl::GetDeviceInfoTracker() {
   return bridge_.get();
 }
@@ -66,18 +73,16 @@
   return bridge_->change_processor()->GetControllerDelegate();
 }
 
-void DeviceInfoSyncServiceImpl::RefreshLocalDeviceInfo(
-    base::OnceClosure callback) {
-  bridge_->RefreshLocalDeviceInfoIfNeeded(std::move(callback));
+void DeviceInfoSyncServiceImpl::RefreshLocalDeviceInfo() {
+  bridge_->RefreshLocalDeviceInfoIfNeeded();
 }
 
 void DeviceInfoSyncServiceImpl::OnFCMRegistrationTokenChanged() {
   RefreshLocalDeviceInfo();
 }
 
-void DeviceInfoSyncServiceImpl::OnInterestedDataTypesChanged(
-    base::OnceClosure callback) {
-  RefreshLocalDeviceInfo(std::move(callback));
+void DeviceInfoSyncServiceImpl::OnInterestedDataTypesChanged() {
+  RefreshLocalDeviceInfo();
 }
 
 void DeviceInfoSyncServiceImpl::Shutdown() {
diff --git a/components/sync_device_info/device_info_sync_service_impl.h b/components/sync_device_info/device_info_sync_service_impl.h
index 7be70a9c..13ee00e 100644
--- a/components/sync_device_info/device_info_sync_service_impl.h
+++ b/components/sync_device_info/device_info_sync_service_impl.h
@@ -43,14 +43,15 @@
   LocalDeviceInfoProvider* GetLocalDeviceInfoProvider() override;
   DeviceInfoTracker* GetDeviceInfoTracker() override;
   base::WeakPtr<ModelTypeControllerDelegate> GetControllerDelegate() override;
-  void RefreshLocalDeviceInfo(
-      base::OnceClosure callback = base::DoNothing()) override;
+  void RefreshLocalDeviceInfo() override;
 
   // FCMRegistrationTokenObserver implementation.
   void OnFCMRegistrationTokenChanged() override;
 
   // InterestedDataTypesHandler implementation.
-  void OnInterestedDataTypesChanged(base::OnceClosure callback) override;
+  void OnInterestedDataTypesChanged() override;
+  void SetCommittedAdditionalInterestedDataTypesCallback(
+      base::RepeatingCallback<void(const ModelTypeSet&)> callback) override;
 
   // KeyedService overrides.
   void Shutdown() override;
diff --git a/components/sync_device_info/fake_device_info_sync_service.cc b/components/sync_device_info/fake_device_info_sync_service.cc
index 5c1cbb1..c0abede 100644
--- a/components/sync_device_info/fake_device_info_sync_service.cc
+++ b/components/sync_device_info/fake_device_info_sync_service.cc
@@ -25,12 +25,8 @@
   return fake_model_type_controller_delegate_.GetWeakPtr();
 }
 
-void FakeDeviceInfoSyncService::RefreshLocalDeviceInfo(
-    base::OnceClosure callback) {
+void FakeDeviceInfoSyncService::RefreshLocalDeviceInfo() {
   refresh_local_device_info_count_++;
-  if (!callback.is_null()) {
-    std::move(callback).Run();
-  }
 }
 
 int FakeDeviceInfoSyncService::RefreshLocalDeviceInfoCount() {
diff --git a/components/sync_device_info/fake_device_info_sync_service.h b/components/sync_device_info/fake_device_info_sync_service.h
index f1a51b5..a1e827a6 100644
--- a/components/sync_device_info/fake_device_info_sync_service.h
+++ b/components/sync_device_info/fake_device_info_sync_service.h
@@ -22,7 +22,7 @@
   FakeLocalDeviceInfoProvider* GetLocalDeviceInfoProvider() override;
   FakeDeviceInfoTracker* GetDeviceInfoTracker() override;
   base::WeakPtr<ModelTypeControllerDelegate> GetControllerDelegate() override;
-  void RefreshLocalDeviceInfo(base::OnceClosure callback) override;
+  void RefreshLocalDeviceInfo() override;
 
   // Returns number of times RefreshLocalDeviceInfo() has been called.
   int RefreshLocalDeviceInfoCount();
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl.cc b/components/viz/service/display_embedder/skia_output_surface_impl.cc
index c4e792b..34c992983 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl.cc
@@ -490,10 +490,11 @@
         frame.sub_buffer_rect ? *frame.sub_buffer_rect : gfx::Rect(size_);
     frame_buffer_damage_tracker_->SwappedWithDamage(damage_rect);
   }
+  pending_swaps_.push_back(current_buffer_modified_);
   current_buffer_modified_ = false;
 
-  pending_swaps_++;
-  if (AvailableBuffersLowerBound() > 0) {
+  int available_buffers_lower_bound = AvailableBuffersLowerBound();
+  if (available_buffers_lower_bound > 0) {
     consecutive_frames_with_extra_buffer_++;
   } else {
     consecutive_frames_with_extra_buffer_ = 0;
@@ -503,7 +504,7 @@
   bool release_one_buffer =
       capabilities_.use_dynamic_frame_buffer_allocation &&
       consecutive_frames_with_extra_buffer_ > kFreeBufferThreshold &&
-      AvailableBuffersLowerBound() > 0;
+      available_buffers_lower_bound > 0;
   if (release_one_buffer) {
     consecutive_frames_with_extra_buffer_ = 0;
     num_allocated_buffers_--;
@@ -974,8 +975,7 @@
       frame_buffer_damage_tracker_->ReallocatedFrameBuffers(size_);
   }
 
-  DCHECK_GT(pending_swaps_, 0);
-  pending_swaps_--;
+  pending_swaps_.pop_front();
 
   if (use_damage_area_from_skia_output_device_) {
     damage_of_current_buffer_ = params.frame_buffer_damage_area;
@@ -1270,9 +1270,14 @@
 }
 
 int SkiaOutputSurfaceImpl::AvailableBuffersLowerBound() const {
-  // Up to 1 buffer may be held for display, and each pending swap can use up
-  // to 1 buffer. Note the result can be negative.
-  return num_allocated_buffers_ - 1 - pending_swaps_;
+  // Up to 1 buffer may be held for display, and each pending swap with damage
+  // can use up to 1 buffer. Note the result can be negative.
+  int pending_swaps_with_damage = 0;
+  for (bool has_damage : pending_swaps_) {
+    if (has_damage)
+      pending_swaps_with_damage++;
+  }
+  return num_allocated_buffers_ - 1 - pending_swaps_with_damage;
 }
 
 bool SkiaOutputSurfaceImpl::ShouldCreateNewBufferForNextSwap() const {
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl.h b/components/viz/service/display_embedder/skia_output_surface_impl.h
index bd8d8c3..487150f 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl.h
+++ b/components/viz/service/display_embedder/skia_output_surface_impl.h
@@ -380,10 +380,11 @@
   // This way, this class knows exactly the number of allocated (once all work
   // posted to GPU thread are done).
   int num_allocated_buffers_ = 0;
-  // Number of SwapBuffers that has yet been matched with a
-  // DidSwapBuffersComplete. This is used to compute a lower bound on the number
-  // of available buffers on the GPU thread.
-  int pending_swaps_ = 0;
+  // For each SwapBuffers that has yet been matched with a
+  // DidSwapBuffersComplete, store whether that swap has damage to the main
+  // buffer. DidSwapBuffersComplete. This is used to compute a lower bound on
+  // the number of available buffers on the GPU thread.
+  base::circular_deque<bool> pending_swaps_;
   // Consecutive number of swaps where there is an extra buffer allocated. Used
   // as part of heuristic to decide when to release extra frame buffers.
   int consecutive_frames_with_extra_buffer_ = 0;
diff --git a/components/webdata/common/web_database.cc b/components/webdata/common/web_database.cc
index 410cd48..09fd36d 100644
--- a/components/webdata/common/web_database.cc
+++ b/components/webdata/common/web_database.cc
@@ -98,7 +98,9 @@
   // Clobber really old databases.
   static_assert(kDeprecatedVersionNumber < kCurrentVersionNumber,
                 "Deprecation version must be less than current");
-  sql::MetaTable::RazeIfDeprecated(&db_, kDeprecatedVersionNumber);
+  sql::MetaTable::RazeIfIncompatible(
+      &db_, /*lowest_supported_version=*/kDeprecatedVersionNumber + 1,
+      kCurrentVersionNumber);
 
   // Scope initialization in a transaction so we can't be partially
   // initialized.
diff --git a/content/browser/accessibility/accessibility_tree_formatter_mac_browsertest.mm b/content/browser/accessibility/accessibility_tree_formatter_mac_browsertest.mm
index c562e7de..c4919c5 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_mac_browsertest.mm
+++ b/content/browser/accessibility/accessibility_tree_formatter_mac_browsertest.mm
@@ -262,7 +262,7 @@
         SCRIPT}},
       {{"*", "*"}},
       R"~~(text_range={anchor: {:3, 0, down}, focus: {:3, 4, down}}
- textbox.AXTextMarkerRangeForUnorderedTextMarkers([text_range.anchor, text_range.focus])={anchor: {:3, 0, down}, focus: {:3, 4, down}}
+textbox.AXTextMarkerRangeForUnorderedTextMarkers([text_range.anchor, text_range.focus])={anchor: {:3, 0, down}, focus: {:3, 4, down}}
 )~~");
 }
 
@@ -440,7 +440,7 @@
                {{"text:= p.AXChildren[0]", SCRIPT}, {"text.AXRole", SCRIPT}},
                {{"*", "*"}},
                R"~~(text=:3
- text.AXRole='AXStaticText'
+text.AXRole='AXStaticText'
 )~~");
 }
 
diff --git a/content/browser/accessibility/accessibility_win_browsertest.cc b/content/browser/accessibility/accessibility_win_browsertest.cc
index fbf7fab3..0a01be8 100644
--- a/content/browser/accessibility/accessibility_win_browsertest.cc
+++ b/content/browser/accessibility/accessibility_win_browsertest.cc
@@ -5169,7 +5169,19 @@
   destroyed_watcher.Wait();
 }
 
-IN_PROC_BROWSER_TEST_F(AccessibilityWinUIABrowserTest,
+class AccessibilityWinUIASelectivelyEnabledBrowserTest
+    : public AccessibilityWinUIABrowserTest {
+ protected:
+  void SetUp() override {
+    scoped_feature_list_.InitAndEnableFeature(
+        features::kSelectiveUIAEnablement);
+
+    AccessibilityWinUIABrowserTest::SetUp();
+  }
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(AccessibilityWinUIASelectivelyEnabledBrowserTest,
                        RequestingTopLevelElementEnablesWebAccessibility) {
   EXPECT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
 
@@ -5190,10 +5202,44 @@
   uia->ElementFromHandle(hwnd, &root);
   ASSERT_NE(nullptr, root.Get());
 
+  // Native API support should now be enabled.
+  ui::AXMode expected_mode = ui::AXMode::kNativeAPIs;
+  EXPECT_EQ(expected_mode, content::BrowserAccessibilityStateImpl::GetInstance()
+                               ->GetAccessibilityMode());
+
+  // Now get the fragment root's first (only) child.
+  Microsoft::WRL::ComPtr<IUIAutomationTreeWalker> tree_walker;
+  uia->get_RawViewWalker(&tree_walker);
+  Microsoft::WRL::ComPtr<IUIAutomationElement> first_child;
+  tree_walker->GetFirstChildElement(root.Get(), &first_child);
+  ASSERT_NE(nullptr, first_child.Get());
+
+  base::win::ScopedBstr name;
+  ASSERT_HRESULT_SUCCEEDED(first_child->get_CurrentName(name.Receive()));
+
   // Web content accessibility support should now be enabled.
-  EXPECT_EQ(ui::kAXModeComplete,
-            content::BrowserAccessibilityStateImpl::GetInstance()
-                ->GetAccessibilityMode());
+  expected_mode |= ui::AXMode::kWebContents;
+  EXPECT_EQ(expected_mode, content::BrowserAccessibilityStateImpl::GetInstance()
+                               ->GetAccessibilityMode());
+
+  Microsoft::WRL::ComPtr<IUnknown> text_pattern_unknown;
+  ASSERT_HRESULT_SUCCEEDED(
+      first_child->GetCurrentPattern(UIA_TextPatternId, &text_pattern_unknown));
+  EXPECT_EQ(nullptr, text_pattern_unknown.Get());
+
+  // Now check that inline text box support is enabled as well.
+  expected_mode |= ui::AXMode::kInlineTextBoxes;
+  EXPECT_EQ(expected_mode, content::BrowserAccessibilityStateImpl::GetInstance()
+                               ->GetAccessibilityMode());
+
+  base::win::ScopedVariant variant;
+  ASSERT_HRESULT_SUCCEEDED(first_child->GetCurrentPropertyValue(
+      UIA_LabeledByPropertyId, variant.Receive()));
+
+  // Now check that we have complete accessibility support enabled.
+  expected_mode |= ui::AXMode::kScreenReader;
+  EXPECT_EQ(expected_mode, content::BrowserAccessibilityStateImpl::GetInstance()
+                               ->GetAccessibilityMode());
 }
 
 IN_PROC_BROWSER_TEST_F(AccessibilityWinUIABrowserTest,
diff --git a/content/browser/accessibility/browser_accessibility_state_impl_win.cc b/content/browser/accessibility/browser_accessibility_state_impl_win.cc
index 9c1ea74..a15418f 100644
--- a/content/browser/accessibility/browser_accessibility_state_impl_win.cc
+++ b/content/browser/accessibility/browser_accessibility_state_impl_win.cc
@@ -74,18 +74,38 @@
     BrowserAccessibilityStateImpl::GetInstance()->OnAccessibilityApiUsage();
   }
 
-  void OnUIAutomationUsed() override {
+  void OnBasicUIAutomationUsed() override {
+    AddAXModeForUIA(ui::AXMode::kNativeAPIs);
+  }
+
+  void OnAdvancedUIAutomationUsed() override {
+    AddAXModeForUIA(ui::AXMode::kWebContents);
+  }
+
+  void OnProbableUIAutomationScreenReaderDetected() override {
+    // Same as kAXModeComplete but without kHTML as it is not needed for UIA.
+    AddAXModeForUIA(ui::kAXModeCompleteNoHTML);
+  }
+
+  void OnTextPatternRequested() override {
+    AddAXModeForUIA(ui::AXMode::kInlineTextBoxes);
+  }
+
+  void AddAXModeForUIA(ui::AXMode mode) {
     DCHECK(::switches::IsExperimentalAccessibilityPlatformUIAEnabled());
 
     // Firing a UIA event can cause UIA to call back into our APIs, don't
     // consider this to be usage.
     if (firing_uia_events_)
       return;
+
     // UI Automation insulates providers from knowing about the client(s) asking
-    // for information. When UI Automation is requested, assume the presence of
-    // a full-fledged accessibility technology and enable full support.
+    // for information. When IsSelectiveUIAEnablement is Enabled, we turn on
+    // various parts of accessibility depending on what APIs have been called.
+    if (!features::IsSelectiveUIAEnablementEnabled())
+      mode = ui::kAXModeComplete;
     BrowserAccessibilityStateImpl::GetInstance()->AddAccessibilityModeFlags(
-        ui::kAXModeComplete);
+        mode);
     BrowserAccessibilityStateImpl::GetInstance()->OnAccessibilityApiUsage();
   }
 
diff --git a/content/browser/aggregation_service/public_key_parsing_utils.cc b/content/browser/aggregation_service/public_key_parsing_utils.cc
index ac2d309d..a401e87 100644
--- a/content/browser/aggregation_service/public_key_parsing_utils.cc
+++ b/content/browser/aggregation_service/public_key_parsing_utils.cc
@@ -36,7 +36,7 @@
 
   std::string latest_version;
 
-  for (const auto& kv : value.DictItems()) {
+  for (const auto kv : value.DictItems()) {
     const std::string& version = kv.first;
     if (version < latest_version)
       continue;
diff --git a/content/browser/browser_interface_binders.cc b/content/browser/browser_interface_binders.cc
index 7c211b13..4673cf57 100644
--- a/content/browser/browser_interface_binders.cc
+++ b/content/browser/browser_interface_binders.cc
@@ -429,6 +429,25 @@
       base::Unretained(host), method);
 }
 
+template <typename WorkerHost, typename Interface>
+base::RepeatingCallback<void(mojo::PendingReceiver<Interface>)>
+BindWorkerReceiverForStorageKey(
+    void (RenderProcessHostImpl::*method)(const blink::StorageKey&,
+                                          mojo::PendingReceiver<Interface>),
+    WorkerHost* host) {
+  return base::BindRepeating(
+      [](WorkerHost* host,
+         void (RenderProcessHostImpl::*method)(
+             const blink::StorageKey&, mojo::PendingReceiver<Interface>),
+         mojo::PendingReceiver<Interface> receiver) {
+        auto* process_host =
+            static_cast<RenderProcessHostImpl*>(host->GetProcessHost());
+        if (process_host)
+          (process_host->*method)(host->GetStorageKey(), std::move(receiver));
+      },
+      base::Unretained(host), method);
+}
+
 template <typename... Args>
 void RunOrPostTaskToBindServiceWorkerReceiver(
     ServiceWorkerHost* host,
@@ -506,6 +525,27 @@
       },
       base::Unretained(host), method);
 }
+
+template <typename Interface>
+base::RepeatingCallback<void(const ServiceWorkerVersionBaseInfo&,
+                             mojo::PendingReceiver<Interface>)>
+BindServiceWorkerReceiverForStorageKey(
+    void (RenderProcessHostImpl::*method)(const blink::StorageKey&,
+                                          mojo::PendingReceiver<Interface>),
+    ServiceWorkerHost* host) {
+  return base::BindRepeating(
+      [](ServiceWorkerHost* host,
+         void (RenderProcessHostImpl::*method)(
+             const blink::StorageKey&, mojo::PendingReceiver<Interface>),
+         const ServiceWorkerVersionBaseInfo& info,
+         mojo::PendingReceiver<Interface> receiver) {
+        RunOrPostTaskToBindServiceWorkerReceiver<
+            const blink::StorageKey&, mojo::PendingReceiver<Interface>>(
+            host, method, info.storage_key, std::move(receiver));
+      },
+      base::Unretained(host), method);
+}
+
 template <typename Interface>
 void EmptyBinderForFrame(RenderFrameHost* host,
                          mojo::PendingReceiver<Interface> receiver) {
@@ -1038,6 +1078,9 @@
   // render process host binders
   map->Add<media::mojom::VideoDecodePerfHistory>(BindWorkerReceiver(
       &RenderProcessHostImpl::BindVideoDecodePerfHistory, host));
+
+  map->Add<blink::mojom::IDBFactory>(BindWorkerReceiverForStorageKey(
+      &RenderProcessHostImpl::BindIndexedDB, host));
 }
 
 void PopulateBinderMapWithContext(
@@ -1054,8 +1097,6 @@
       &RenderProcessHostImpl::BindFileSystemAccessManager, host));
   map->Add<blink::mojom::NativeIOHost>(BindWorkerReceiverForOrigin(
       &RenderProcessHostImpl::BindNativeIOHost, host));
-  map->Add<blink::mojom::IDBFactory>(
-      BindWorkerReceiverForOrigin(&RenderProcessHostImpl::BindIndexedDB, host));
   map->Add<blink::mojom::BucketManagerHost>(BindWorkerReceiverForOrigin(
       &RenderProcessHostImpl::BindBucketManagerHost, host));
 
@@ -1128,6 +1169,8 @@
   // render process host binders
   map->Add<media::mojom::VideoDecodePerfHistory>(BindWorkerReceiver(
       &RenderProcessHostImpl::BindVideoDecodePerfHistory, host));
+  map->Add<blink::mojom::IDBFactory>(BindWorkerReceiverForStorageKey(
+      &RenderProcessHostImpl::BindIndexedDB, host));
 }
 
 void PopulateBinderMapWithContext(
@@ -1146,8 +1189,6 @@
       &RenderProcessHostImpl::BindNativeIOHost, host));
   map->Add<blink::mojom::WebSocketConnector>(BindWorkerReceiverForOrigin(
       &RenderProcessHostImpl::CreateWebSocketConnector, host));
-  map->Add<blink::mojom::IDBFactory>(
-      BindWorkerReceiverForOrigin(&RenderProcessHostImpl::BindIndexedDB, host));
   map->Add<blink::mojom::BucketManagerHost>(BindWorkerReceiverForOrigin(
       &RenderProcessHostImpl::BindBucketManagerHost, host));
 
@@ -1256,11 +1297,13 @@
       BindServiceWorkerReceiverForOrigin(
           &RenderProcessHostImpl::BindRestrictedCookieManagerForServiceWorker,
           host));
-  map->Add<blink::mojom::IDBFactory>(BindServiceWorkerReceiverForOrigin(
-      &RenderProcessHostImpl::BindIndexedDB, host));
   map->Add<blink::mojom::BucketManagerHost>(BindServiceWorkerReceiverForOrigin(
       &RenderProcessHostImpl::BindBucketManagerHost, host));
 
+  // render process host binders taking a storage key
+  map->Add<blink::mojom::IDBFactory>(BindServiceWorkerReceiverForStorageKey(
+      &RenderProcessHostImpl::BindIndexedDB, host));
+
   // render process host binders taking a frame id and an origin
   map->Add<blink::mojom::LockManager>(
       BindServiceWorkerReceiverForOriginAndFrameId(
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index fe7a49d..4da6b81 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -9256,7 +9256,7 @@
 
 void RenderFrameHostImpl::CreateIDBFactory(
     mojo::PendingReceiver<blink::mojom::IDBFactory> receiver) {
-  GetProcess()->BindIndexedDB(GetLastCommittedOrigin(), std::move(receiver));
+  GetProcess()->BindIndexedDB(storage_key(), std::move(receiver));
 }
 
 void RenderFrameHostImpl::CreateBucketManagerHost(
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 2bbf363..3f92d148 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -2151,20 +2151,18 @@
 }
 
 void RenderProcessHostImpl::BindIndexedDB(
-    const url::Origin& origin,
+    const blink::StorageKey& storage_key,
     mojo::PendingReceiver<blink::mojom::IDBFactory> receiver) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (origin.opaque()) {
+  if (storage_key.origin().opaque()) {
     // Opaque origins aren't valid for IndexedDB access, so we won't bind
     // |receiver| to |indexed_db_factory_|.  Return early here which
     // will cause |receiver| to be freed.  When |receiver| is
     // freed, we expect the pipe on the client will be closed.
     return;
   }
-  // TODO(https://crbug.com/1199077): Pass the real StorageKey into this
-  // function directly.
   storage_partition_impl_->GetIndexedDBControl().BindIndexedDB(
-      blink::StorageKey(origin), std::move(receiver));
+      storage_key, std::move(receiver));
 }
 
 void RenderProcessHostImpl::BindBucketManagerHost(
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index f0a01469..af612cd 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -281,7 +281,7 @@
       const blink::StorageKey& storage_key,
       mojo::PendingReceiver<blink::mojom::CacheStorage> receiver) override;
   void BindIndexedDB(
-      const url::Origin& origin,
+      const blink::StorageKey& storage_key,
       mojo::PendingReceiver<blink::mojom::IDBFactory> receiver) override;
   void BindBucketManagerHost(
       const url::Origin& origin,
diff --git a/content/browser/webid/federated_auth_request_impl.cc b/content/browser/webid/federated_auth_request_impl.cc
index 40137119..35cd8ce26 100644
--- a/content/browser/webid/federated_auth_request_impl.cc
+++ b/content/browser/webid/federated_auth_request_impl.cc
@@ -13,6 +13,7 @@
 #include "content/public/browser/federated_identity_request_permission_context_delegate.h"
 #include "content/public/browser/federated_identity_sharing_permission_context_delegate.h"
 #include "content/public/common/content_client.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 #include "url/url_constants.h"
 
 using blink::mojom::LogoutStatus;
@@ -22,6 +23,23 @@
 
 namespace content {
 
+namespace {
+std::string FormatRequestParams(const std::string& client_id,
+                                const std::string& nonce) {
+  std::string query;
+  // 'openid' scope is required for IdPs using OpenID Connect. We hope that IdPs
+  // using OAuth will ignore it, although some might return errors.
+  query += "scope=openid profile email";
+  if (client_id.length() > 0) {
+    query += "&client_id=" + client_id;
+  }
+  if (nonce.length() > 0) {
+    query += "&nonce=" + nonce;
+  }
+  return query;
+}
+}  // namespace
+
 FederatedAuthRequestImpl::FederatedAuthRequestImpl(
     RenderFrameHost* host,
     mojo::PendingReceiver<blink::mojom::FederatedAuthRequest> receiver)
@@ -57,7 +75,8 @@
 }
 
 void FederatedAuthRequestImpl::RequestIdToken(const GURL& provider,
-                                              const std::string& id_request,
+                                              const std::string& client_id,
+                                              const std::string& nonce,
                                               RequestMode mode,
                                               RequestIdTokenCallback callback) {
   if (logout_callback_ || auth_request_callback_) {
@@ -67,7 +86,8 @@
 
   auth_request_callback_ = std::move(callback);
   provider_ = provider;
-  id_request_ = id_request;
+  client_id_ = client_id;
+  nonce_ = nonce;
   mode_ = mode;
 
   network_manager_ = CreateNetworkManager(provider);
@@ -212,7 +232,7 @@
       }
 
       network_manager_->SendSigninRequest(
-          endpoints_.idp, id_request_,
+          endpoints_.idp, FormatRequestParams(client_id_, nonce_),
           base::BindOnce(&FederatedAuthRequestImpl::OnSigninResponseReceived,
                          weak_ptr_factory_.GetWeakPtr()));
       break;
@@ -398,7 +418,7 @@
   }
 
   network_manager_->SendTokenRequest(
-      endpoints_.token, account_id, id_request_,
+      endpoints_.token, account_id, FormatRequestParams(client_id_, nonce_),
       base::BindOnce(&FederatedAuthRequestImpl::OnTokenResponseReceived,
                      weak_ptr_factory_.GetWeakPtr()));
 }
diff --git a/content/browser/webid/federated_auth_request_impl.h b/content/browser/webid/federated_auth_request_impl.h
index f209d0b..0c6c0108 100644
--- a/content/browser/webid/federated_auth_request_impl.h
+++ b/content/browser/webid/federated_auth_request_impl.h
@@ -50,7 +50,8 @@
 
   // blink::mojom::FederatedAuthRequest:
   void RequestIdToken(const GURL& provider,
-                      const std::string& id_request,
+                      const std::string& client_id,
+                      const std::string& nonce,
                       blink::mojom::RequestMode mode,
                       RequestIdTokenCallback) override;
   void Logout(const std::vector<std::string>& logout_endpoints,
@@ -107,7 +108,8 @@
 
   // Parameters of auth request.
   GURL provider_;
-  std::string id_request_;
+  std::string client_id_;
+  std::string nonce_;
   blink::mojom::RequestMode mode_;
 
   // Fetched from the IDP well-known configuration.
diff --git a/content/browser/webid/federated_auth_request_impl_unittest.cc b/content/browser/webid/federated_auth_request_impl_unittest.cc
index 6b2882a..de0f0d8 100644
--- a/content/browser/webid/federated_auth_request_impl_unittest.cc
+++ b/content/browser/webid/federated_auth_request_impl_unittest.cc
@@ -48,9 +48,10 @@
 constexpr char kAccountsEndpoint[] = "https://idp.example/accounts";
 constexpr char kTokenEndpoint[] = "https://idp.example/token";
 constexpr char kSigninUrl[] = "https://idp.example/signin";
+constexpr char kClientId[] = "client_id_123";
+constexpr char kNonce[] = "nonce123";
 
 // Values will be added here as token introspection is implemented.
-constexpr char kAuthRequest[] = "";
 constexpr char kToken[] = "[not a real token]";
 constexpr char kEmptyToken[] = "";
 
@@ -65,7 +66,8 @@
 // Parameters for a call to RequestIdToken.
 typedef struct {
   const char* provider;
-  const char* request;
+  const char* client_id;
+  const char* nonce;
   RequestMode mode;
 } RequestParameters;
 
@@ -122,7 +124,7 @@
 
 static const AuthRequestTestCase kPermissionTestCases[]{
     {"Successful run with the IdP page loaded",
-     {kIdpTestOrigin, kAuthRequest, RequestMode::kPermission},
+     {kIdpTestOrigin, kClientId, kNonce, RequestMode::kPermission},
      {RequestIdTokenStatus::kSuccess, kToken},
      {kToken,
       UserApproval::kApproved,
@@ -134,7 +136,7 @@
       kMediatedNoop}},
 
     {"Successful run with a token response from the idp_endpoint",
-     {kIdpTestOrigin, kAuthRequest, RequestMode::kPermission},
+     {kIdpTestOrigin, kClientId, kNonce, RequestMode::kPermission},
      {RequestIdTokenStatus::kSuccess, kToken},
      {kToken,
       UserApproval::kApproved,
@@ -146,31 +148,31 @@
       kMediatedNoop}},
 
     {"Initial user permission denied",
-     {kIdpTestOrigin, kAuthRequest, RequestMode::kPermission},
+     {kIdpTestOrigin, kClientId, kNonce, RequestMode::kPermission},
      {RequestIdTokenStatus::kApprovalDeclined, kEmptyToken},
      {kToken, UserApproval::kDenied, absl::nullopt, "", "", "", kPermissionNoop,
       kMediatedNoop}},
 
     {"Wellknown file not found",
-     {kIdpTestOrigin, kAuthRequest, RequestMode::kPermission},
+     {kIdpTestOrigin, kClientId, kNonce, RequestMode::kPermission},
      {RequestIdTokenStatus::kErrorWebIdNotSupportedByProvider, kEmptyToken},
      {kToken, UserApproval::kApproved, FetchStatus::kWebIdNotSupported, "", "",
       "", kPermissionNoop, kMediatedNoop}},
 
     {"Wellknown fetch error",
-     {kIdpTestOrigin, kAuthRequest, RequestMode::kPermission},
+     {kIdpTestOrigin, kClientId, kNonce, RequestMode::kPermission},
      {RequestIdTokenStatus::kErrorFetchingWellKnown, kEmptyToken},
      {kToken, UserApproval::kApproved, FetchStatus::kFetchError, "", "", "",
       kPermissionNoop, kMediatedNoop}},
 
     {"Error parsing wellknown for Permission mode",
-     {kIdpTestOrigin, kAuthRequest, RequestMode::kPermission},
+     {kIdpTestOrigin, kClientId, kNonce, RequestMode::kPermission},
      {RequestIdTokenStatus::kErrorInvalidWellKnown, kEmptyToken},
      {kToken, UserApproval::kApproved, FetchStatus::kInvalidResponseError, "",
       kAccountsEndpoint, kTokenEndpoint, kPermissionNoop, kMediatedNoop}},
 
     {"Error reaching the idpendpoint",
-     {kIdpTestOrigin, kAuthRequest, RequestMode::kPermission},
+     {kIdpTestOrigin, kClientId, kNonce, RequestMode::kPermission},
      {RequestIdTokenStatus::kErrorFetchingSignin, kEmptyToken},
      {kToken,
       UserApproval::kApproved,
@@ -182,7 +184,7 @@
       kMediatedNoop}},
 
     {"Error parsing the idpendpoint response",
-     {kIdpTestOrigin, kAuthRequest, RequestMode::kPermission},
+     {kIdpTestOrigin, kClientId, kNonce, RequestMode::kPermission},
      {RequestIdTokenStatus::kErrorInvalidSigninResponse, kEmptyToken},
      {kToken,
       UserApproval::kApproved,
@@ -194,7 +196,7 @@
       kMediatedNoop}},
 
     {"IdP window closed before token provision",
-     {kIdpTestOrigin, kAuthRequest, RequestMode::kPermission},
+     {kIdpTestOrigin, kClientId, kNonce, RequestMode::kPermission},
      {RequestIdTokenStatus::kError, kEmptyToken},
      {kEmptyToken,
       UserApproval::kApproved,
@@ -206,7 +208,7 @@
       kMediatedNoop}},
 
     {"Token provision declined by user after IdP window closed",
-     {kIdpTestOrigin, kAuthRequest, RequestMode::kPermission},
+     {kIdpTestOrigin, kClientId, kNonce, RequestMode::kPermission},
      {RequestIdTokenStatus::kApprovalDeclined, kEmptyToken},
      {kToken,
       UserApproval::kApproved,
@@ -219,19 +221,19 @@
 
 static const AuthRequestTestCase kMediatedTestCases[]{
     {"Error parsing wellknown for Mediated mode missing token endpoint",
-     {kIdpTestOrigin, kAuthRequest, RequestMode::kMediated},
+     {kIdpTestOrigin, kClientId, kNonce, RequestMode::kMediated},
      {RequestIdTokenStatus::kErrorInvalidWellKnown, kEmptyToken},
      {kToken, absl::nullopt, FetchStatus::kInvalidResponseError, kIdpEndpoint,
       kAccountsEndpoint, "", kPermissionNoop, kMediatedNoop}},
 
     {"Error parsing wellknown for Mediated mode missing accounts endpoint",
-     {kIdpTestOrigin, kAuthRequest, RequestMode::kMediated},
+     {kIdpTestOrigin, kClientId, kNonce, RequestMode::kMediated},
      {RequestIdTokenStatus::kErrorInvalidWellKnown, kEmptyToken},
      {kToken, absl::nullopt, FetchStatus::kInvalidResponseError, kIdpEndpoint,
       "", kTokenEndpoint, kPermissionNoop, kMediatedNoop}},
 
     {"Error reaching Accounts endpoint",
-     {kIdpTestOrigin, kAuthRequest, RequestMode::kMediated},
+     {kIdpTestOrigin, kClientId, kNonce, RequestMode::kMediated},
      {RequestIdTokenStatus::kError, kEmptyToken},
      {kEmptyToken,
       absl::nullopt,
@@ -243,7 +245,7 @@
       {AccountsResponse::kNetError, kAccounts, absl::nullopt}}},
 
     {"Error parsing Accounts response",
-     {kIdpTestOrigin, kAuthRequest, RequestMode::kMediated},
+     {kIdpTestOrigin, kClientId, kNonce, RequestMode::kMediated},
      {RequestIdTokenStatus::kErrorInvalidAccountsResponse, kEmptyToken},
      {kToken,
       absl::nullopt,
@@ -255,7 +257,7 @@
       {AccountsResponse::kInvalidResponseError, kAccounts, absl::nullopt}}},
 
     {"Successful Mediated flow",
-     {kIdpTestOrigin, kAuthRequest, RequestMode::kMediated},
+     {kIdpTestOrigin, kClientId, kNonce, RequestMode::kMediated},
      {RequestIdTokenStatus::kSuccess, kToken},
      {kToken,
       absl::nullopt,
@@ -373,7 +375,8 @@
   }
 
   std::pair<RequestIdTokenStatus, absl::optional<std::string>>
-  PerformAuthRequest(const std::string& request,
+  PerformAuthRequest(const std::string& client_id,
+                     const std::string& nonce,
                      blink::mojom::RequestMode mode) {
     auth_request_impl_->SetNetworkManagerForTests(
         std::move(mock_request_manager_));
@@ -381,7 +384,7 @@
         std::move(mock_dialog_controller_));
 
     AuthRequestCallbackHelper auth_helper;
-    request_remote_->RequestIdToken(provider_, request, mode,
+    request_remote_->RequestIdToken(provider_, client_id, nonce, mode,
                                     auth_helper.callback());
     auth_helper.WaitForCallback();
     return std::make_pair(auth_helper.status(), auth_helper.token());
@@ -595,7 +598,8 @@
   CreateAuthRequest(GURL(test_case.inputs.provider));
   SetMockExpectations(test_case);
   auto auth_response =
-      PerformAuthRequest(test_case.inputs.request, test_case.inputs.mode);
+      PerformAuthRequest(test_case.inputs.client_id, test_case.inputs.nonce,
+                         test_case.inputs.mode);
   EXPECT_EQ(auth_response.first, test_case.expected.return_status);
   EXPECT_EQ(auth_response.second, test_case.expected.token);
 }
diff --git a/content/browser/webid/idp_network_request_manager.cc b/content/browser/webid/idp_network_request_manager.cc
index d435277..34f34e86 100644
--- a/content/browser/webid/idp_network_request_manager.cc
+++ b/content/browser/webid/idp_network_request_manager.cc
@@ -5,13 +5,13 @@
 #include "content/browser/webid/idp_network_request_manager.h"
 
 #include "base/base64.h"
-#include "base/base64url.h"
 #include "base/json/json_writer.h"
 #include "base/rand_util.h"
 #include "content/public/browser/identity_request_dialog_controller.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/storage_partition.h"
 #include "mojo/public/cpp/bindings/remote.h"
+#include "net/base/escape.h"
 #include "net/base/isolation_info.h"
 #include "net/cookies/site_for_cookies.h"
 #include "net/http/http_request_headers.h"
@@ -228,16 +228,9 @@
 
   signin_request_callback_ = std::move(callback);
 
-  // TODO(kenrb): A straight URL encoding isn't right. Add proper parsing.
-  // https://crbug.com/1141125.
-  std::string encoded_request;
-  base::Base64UrlEncode(base::StringPiece(request),
-                        base::Base64UrlEncodePolicy::INCLUDE_PADDING,
-                        &encoded_request);
+  std::string escaped_request = net::EscapeUrlEncodedData(request, true);
 
-  // TODO: Should this be a POST, rather than a GET using query parameters?
-  // https://crbug.com/1141125.
-  GURL target_url = GURL(signin_url.spec() + "?" + encoded_request);
+  GURL target_url = GURL(signin_url.spec() + "?" + escaped_request);
   auto resource_request =
       CreateCredentialedResourceRequest(target_url, relying_party_origin_);
   auto traffic_annotation = CreateTrafficAnnotation();
diff --git a/content/browser/webid/webid_browsertest.cc b/content/browser/webid/webid_browsertest.cc
index 55aeefac..e1492b63 100644
--- a/content/browser/webid/webid_browsertest.cc
+++ b/content/browser/webid/webid_browsertest.cc
@@ -200,7 +200,8 @@
           var x = (await navigator.id.get({
             provider: ')" +
            BaseIdpUrl() + R"(',
-            request: '[not a real request]',
+            client_id: 'client_id_1',
+            nonce: '12345',
           }));
           return x;
         }) ()
@@ -305,7 +306,8 @@
           var x = (await navigator.id.get({
             provider: 'http://idp.example)" +
                        base::NumberToString(https_server().port()) + R"(',
-            request: '[not a real request]',
+            client_id: 'client_id_1',
+            nonce: '12345',
           }));
           return x;
         }) ()
diff --git a/content/browser/worker_host/shared_worker_host.cc b/content/browser/worker_host/shared_worker_host.cc
index 8da06a4..dccba89c 100644
--- a/content/browser/worker_host/shared_worker_host.cc
+++ b/content/browser/worker_host/shared_worker_host.cc
@@ -350,7 +350,7 @@
 
 network::mojom::URLLoaderFactoryParamsPtr
 SharedWorkerHost::CreateNetworkFactoryParamsForSubresources() {
-  url::Origin origin = instance().storage_key().origin();
+  url::Origin origin = GetStorageKey().origin();
 
   // TODO(https://crbug.com/1060832): Implement COEP reporter for shared
   // workers.
@@ -432,9 +432,9 @@
   mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter>
       coep_reporter;
 
-  GetProcessHost()->BindCacheStorage(
-      cross_origin_embedder_policy(), std::move(coep_reporter),
-      instance().storage_key(), std::move(receiver));
+  GetProcessHost()->BindCacheStorage(cross_origin_embedder_policy(),
+                                     std::move(coep_reporter), GetStorageKey(),
+                                     std::move(receiver));
 }
 
 void SharedWorkerHost::CreateCodeCacheHost(
@@ -541,7 +541,11 @@
   // top-level browsing context, which shouldn't be use for SharedWorkers used
   // in iframes.
   return net::NetworkIsolationKey::ToDoUseTopFrameOriginAsWell(
-      instance().storage_key().origin());
+      GetStorageKey().origin());
+}
+
+const blink::StorageKey& SharedWorkerHost::GetStorageKey() const {
+  return instance().storage_key();
 }
 
 void SharedWorkerHost::ReportNoBinderForInterface(const std::string& error) {
diff --git a/content/browser/worker_host/shared_worker_host.h b/content/browser/worker_host/shared_worker_host.h
index 9154faf..864fb28 100644
--- a/content/browser/worker_host/shared_worker_host.h
+++ b/content/browser/worker_host/shared_worker_host.h
@@ -50,6 +50,7 @@
 namespace blink {
 class MessagePortChannel;
 class PendingURLLoaderFactoryBundle;
+class StorageKey;
 }  // namespace blink
 
 namespace content {
@@ -176,6 +177,8 @@
 
   net::NetworkIsolationKey GetNetworkIsolationKey() const;
 
+  const blink::StorageKey& GetStorageKey() const;
+
   const base::UnguessableToken& GetReportingSource() const {
     return reporting_source_;
   }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/VideoFullscreenOrientationLockTest.java b/content/public/android/javatests/src/org/chromium/content/browser/VideoFullscreenOrientationLockTest.java
index 73367178..5eb6aa1 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/VideoFullscreenOrientationLockTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/VideoFullscreenOrientationLockTest.java
@@ -23,6 +23,7 @@
 import org.chromium.base.test.util.CriteriaNotSatisfiedException;
 import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.DisabledTest;
+import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.content_public.browser.test.ContentJUnit4ClassRunner;
 import org.chromium.content_public.browser.test.util.DOMUtils;
@@ -194,6 +195,7 @@
     @Test
     @MediumTest
     @Restriction({UiRestriction.RESTRICTION_TYPE_PHONE})
+    @FlakyTest(message = "crbug.com/1228632")
     public void testExitFullscreenByRemovingVideo() throws Exception {
         // Start playback to guarantee it's properly loaded.
         Assert.assertTrue(DOMUtils.isMediaPaused(mActivityTestRule.getWebContents(), VIDEO_ID));
@@ -217,6 +219,7 @@
     @Test
     @MediumTest
     @Restriction({UiRestriction.RESTRICTION_TYPE_PHONE})
+    @FlakyTest(message = "crbug.com/1228632")
     public void testExitFullscreenWithNavigation() throws Exception {
         // Start playback to guarantee it's properly loaded.
         Assert.assertTrue(DOMUtils.isMediaPaused(mActivityTestRule.getWebContents(), VIDEO_ID));
diff --git a/content/public/browser/render_process_host.h b/content/public/browser/render_process_host.h
index 65cf9ea..143c111 100644
--- a/content/public/browser/render_process_host.h
+++ b/content/public/browser/render_process_host.h
@@ -491,7 +491,7 @@
   // |render_frame_id| is the frame associated with |receiver|, or
   // MSG_ROUTING_NONE if |receiver| is associated with a worker.
   virtual void BindIndexedDB(
-      const url::Origin& origin,
+      const blink::StorageKey& storage_key,
       mojo::PendingReceiver<blink::mojom::IDBFactory> receiver) = 0;
   virtual void BindBucketManagerHost(
       const url::Origin& origin,
diff --git a/content/public/test/mock_render_process_host.cc b/content/public/test/mock_render_process_host.cc
index b464b91a..60a2259a 100644
--- a/content/public/test/mock_render_process_host.cc
+++ b/content/public/test/mock_render_process_host.cc
@@ -454,7 +454,7 @@
 }
 
 void MockRenderProcessHost::BindIndexedDB(
-    const url::Origin& origin,
+    const blink::StorageKey& storage_key,
     mojo::PendingReceiver<blink::mojom::IDBFactory> receiver) {
   idb_factory_receiver_ = std::move(receiver);
 }
diff --git a/content/public/test/mock_render_process_host.h b/content/public/test/mock_render_process_host.h
index 89eef11..743ec88 100644
--- a/content/public/test/mock_render_process_host.h
+++ b/content/public/test/mock_render_process_host.h
@@ -180,7 +180,7 @@
       mojo::PendingReceiver<blink::mojom::FileSystemAccessManager> receiver)
       override {}
   void BindIndexedDB(
-      const url::Origin& origin,
+      const blink::StorageKey& storage_key,
       mojo::PendingReceiver<blink::mojom::IDBFactory> receiver) override;
   void BindBucketManagerHost(
       const url::Origin& origin,
diff --git a/content/test/data/gpu/webgpu-import-video.html b/content/test/data/gpu/webgpu-import-video.html
index 3134e5a4..98c642c 100644
--- a/content/test/data/gpu/webgpu-import-video.html
+++ b/content/test/data/gpu/webgpu-import-video.html
@@ -6,6 +6,7 @@
         video.src = './vc/teddy1_vp9_640x360_30fps.webm';
         video.loop = true;
         video.muted = true;
+        await video.play();
 
         // Test with two videos. The original implementation had a bug
         // where importing a second video would result in improper
@@ -14,6 +15,7 @@
         video2.src = './vc/teddy2_vp9_320x180_15fps.webm';
         video2.loop = true;
         video2.muted = true;
+        await video2.play();
 
         const adapter = navigator.gpu && await navigator.gpu.requestAdapter();
         const device = await adapter.requestDevice();
@@ -27,7 +29,31 @@
           format: swapChainFormat,
         });
 
+        // TODO: Use getBindGroupLayout. We can't right now because SPIRV-Cross
+        // doesn't reflect external textures correctly.
+        const bindGroupLayout = device.createBindGroupLayout({
+        entries: [
+          {
+            binding: 0,
+            visibility: GPUShaderStage.FRAGMENT,
+            sampler: {type: "filtering"}
+          },
+          {
+            binding: 1,
+            visibility: GPUShaderStage.FRAGMENT,
+            externalTexture: {}
+          },{
+            binding: 2,
+            visibility: GPUShaderStage.FRAGMENT,
+            externalTexture: {}
+          }
+        ],
+        });
+
+        const pipelineLayout = device.createPipelineLayout({bindGroupLayouts: [bindGroupLayout]});
+
         const pipeline = device.createRenderPipeline({
+          layout: pipelineLayout,
           vertex: {
             module: device.createShaderModule({
               code: `
@@ -37,8 +63,8 @@
 };
 
 [[stage(vertex)]]
-fn main([[builtin(vertex_index)]] VertexIndex : u32) -> VertexOutput {
-  let pos : array<vec3<f32>, 6> = array<vec3<f32>, 6>(
+fn main([[builtin(vertex_index)]] idx : u32) -> VertexOutput {
+  var pos = array<vec3<f32>, 6>(
     vec3<f32>( 1.0,  1.0, 0.0),
     vec3<f32>( 1.0, -1.0, 0.0),
     vec3<f32>(-1.0, -1.0, 0.0),
@@ -46,7 +72,7 @@
     vec3<f32>(-1.0, -1.0, 0.0),
     vec3<f32>(-1.0,  1.0, 0.0)
   );
-  let uv : array<vec2<f32>, 6> = array<vec2<f32>, 6>(
+  var uv  = array<vec2<f32>, 6>(
     vec2<f32>(1.0, 0.0),
     vec2<f32>(1.0, 2.0),
     vec2<f32>(0.0, 2.0),
@@ -56,8 +82,8 @@
   );
 
   var output : VertexOutput;
-  output.Position = vec4<f32>(pos[VertexIndex], 1.0);
-  output.fragUV = uv[VertexIndex];
+  output.Position = vec4<f32>(pos[idx], 1.0);
+  output.fragUV = uv[idx];
   return output;
 }
 `,
@@ -68,17 +94,17 @@
             module: device.createShaderModule({
               code: `
 [[binding(0), group(0)]] var mySampler: sampler;
-[[binding(1), group(0)]] var myTexture: texture_2d<f32>;
-[[binding(2), group(0)]] var myTexture2: texture_2d<f32>;
+[[binding(1), group(0)]] var myTexture: texture_external;
+[[binding(2), group(0)]] var myTexture2: texture_external;
 
 [[stage(fragment)]]
 fn main([[location(0)]] fragUV : vec2<f32>) -> [[location(0)]] vec4<f32> {
   var result : vec4<f32>;
   if (fragUV.y <= 1.0) {
-    result = textureSample(myTexture, mySampler, fragUV);
+    result = textureSampleLevel(myTexture, mySampler, fragUV);
   } else {
     var uv : vec2<f32> = vec2<f32>(fragUV.x, fragUV.y - 1.0);
-    result = textureSample(myTexture2, mySampler, uv);
+    result = textureSampleLevel(myTexture2, mySampler, uv);
   }
   return result;
 }
@@ -94,15 +120,12 @@
           },
         });
 
-        const linearSampler = device.createSampler({
-          magFilter: 'linear',
-          minFilter: 'linear',
-        });
+        const linearSampler = device.createSampler();
 
         const renderPassDescriptor = {
           colorAttachments: [
             {
-              attachment: undefined, // Assigned later
+              view: undefined, // Assigned later
               loadValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },
               storeOp: 'store',
             },
@@ -110,18 +133,17 @@
         };
 
         function frame() {
-          renderPassDescriptor.colorAttachments[0].attachment = swapChain
+          renderPassDescriptor.colorAttachments[0].view = swapChain
             .getCurrentTexture()
             .createView();
 
-          const videoTexture = device.experimentalImportTexture(
-            video, GPUTextureUsage.SAMPLED);
-
-          const videoTexture2 = device.experimentalImportTexture(
-            video2, GPUTextureUsage.SAMPLED);
+         const externalTextureDescriptor =  {source: video};
+         const externalTextureDescriptor2 =  {source: video2};
+         const externalTexture = device.importExternalTexture(externalTextureDescriptor);
+         const externalTexture2 = device.importExternalTexture(externalTextureDescriptor2);
 
           const bindGroup = device.createBindGroup({
-            layout: pipeline.getBindGroupLayout(0),
+            layout: bindGroupLayout,
             entries: [
               {
                 binding: 0,
@@ -129,15 +151,14 @@
               },
               {
                 binding: 1,
-                resource: videoTexture.createView(),
+                resource: externalTexture,
               },
               {
                 binding: 2,
-                resource: videoTexture2.createView(),
-              },
+                resource: externalTexture2,
+              }
             ],
           });
-
           const commandEncoder = device.createCommandEncoder();
           const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
           passEncoder.setPipeline(pipeline);
@@ -146,15 +167,9 @@
           passEncoder.endPass();
           device.queue.submit([commandEncoder.finish()]);
 
-          // Destroy the texture after submit to promptly recycle resources.
-          videoTexture.destroy();
-          videoTexture2.destroy();
-
           requestAnimationFrame(frame);
         }
 
-        await video.play();
-        await video2.play();
         requestAnimationFrame(frame);
     </script>
   </body>
diff --git a/extensions/browser/api/messaging/extension_message_port.cc b/extensions/browser/api/messaging/extension_message_port.cc
index 6821512..d8cdee47 100644
--- a/extensions/browser/api/messaging/extension_message_port.cc
+++ b/extensions/browser/api/messaging/extension_message_port.cc
@@ -170,6 +170,11 @@
   CHECK(tab);
   frame_tracker_->TrackTabFrames(tab);
   if (include_child_frames) {
+    // TODO(https://crbug.com/1227787) We don't yet support MParch so make sure
+    // `include_child_frames` is only provided for primary pages. If `rfh`
+    // belongs to a non-primary page, then the ForEachFrame iteration below
+    // would actually correspond to a different page than `rfh`'s page.
+    CHECK(rfh->GetPage().IsPrimary());
     tab->ForEachFrame(base::BindRepeating(&ExtensionMessagePort::RegisterFrame,
                                           base::Unretained(this)));
   } else {
diff --git a/fuchsia/engine/web_instance_host/web_instance_host.cc b/fuchsia/engine/web_instance_host/web_instance_host.cc
index 07bda08f..df9b7e3 100644
--- a/fuchsia/engine/web_instance_host/web_instance_host.cc
+++ b/fuchsia/engine/web_instance_host/web_instance_host.cc
@@ -373,7 +373,7 @@
       switches::kWebglMSAASampleCount,
   };
 
-  for (const auto& arg : args->DictItems()) {
+  for (const auto arg : args->DictItems()) {
     if (!base::Contains(kAllowedArgs, arg.first)) {
       // TODO(https://crbug.com/1032439): Increase severity and return false
       // once we have a mechanism for soft transitions of supported arguments.
diff --git a/gpu/command_buffer/service/raster_decoder.cc b/gpu/command_buffer/service/raster_decoder.cc
index 0df7d28..2ada6fc 100644
--- a/gpu/command_buffer/service/raster_decoder.cc
+++ b/gpu/command_buffer/service/raster_decoder.cc
@@ -2819,33 +2819,6 @@
     return;
   }
 
-  std::vector<GrBackendSemaphore> begin_semaphores;
-
-  std::unique_ptr<SharedImageRepresentationSkia::ScopedReadAccess>
-      source_scoped_access = source_shared_image->BeginScopedReadAccess(
-          &begin_semaphores, nullptr);
-
-  if (!begin_semaphores.empty()) {
-    bool result = shared_context_state_->gr_context()->wait(
-        begin_semaphores.size(), begin_semaphores.data(),
-        /*deleteSemaphoresAfterWait=*/false);
-    DCHECK(result);
-  }
-
-  if (!source_scoped_access) {
-    LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glReadbackImagePixels",
-                       "Source shared image is not accessible");
-    return;
-  }
-
-  auto sk_image =
-      source_scoped_access->CreateSkImage(shared_context_state_->gr_context());
-  if (!sk_image) {
-    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glReadbackImagePixels",
-                       "Couldn't create SkImage for reading.");
-    return;
-  }
-
   size_t byte_size = dst_info.computeByteSize(row_bytes);
   if (byte_size > UINT32_MAX) {
     LOCAL_SET_GL_ERROR(
@@ -2871,6 +2844,47 @@
     return;
   }
 
+  std::vector<GrBackendSemaphore> begin_semaphores;
+  std::vector<GrBackendSemaphore> end_semaphores;
+
+  std::unique_ptr<SharedImageRepresentationSkia::ScopedReadAccess>
+      source_scoped_access = source_shared_image->BeginScopedReadAccess(
+          &begin_semaphores, &end_semaphores);
+
+  if (!source_scoped_access) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glReadbackImagePixels",
+                       "Source shared image is not accessible");
+    return;
+  }
+
+  if (!begin_semaphores.empty()) {
+    bool wait_result = shared_context_state_->gr_context()->wait(
+        begin_semaphores.size(), begin_semaphores.data(),
+        /*deleteSemaphoresAfterWait=*/false);
+    DCHECK(wait_result);
+  }
+
+  if (!end_semaphores.empty()) {
+    // Ask skia to signal |end_semaphores| here, since we will synchronized
+    // read pixels from the shared image.
+    GrFlushInfo flush_info = {
+        .fNumSemaphores = end_semaphores.size(),
+        .fSignalSemaphores = end_semaphores.data(),
+    };
+    AddVulkanCleanupTaskForSkiaFlush(
+        shared_context_state_->vk_context_provider(), &flush_info);
+    auto flush_result = shared_context_state_->gr_context()->flush(flush_info);
+    DCHECK(flush_result == GrSemaphoresSubmitted::kYes);
+  }
+
+  auto sk_image =
+      source_scoped_access->CreateSkImage(shared_context_state_->gr_context());
+  if (!sk_image) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glReadbackImagePixels",
+                       "Couldn't create SkImage for reading.");
+    return;
+  }
+
   bool success =
       sk_image->readPixels(dst_info, pixel_address, row_bytes, src_x, src_y);
   if (!success) {
diff --git a/headless/BUILD.gn b/headless/BUILD.gn
index 2b5bd5a1..f9e3e8b 100644
--- a/headless/BUILD.gn
+++ b/headless/BUILD.gn
@@ -264,8 +264,8 @@
 # |headless_non_renderer| components.
 source_set("headless_shared_sources") {
   visibility = [
-    "//headless:headless",
-    "//headless:headless_non_renderer",
+    ":headless",
+    ":headless_non_renderer",
   ]
   defines = []
 
@@ -309,10 +309,13 @@
   ]
 
   if (!is_fuchsia) {
-    deps += [ "//components/crash/content/browser" ]
+    deps += [
+      "//components/crash/content/browser",
+      "//components/crash/core/app",
+    ]
   }
-  if (is_component_build && is_win) {
-    deps += [ "//components/crash/core/app:crash_export_thunks" ]
+  if (is_win) {
+    deps += [ "//sandbox" ]
   }
 
   configs += [ ":inside_headless_component" ]
@@ -434,16 +437,26 @@
     ":headless_shared_sources",
     ":version_header",
     "//base:base_static",
+    "//build:branding_buildflags",
     "//build:chromeos_buildflags",
     "//components/cookie_config",
+    "//components/embedder_support",
     "//components/keyed_service/content",
+    "//components/policy:policy_code_generate",
+    "//components/policy/core/browser",
+    "//components/policy/core/common:common_constants",
+    "//components/pref_registry",
+    "//components/prefs",
     "//components/profile_metrics",
     "//components/security_state/core",
+    "//content/public/app",
     "//content/public/browser",
     "//content/public/common",
+    "//printing/buildflags",
     "//services/cert_verifier/public/mojom",
     "//services/device/public/cpp/geolocation",
     "//services/service_manager/public/cpp",
+    "//third_party/inspector_protocol:crdtp",
     "//ui/base",
     "//ui/base/clipboard",
     "//ui/compositor",
@@ -454,7 +467,12 @@
   ]
 
   if (enable_basic_printing) {
-    deps += [ "//components/printing/browser" ]
+    deps += [
+      "//components/printing/browser",
+      "//components/printing/common:mojo_interfaces",
+      "//printing",
+      "//printing/mojom",
+    ]
   }
 
   if (is_component_build) {
@@ -492,10 +510,10 @@
     ]
 
     if (!is_fuchsia) {
-      deps += [ "//components/crash/content/browser" ]
-    }
-    if (is_win) {
-      deps += [ "//components/crash/core/app:crash_export_thunks" ]
+      deps += [
+        "//components/crash/content/browser",
+        "//components/crash/core/app",
+      ]
     }
 
     if (enable_basic_printing) {
@@ -507,8 +525,15 @@
       ]
     }
 
+    if (headless_use_prefs) {
+      deps += [ "//components/os_crypt" ]
+    }
+
     if (headless_use_policy) {
-      deps += [ "//components/policy/content" ]
+      deps += [
+        "//components/policy/content",
+        "//components/user_prefs",
+      ]
     }
   }
 
@@ -593,11 +618,24 @@
 
     deps = [
       ":headless",
+      "//build:chromeos_buildflags",
       "//components/crash/core/common",
+      "//components/security_state/content",
+      "//components/security_state/core",
+      "//content/public/app",
+      "//content/public/browser",
+      "//content/public/common",
+      "//content/public/renderer",
+      "//content/public/utility",
+      "//printing/buildflags",
       "//third_party/blink/public:blink_headers",
       "//ui/base",
+      "//ui/compositor",
       "//v8",
     ]
+    if (use_ozone) {
+      deps += [ "//ui/ozone" ]
+    }
     if (enable_basic_printing) {
       deps += [
         "//components/printing/renderer",
@@ -614,6 +652,10 @@
         "$root_gen_dir/headless/embedded_resource_pak.h",
       ]
     }
+
+    if (is_mac || is_win || is_linux || is_chromeos) {
+      deps += [ "//components/crash/core/app" ]
+    }
   }
 } else {
   # For component builds all dependencies are already included in the headless
@@ -660,6 +702,8 @@
     sources += [ "lib/browser/headless_printing_unittest.cc" ]
     deps += [
       "//components/printing/browser",
+      "//printing",
+      "//printing/buildflags",
       "//third_party/blink/public:blink",
     ]
   }
@@ -737,8 +781,12 @@
     ":headless_shell_lib",
     "//base",
     "//cc:test_support",
+    "//components/policy/core/browser",
     "//components/security_state/content",
+    "//content/test:browsertest_support",
     "//content/test:test_support",
+    "//net:test_support",
+    "//printing/buildflags",
     "//services/network/public/mojom",
     "//testing/gmock",
     "//testing/gtest",
@@ -753,6 +801,7 @@
     deps += [
       "//components/printing/browser",
       "//pdf",
+      "//printing",
     ]
   }
 
@@ -777,12 +826,19 @@
     deps = [
       ":headless_non_renderer",
       "//build:branding_buildflags",
+      "//components/crash/core/app:run_as_crashpad_handler",
+      "//components/embedder_support",
       "//content:sandbox_helper_win",
+      "//content/public/app",
       "//content/public/browser",
       "//content/public/common",
       "//net",
+      "//printing/buildflags",
       "//sandbox",
     ]
+    if (headless_use_policy) {
+      deps += [ "//components/policy/content" ]
+    }
     configs += [ ":headless_defines_config" ]
   }
 }
@@ -809,11 +865,15 @@
   deps = [
     ":headless_renderer",
     "//build:branding_buildflags",
+    "//components/embedder_support",
     "//components/security_state/content",
+    "//content",
     "//content/public/app",
     "//content/public/browser",
     "//content/public/child:child",
     "//content/public/common",
+    "//content/public/utility",
+    "//printing/buildflags",
   ]
 
   public_deps = [ "//base" ]
@@ -843,7 +903,6 @@
     defines = [ "HEADLESS_USE_CRASHPAD" ]
 
     deps += [
-      "//components/crash/core/app:crash_export_thunks",
       "//components/crash/core/app:run_as_crashpad_handler",
       "//content:sandbox_helper_win",
       "//sandbox",
@@ -854,6 +913,10 @@
     deps += [ "//components/os_crypt" ]
   }
 
+  if (is_win || (is_posix && !is_mac)) {
+    deps += [ "//components/crash/core/app" ]
+  }
+
   configs += [ ":headless_defines_config" ]
 }
 
@@ -881,7 +944,10 @@
   }
 
   if (is_win) {
-    deps += [ "//build/win:default_exe_manifest" ]
+    deps += [
+      "//build/win:default_exe_manifest",
+      "//content/public/app",
+    ]
   }
 
   if (is_mac) {
@@ -906,8 +972,15 @@
 
   deps = [
     ":headless_shell_lib",
+    "//content",
+    "//sandbox",
     "//skia",  # we need this to override font render hinting in headless build
+    "//ui/gfx/geometry",
   ]
 
+  if (is_win) {
+    deps += [ "//content/public/app" ]
+  }
+
   configs += [ ":headless_defines_config" ]
 }
diff --git a/headless/app/headless_shell.cc b/headless/app/headless_shell.cc
index f15a5bd7..3cd013e 100644
--- a/headless/app/headless_shell.cc
+++ b/headless/app/headless_shell.cc
@@ -52,13 +52,13 @@
 #include "ui/gfx/geometry/size.h"
 
 #if defined(OS_WIN)
-#include "components/crash/core/app/crash_switches.h"
+#include "components/crash/core/app/crash_switches.h"  // nogncheck
 #include "components/crash/core/app/run_as_crashpad_handler_win.h"
 #include "sandbox/win/src/sandbox_types.h"
 #endif
 
 #if defined(OS_MAC)
-#include "components/os_crypt/os_crypt_switches.h"
+#include "components/os_crypt/os_crypt_switches.h"  // nogncheck
 #endif
 
 #if defined(HEADLESS_USE_POLICY)
diff --git a/headless/app/headless_shell_main.cc b/headless/app/headless_shell_main.cc
index a51bc44..f2457fa 100644
--- a/headless/app/headless_shell_main.cc
+++ b/headless/app/headless_shell_main.cc
@@ -7,7 +7,7 @@
 
 #if defined(OS_WIN)
 #include "content/public/app/sandbox_helper_win.h"
-#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/sandbox_types.h"  // nogncheck
 #elif defined(OS_MAC)
 #include "base/check.h"
 #include "sandbox/mac/seatbelt_exec.h"
diff --git a/headless/lib/browser/headless_browser_context_impl.cc b/headless/lib/browser/headless_browser_context_impl.cc
index 86f66e5..d5cfa9e 100644
--- a/headless/lib/browser/headless_browser_context_impl.cc
+++ b/headless/lib/browser/headless_browser_context_impl.cc
@@ -27,7 +27,7 @@
 #include "ui/base/resource/resource_bundle.h"
 
 #if defined(HEADLESS_USE_POLICY)
-#include "components/user_prefs/user_prefs.h"
+#include "components/user_prefs/user_prefs.h"  // nogncheck
 #endif
 
 namespace headless {
diff --git a/headless/lib/browser/headless_browser_main_parts.cc b/headless/lib/browser/headless_browser_main_parts.cc
index b6d0091..e8d5d3e7c 100644
--- a/headless/lib/browser/headless_browser_main_parts.cc
+++ b/headless/lib/browser/headless_browser_main_parts.cc
@@ -14,7 +14,7 @@
 #include "headless/lib/browser/headless_screen.h"
 
 #if defined(HEADLESS_USE_PREFS)
-#include "components/os_crypt/os_crypt.h"
+#include "components/os_crypt/os_crypt.h"  // nogncheck
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/in_memory_pref_store.h"
 #include "components/prefs/json_pref_store.h"
diff --git a/headless/lib/browser/headless_content_browser_client.cc b/headless/lib/browser/headless_content_browser_client.cc
index a828ac9a..054f7a7 100644
--- a/headless/lib/browser/headless_content_browser_client.cc
+++ b/headless/lib/browser/headless_content_browser_client.cc
@@ -53,7 +53,7 @@
 
 #if defined(HEADLESS_USE_POLICY)
 #include "components/policy/content/policy_blocklist_navigation_throttle.h"
-#include "components/policy/core/common/policy_service.h"
+#include "components/policy/core/common/policy_service.h"  // nogncheck http://crbug.com/1227148
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/navigation_throttle.h"
 #endif  // defined(HEADLESS_USE_POLICY)
diff --git a/headless/lib/browser/headless_request_context_manager.cc b/headless/lib/browser/headless_request_context_manager.cc
index 3b54e857..fa0e7e7 100644
--- a/headless/lib/browser/headless_request_context_manager.cc
+++ b/headless/lib/browser/headless_request_context_manager.cc
@@ -26,7 +26,7 @@
 #include "services/network/url_request_context_builder_mojo.h"
 
 #if defined(HEADLESS_USE_PREFS)
-#include "components/os_crypt/os_crypt.h"
+#include "components/os_crypt/os_crypt.h"  // nogncheck
 #include "content/public/common/network_service_util.h"
 #endif
 
diff --git a/headless/lib/browser/policy/headless_browser_policy_connector.cc b/headless/lib/browser/policy/headless_browser_policy_connector.cc
index e36021a5..ee63ed99 100644
--- a/headless/lib/browser/policy/headless_browser_policy_connector.cc
+++ b/headless/lib/browser/policy/headless_browser_policy_connector.cc
@@ -14,9 +14,9 @@
 #include "base/task/thread_pool.h"
 #include "build/branding_buildflags.h"
 #include "build/build_config.h"
-#include "components/policy/core/browser/configuration_policy_handler.h"
-#include "components/policy/core/browser/url_blocklist_policy_handler.h"
-#include "components/policy/core/common/async_policy_provider.h"
+#include "components/policy/core/browser/configuration_policy_handler.h"  // nogncheck http://crbug.com/1227148
+#include "components/policy/core/browser/url_blocklist_policy_handler.h"  // nogncheck http://crbug.com/1227148
+#include "components/policy/core/common/async_policy_provider.h"  // nogncheck http://crbug.com/1227148
 #include "components/policy/core/common/policy_pref_names.h"
 #include "components/policy/policy_constants.h"
 #include "headless/lib/browser/headless_pref_names.h"
@@ -33,7 +33,7 @@
 #include "components/policy/core/common/policy_loader_mac.h"
 #include "components/policy/core/common/preferences_mac.h"
 #elif defined(OS_POSIX) && !defined(OS_ANDROID)
-#include "components/policy/core/common/config_dir_policy_loader.h"
+#include "components/policy/core/common/config_dir_policy_loader.h"  // nogncheck http://crbug.com/1227148
 #endif
 
 namespace policy {
diff --git a/headless/lib/browser/policy/headless_browser_policy_connector.h b/headless/lib/browser/policy/headless_browser_policy_connector.h
index b067c01..e15bba06 100644
--- a/headless/lib/browser/policy/headless_browser_policy_connector.h
+++ b/headless/lib/browser/policy/headless_browser_policy_connector.h
@@ -6,8 +6,8 @@
 #define HEADLESS_LIB_BROWSER_POLICY_HEADLESS_BROWSER_POLICY_CONNECTOR_H_
 
 #include "base/memory/ref_counted.h"
-#include "components/policy/core/browser/browser_policy_connector.h"
-#include "components/policy/core/browser/configuration_policy_pref_store.h"
+#include "components/policy/core/browser/browser_policy_connector.h"  // nogncheck http://crbug.com/1227148
+#include "components/policy/core/browser/configuration_policy_pref_store.h"  // nogncheck http://crbug.com/1227148
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace policy {
diff --git a/headless/lib/browser/policy/headless_mode_policy.h b/headless/lib/browser/policy/headless_mode_policy.h
index da2c8896..f73b04a 100644
--- a/headless/lib/browser/policy/headless_mode_policy.h
+++ b/headless/lib/browser/policy/headless_mode_policy.h
@@ -5,7 +5,7 @@
 #ifndef HEADLESS_LIB_BROWSER_POLICY_HEADLESS_MODE_POLICY_H_
 #define HEADLESS_LIB_BROWSER_POLICY_HEADLESS_MODE_POLICY_H_
 
-#include "components/policy/core/browser/configuration_policy_handler.h"
+#include "components/policy/core/browser/configuration_policy_handler.h"  // nogncheck http://crbug.com/1227148
 #include "headless/public/headless_export.h"
 
 class PrefService;
diff --git a/headless/lib/browser/policy/headless_policies.cc b/headless/lib/browser/policy/headless_policies.cc
index f0edc59..b48ac82 100644
--- a/headless/lib/browser/policy/headless_policies.cc
+++ b/headless/lib/browser/policy/headless_policies.cc
@@ -5,7 +5,7 @@
 #include "headless/lib/browser/policy/headless_policies.h"
 
 #include "base/check.h"
-#include "components/policy/core/browser/url_blocklist_manager.h"
+#include "components/policy/core/browser/url_blocklist_manager.h"  // nogncheck http://crbug.com/1227148
 #include "components/policy/policy_constants.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
diff --git a/headless/lib/browser/protocol/headless_handler.cc b/headless/lib/browser/protocol/headless_handler.cc
index 77d3f934..bdc42f0 100644
--- a/headless/lib/browser/protocol/headless_handler.cc
+++ b/headless/lib/browser/protocol/headless_handler.cc
@@ -14,7 +14,7 @@
 #include "components/viz/common/switches.h"
 #include "content/public/common/content_switches.h"
 #include "headless/lib/browser/headless_browser_impl.h"
-#include "headless/lib/browser/headless_web_contents_impl.h"
+#include "headless/lib/browser/headless_web_contents_impl.h"  // nogncheck http://crbug.com/1227378
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/codec/jpeg_codec.h"
diff --git a/headless/public/headless_browser.h b/headless/public/headless_browser.h
index dfd6be4..9e2b6f5b 100644
--- a/headless/public/headless_browser.h
+++ b/headless/public/headless_browser.h
@@ -15,6 +15,7 @@
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "build/build_config.h"
 #include "headless/public/headless_browser_context.h"
 #include "headless/public/headless_devtools_channel.h"
 #include "headless/public/headless_export.h"
diff --git a/headless/test/headless_browser_browsertest.cc b/headless/test/headless_browser_browsertest.cc
index f7f76a6..083f1de 100644
--- a/headless/test/headless_browser_browsertest.cc
+++ b/headless/test/headless_browser_browsertest.cc
@@ -52,7 +52,7 @@
 #include "ui/gfx/geometry/size.h"
 
 #if defined(OS_MAC)
-#include "third_party/crashpad/crashpad/client/crash_report_database.h"
+#include "third_party/crashpad/crashpad/client/crash_report_database.h"  // nogncheck
 #endif
 
 using testing::UnorderedElementsAre;
diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg
index 96ee2dc5..bff277c3 100644
--- a/infra/config/generated/cr-buildbucket.cfg
+++ b/infra/config/generated/cr-buildbucket.cfg
@@ -28911,6 +28911,74 @@
       }
     }
     builders {
+      name: "linux-exp-code-coverage"
+      swarming_host: "chromium-swarm.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      dimensions: "builderless:1"
+      dimensions: "cores:32"
+      dimensions: "cpu:x86-64"
+      dimensions: "os:Ubuntu-18.04"
+      dimensions: "pool:luci.chromium.ci"
+      dimensions: "ssd:1"
+      exe {
+        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
+        cipd_version: "refs/heads/master"
+        cmd: "luciexe"
+      }
+      properties: "{\"$build/code_coverage\":{\"coverage_reference_commit\":\"c942891373445199f69afd905965ad1e89cdee09\",\"coverage_test_types\":[\"overall\"],\"use_clang_coverage\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"$recipe_engine/isolated\":{\"server\":\"https://isolateserver.appspot.com\"},\"$recipe_engine/resultdb/test_presentation\":{\"column_keys\":[],\"grouping_keys\":[\"status\",\"v.test_suite\"]},\"builder_group\":\"chromium.fyi\",\"recipe\":\"chromium\"}"
+      execution_timeout_secs: 72000
+      build_numbers: YES
+      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+      experiments {
+        key: "chromium.resultdb.result_sink"
+        value: 100
+      }
+      experiments {
+        key: "chromium.resultdb.result_sink.gtests_local"
+        value: 100
+      }
+      experiments {
+        key: "chromium.resultdb.result_sink.junit_tests"
+        value: 100
+      }
+      experiments {
+        key: "luci.use_realms"
+        value: 100
+      }
+      resultdb {
+        enable: true
+        bq_exports {
+          project: "luci-resultdb"
+          dataset: "chromium"
+          table: "ci_test_results"
+          test_results {}
+        }
+        bq_exports {
+          project: "luci-resultdb"
+          dataset: "chromium"
+          table: "gpu_ci_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "ninja://(chrome/test:|content/test:fuchsia_)telemetry_gpu_integration_test/.+"
+            }
+          }
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "blink_web_tests_ci_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "ninja://[^/]*blink_web_tests/.+"
+            }
+          }
+        }
+        history_options {
+          use_invocation_timestamp: true
+        }
+      }
+    }
+    builders {
       name: "linux-extended-tracing-rel"
       swarming_host: "chromium-swarm.appspot.com"
       swarming_tags: "vpython:native-python-wrapper"
diff --git a/infra/config/generated/luci-milo.cfg b/infra/config/generated/luci-milo.cfg
index a04a116..486374a 100644
--- a/infra/config/generated/luci-milo.cfg
+++ b/infra/config/generated/luci-milo.cfg
@@ -6005,6 +6005,11 @@
     short_name: "lnx"
   }
   builders {
+    name: "buildbucket/luci.chromium.ci/linux-exp-code-coverage"
+    category: "code_coverage"
+    short_name: "lnx"
+  }
+  builders {
     name: "buildbucket/luci.chromium.ci/linux-chromeos-code-coverage"
     category: "code_coverage"
     short_name: "lcr"
diff --git a/infra/config/generated/luci-scheduler.cfg b/infra/config/generated/luci-scheduler.cfg
index 3a54a84..fc00de38 100644
--- a/infra/config/generated/luci-scheduler.cfg
+++ b/infra/config/generated/luci-scheduler.cfg
@@ -5725,6 +5725,17 @@
   }
 }
 job {
+  id: "linux-exp-code-coverage"
+  realm: "ci"
+  schedule: "triggered"
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "linux-exp-code-coverage"
+  }
+}
+job {
   id: "linux-extended-tracing-rel"
   realm: "ci"
   acl_sets: "ci"
diff --git a/infra/config/subprojects/chromium/ci.star b/infra/config/subprojects/chromium/ci.star
index a97dc6e..0df96ce 100644
--- a/infra/config/subprojects/chromium/ci.star
+++ b/infra/config/subprojects/chromium/ci.star
@@ -4248,6 +4248,19 @@
 )
 
 ci.fyi_coverage_builder(
+    name = "linux-exp-code-coverage",
+    console_view_entry = consoles.console_view_entry(
+        category = "code_coverage",
+        short_name = "lnx",
+    ),
+    use_clang_coverage = True,
+    coverage_test_types = ["overall"],
+    schedule = "triggered",
+    coverage_reference_commit = "c942891373445199f69afd905965ad1e89cdee09",
+    triggered_by = [],
+)
+
+ci.fyi_coverage_builder(
     name = "linux-lacros-code-coverage",
     console_view_entry = consoles.console_view_entry(
         category = "code_coverage",
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index 7110d44..2b2194f 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -336,8 +336,8 @@
       <message name="IDS_IOS_AUTOFILL_SAVE_CARD_BADGE_HINT" desc="Accessibility Hint for the Save Card button which presents the current options to Save a Card. This is spoken by VoiceOver.   [Length:Unlimited] [iOS only]">
         Options to Save Card
       </message>
-      <message name="IDS_IOS_AUTOFILL_HONORIFIC_PREFIX" desc="Title of the field of a profile address representing the title that can be auto-filled by Chrome. [iOS only]" meaning="A 'Title' field in a web form could be a prefix like Ms., Mx., or Dr. or a position held, like Captain or Rabbi. [Length: 15em]">
-           Title
+      <message name="IDS_IOS_AUTOFILL_HONORIFIC_PREFIX" desc="Title of the field of a profile address representing the title that can be auto-filled by Chrome. A 'Title' field in a web form could be a prefix like Ms., Mx., or Dr. or a position held, like Captain or Rabbi. [Length: 15em] [iOS only]" meaning="Honorific">
+        Title
       </message>
       <message name="IDS_IOS_AUTOFILL_FULLNAME" desc="Title of the field of a profile address representing the full name of the addressee. [Length: 15em] [iOS only]">
         Full Name
diff --git a/ios/chrome/browser/browsing_data/browsing_data_remover_impl.mm b/ios/chrome/browser/browsing_data/browsing_data_remover_impl.mm
index ae8bc27..d8f6e13 100644
--- a/ios/chrome/browser/browsing_data/browsing_data_remover_impl.mm
+++ b/ios/chrome/browser/browsing_data/browsing_data_remover_impl.mm
@@ -422,8 +422,11 @@
             .get();
 
     if (password_store) {
+      // It doesn't matter whether any logins were removed so bool argument can
+      // be omitted.
       password_store->RemoveLoginsCreatedBetween(
-          delete_begin, delete_end, CreatePendingTaskCompletionClosure());
+          delete_begin, delete_end,
+          IgnoreArgument<bool>(CreatePendingTaskCompletionClosure()));
     }
   }
 
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler.h
index 2d48ff45..ace6325f 100644
--- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler.h
+++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/autofill_address_profile/save_address_profile_infobar_modal_interaction_handler.h
@@ -5,6 +5,8 @@
 #ifndef IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_AUTOFILL_ADDRESS_PROFILE_SAVE_ADDRESS_PROFILE_INFOBAR_MODAL_INTERACTION_HANDLER_H_
 #define IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_AUTOFILL_ADDRESS_PROFILE_SAVE_ADDRESS_PROFILE_INFOBAR_MODAL_INTERACTION_HANDLER_H_
 
+#include <CoreFoundation/CoreFoundation.h>
+
 #import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_modal_interaction_handler.h"
 
 class InfoBarIOS;
diff --git a/ios/chrome/browser/main/browser_impl.h b/ios/chrome/browser/main/browser_impl.h
index c0455af..a8a37d7b 100644
--- a/ios/chrome/browser/main/browser_impl.h
+++ b/ios/chrome/browser/main/browser_impl.h
@@ -5,11 +5,12 @@
 #ifndef IOS_CHROME_BROWSER_MAIN_BROWSER_IMPL_H_
 #define IOS_CHROME_BROWSER_MAIN_BROWSER_IMPL_H_
 
-#import "ios/chrome/browser/main/browser.h"
+#include <CoreFoundation/CoreFoundation.h>
 
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
+#import "ios/chrome/browser/main/browser.h"
 
 class ChromeBrowserState;
 @class SceneState;
diff --git a/ios/chrome/browser/main/browser_observer_bridge.h b/ios/chrome/browser/main/browser_observer_bridge.h
index d5c62333e..c0547a3b 100644
--- a/ios/chrome/browser/main/browser_observer_bridge.h
+++ b/ios/chrome/browser/main/browser_observer_bridge.h
@@ -5,6 +5,8 @@
 #ifndef IOS_CHROME_BROWSER_MAIN_BROWSER_OBSERVER_BRIDGE_H_
 #define IOS_CHROME_BROWSER_MAIN_BROWSER_OBSERVER_BRIDGE_H_
 
+#include <CoreFoundation/CoreFoundation.h>
+
 #include "base/scoped_observation.h"
 #import "ios/chrome/browser/main/browser.h"
 #import "ios/chrome/browser/main/browser_observer.h"
diff --git a/ios/chrome/browser/main/browser_observer_bridge.mm b/ios/chrome/browser/main/browser_observer_bridge.mm
index f9f3094..0e7036b 100644
--- a/ios/chrome/browser/main/browser_observer_bridge.mm
+++ b/ios/chrome/browser/main/browser_observer_bridge.mm
@@ -4,6 +4,8 @@
 
 #import "ios/chrome/browser/main/browser_observer_bridge.h"
 
+#include <CoreFoundation/CoreFoundation.h>
+
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
diff --git a/ios/chrome/browser/main/test_browser.h b/ios/chrome/browser/main/test_browser.h
index 53575f5..8e9ee24 100644
--- a/ios/chrome/browser/main/test_browser.h
+++ b/ios/chrome/browser/main/test_browser.h
@@ -7,6 +7,8 @@
 
 #include "ios/chrome/browser/main/browser.h"
 
+#include <CoreFoundation/CoreFoundation.h>
+
 #include "base/macros.h"
 #include "base/observer_list.h"
 #import "ios/chrome/browser/web_state_list/fake_web_state_list_delegate.h"
diff --git a/ios/chrome/browser/notification_promo_unittest.cc b/ios/chrome/browser/notification_promo_unittest.cc
index 67a55cf..f24d3e5 100644
--- a/ios/chrome/browser/notification_promo_unittest.cc
+++ b/ios/chrome/browser/notification_promo_unittest.cc
@@ -102,7 +102,7 @@
     ASSERT_TRUE(payload);
     ASSERT_TRUE(payload->is_dict());
 
-    for (const auto& pair : payload->DictItems()) {
+    for (const auto pair : payload->DictItems()) {
       field_trial_params[pair.first] =
           pair.second.is_string() ? pair.second.GetString() : std::string();
     }
diff --git a/ios/chrome/browser/overlays/public/infobar_banner/add_to_reading_list_infobar_banner_overlay_request_config.h b/ios/chrome/browser/overlays/public/infobar_banner/add_to_reading_list_infobar_banner_overlay_request_config.h
index e668a83..b8cb1dc 100644
--- a/ios/chrome/browser/overlays/public/infobar_banner/add_to_reading_list_infobar_banner_overlay_request_config.h
+++ b/ios/chrome/browser/overlays/public/infobar_banner/add_to_reading_list_infobar_banner_overlay_request_config.h
@@ -5,6 +5,8 @@
 #ifndef IOS_CHROME_BROWSER_OVERLAYS_PUBLIC_INFOBAR_BANNER_ADD_TO_READING_LIST_INFOBAR_BANNER_OVERLAY_REQUEST_CONFIG_H_
 #define IOS_CHROME_BROWSER_OVERLAYS_PUBLIC_INFOBAR_BANNER_ADD_TO_READING_LIST_INFOBAR_BANNER_OVERLAY_REQUEST_CONFIG_H_
 
+#include <CoreFoundation/CoreFoundation.h>
+
 #include "ios/chrome/browser/overlays/public/overlay_request_config.h"
 #include "ios/chrome/browser/overlays/public/overlay_user_data.h"
 
diff --git a/ios/chrome/browser/overlays/public/infobar_banner/save_address_profile_infobar_banner_overlay_request_config.h b/ios/chrome/browser/overlays/public/infobar_banner/save_address_profile_infobar_banner_overlay_request_config.h
index cd66a60..1cbf0ef9 100644
--- a/ios/chrome/browser/overlays/public/infobar_banner/save_address_profile_infobar_banner_overlay_request_config.h
+++ b/ios/chrome/browser/overlays/public/infobar_banner/save_address_profile_infobar_banner_overlay_request_config.h
@@ -5,6 +5,8 @@
 #ifndef IOS_CHROME_BROWSER_OVERLAYS_PUBLIC_INFOBAR_BANNER_SAVE_ADDRESS_PROFILE_INFOBAR_BANNER_OVERLAY_REQUEST_CONFIG_H_
 #define IOS_CHROME_BROWSER_OVERLAYS_PUBLIC_INFOBAR_BANNER_SAVE_ADDRESS_PROFILE_INFOBAR_BANNER_OVERLAY_REQUEST_CONFIG_H_
 
+#include <CoreFoundation/CoreFoundation.h>
+
 #include <string>
 
 #include "ios/chrome/browser/overlays/public/overlay_request_config.h"
diff --git a/ios/chrome/browser/overlays/public/infobar_banner/save_card_infobar_banner_overlay_request_config.h b/ios/chrome/browser/overlays/public/infobar_banner/save_card_infobar_banner_overlay_request_config.h
index f74c333..f290b5ca5 100644
--- a/ios/chrome/browser/overlays/public/infobar_banner/save_card_infobar_banner_overlay_request_config.h
+++ b/ios/chrome/browser/overlays/public/infobar_banner/save_card_infobar_banner_overlay_request_config.h
@@ -5,6 +5,8 @@
 #ifndef IOS_CHROME_BROWSER_OVERLAYS_PUBLIC_INFOBAR_BANNER_SAVE_CARD_INFOBAR_BANNER_OVERLAY_REQUEST_CONFIG_H_
 #define IOS_CHROME_BROWSER_OVERLAYS_PUBLIC_INFOBAR_BANNER_SAVE_CARD_INFOBAR_BANNER_OVERLAY_REQUEST_CONFIG_H_
 
+#include <CoreFoundation/CoreFoundation.h>
+
 #include <string>
 
 #include "ios/chrome/browser/overlays/public/overlay_request_config.h"
diff --git a/ios/chrome/browser/overlays/public/infobar_banner/save_password_infobar_banner_overlay.h b/ios/chrome/browser/overlays/public/infobar_banner/save_password_infobar_banner_overlay.h
index 51167e1d..2a8e024 100644
--- a/ios/chrome/browser/overlays/public/infobar_banner/save_password_infobar_banner_overlay.h
+++ b/ios/chrome/browser/overlays/public/infobar_banner/save_password_infobar_banner_overlay.h
@@ -5,6 +5,8 @@
 #ifndef IOS_CHROME_BROWSER_OVERLAYS_PUBLIC_INFOBAR_BANNER_SAVE_PASSWORD_INFOBAR_BANNER_OVERLAY_H_
 #define IOS_CHROME_BROWSER_OVERLAYS_PUBLIC_INFOBAR_BANNER_SAVE_PASSWORD_INFOBAR_BANNER_OVERLAY_H_
 
+#include <CoreFoundation/CoreFoundation.h>
+
 #include "ios/chrome/browser/overlays/public/overlay_request_config.h"
 #include "ios/chrome/browser/overlays/public/overlay_user_data.h"
 
diff --git a/ios/chrome/browser/overlays/public/infobar_banner/translate_infobar_banner_overlay_request_config.h b/ios/chrome/browser/overlays/public/infobar_banner/translate_infobar_banner_overlay_request_config.h
index 616ad25..4c4a387 100644
--- a/ios/chrome/browser/overlays/public/infobar_banner/translate_infobar_banner_overlay_request_config.h
+++ b/ios/chrome/browser/overlays/public/infobar_banner/translate_infobar_banner_overlay_request_config.h
@@ -5,6 +5,8 @@
 #ifndef IOS_CHROME_BROWSER_OVERLAYS_PUBLIC_INFOBAR_BANNER_TRANSLATE_INFOBAR_BANNER_OVERLAY_REQUEST_CONFIG_H_
 #define IOS_CHROME_BROWSER_OVERLAYS_PUBLIC_INFOBAR_BANNER_TRANSLATE_INFOBAR_BANNER_OVERLAY_REQUEST_CONFIG_H_
 
+#include <CoreFoundation/CoreFoundation.h>
+
 #include "components/translate/core/browser/translate_step.h"
 #include "ios/chrome/browser/overlays/public/overlay_request_config.h"
 #include "ios/chrome/browser/overlays/public/overlay_user_data.h"
diff --git a/ios/chrome/browser/overlays/public/infobar_banner/update_password_infobar_banner_overlay.h b/ios/chrome/browser/overlays/public/infobar_banner/update_password_infobar_banner_overlay.h
index 40e9bf3..41a3f59 100644
--- a/ios/chrome/browser/overlays/public/infobar_banner/update_password_infobar_banner_overlay.h
+++ b/ios/chrome/browser/overlays/public/infobar_banner/update_password_infobar_banner_overlay.h
@@ -5,6 +5,8 @@
 #ifndef IOS_CHROME_BROWSER_OVERLAYS_PUBLIC_INFOBAR_BANNER_UPDATE_PASSWORD_INFOBAR_BANNER_OVERLAY_H_
 #define IOS_CHROME_BROWSER_OVERLAYS_PUBLIC_INFOBAR_BANNER_UPDATE_PASSWORD_INFOBAR_BANNER_OVERLAY_H_
 
+#include <CoreFoundation/CoreFoundation.h>
+
 #include "ios/chrome/browser/overlays/public/overlay_request_config.h"
 #include "ios/chrome/browser/overlays/public/overlay_user_data.h"
 
diff --git a/ios/chrome/browser/overlays/public/infobar_modal/password_infobar_modal_overlay_request_config.h b/ios/chrome/browser/overlays/public/infobar_modal/password_infobar_modal_overlay_request_config.h
index a39d68f..53118a3 100644
--- a/ios/chrome/browser/overlays/public/infobar_modal/password_infobar_modal_overlay_request_config.h
+++ b/ios/chrome/browser/overlays/public/infobar_modal/password_infobar_modal_overlay_request_config.h
@@ -5,6 +5,8 @@
 #ifndef IOS_CHROME_BROWSER_OVERLAYS_PUBLIC_INFOBAR_MODAL_PASSWORD_INFOBAR_MODAL_OVERLAY_REQUEST_CONFIG_H_
 #define IOS_CHROME_BROWSER_OVERLAYS_PUBLIC_INFOBAR_MODAL_PASSWORD_INFOBAR_MODAL_OVERLAY_REQUEST_CONFIG_H_
 
+#include <CoreFoundation/CoreFoundation.h>
+
 #include "ios/chrome/browser/overlays/public/overlay_request_config.h"
 
 class InfoBarIOS;
diff --git a/ios/chrome/browser/passwords/password_manager_app_interface.mm b/ios/chrome/browser/passwords/password_manager_app_interface.mm
index c687870..edd69e8 100644
--- a/ios/chrome/browser/passwords/password_manager_app_interface.mm
+++ b/ios/chrome/browser/passwords/password_manager_app_interface.mm
@@ -97,7 +97,7 @@
           .get();
   // Remove credentials stored during executing the test.
   passwordStore->RemoveLoginsCreatedBetween(base::Time(), base::Time::Now(),
-                                            base::OnceClosure());
+                                            base::DoNothing());
 }
 
 + (int)storedCredentialsCount {
diff --git a/ios/chrome/browser/passwords/save_passwords_consumer.h b/ios/chrome/browser/passwords/save_passwords_consumer.h
index b897814..456c4db 100644
--- a/ios/chrome/browser/passwords/save_passwords_consumer.h
+++ b/ios/chrome/browser/passwords/save_passwords_consumer.h
@@ -5,6 +5,8 @@
 #ifndef IOS_CHROME_BROWSER_PASSWORDS_SAVE_PASSWORDS_CONSUMER_H_
 #define IOS_CHROME_BROWSER_PASSWORDS_SAVE_PASSWORDS_CONSUMER_H_
 
+#include <CoreFoundation/CoreFoundation.h>
+
 #include <memory>
 #include <vector>
 
diff --git a/ios/chrome/browser/policy/policy_watcher_browser_agent.h b/ios/chrome/browser/policy/policy_watcher_browser_agent.h
index 181bffd..7252ad1 100644
--- a/ios/chrome/browser/policy/policy_watcher_browser_agent.h
+++ b/ios/chrome/browser/policy/policy_watcher_browser_agent.h
@@ -5,6 +5,8 @@
 #ifndef IOS_CHROME_BROWSER_POLICY_POLICY_WATCHER_BROWSER_AGENT_H_
 #define IOS_CHROME_BROWSER_POLICY_POLICY_WATCHER_BROWSER_AGENT_H_
 
+#include <CoreFoundation/CoreFoundation.h>
+
 #include <memory>
 
 #include "base/macros.h"
diff --git a/ios/chrome/browser/providers/BUILD.gn b/ios/chrome/browser/providers/BUILD.gn
index 45c4dbcd..4f5f3b02 100644
--- a/ios/chrome/browser/providers/BUILD.gn
+++ b/ios/chrome/browser/providers/BUILD.gn
@@ -53,6 +53,7 @@
 
     # The individual API implementations.
     "//ios/chrome/browser/providers/modals:chromium_modals",
+    "//ios/chrome/browser/providers/text_zoom:chromium_text_zoom",
 
     # The provider API needs to provide MaterialDesignComponent API (as the
     # internal provider provides an alternate implementation).
diff --git a/ios/chrome/browser/providers/text_zoom/BUILD.gn b/ios/chrome/browser/providers/text_zoom/BUILD.gn
new file mode 100644
index 0000000..efe34d2
--- /dev/null
+++ b/ios/chrome/browser/providers/text_zoom/BUILD.gn
@@ -0,0 +1,14 @@
+# Copyright 2021 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("chromium_text_zoom") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [ "chromium_text_zoom.mm" ]
+  deps = [
+    "//ios/chrome/browser/web:feature_flags",
+    "//ios/public/provider/chrome/browser:font_size_java_script_feature",
+    "//ios/public/provider/chrome/browser/text_zoom:text_zoom_api",
+    "//ui/base",
+  ]
+}
diff --git a/ios/chrome/browser/providers/text_zoom/chromium_text_zoom.mm b/ios/chrome/browser/providers/text_zoom/chromium_text_zoom.mm
new file mode 100644
index 0000000..31e7d185
--- /dev/null
+++ b/ios/chrome/browser/providers/text_zoom/chromium_text_zoom.mm
@@ -0,0 +1,27 @@
+// Copyright 2021 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/chrome/browser/web/features.h"
+#import "ios/public/provider/chrome/browser/font_size_java_script_feature.h"
+#import "ios/public/provider/chrome/browser/text_zoom/text_zoom_api.h"
+#include "ui/base/device_form_factor.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace ios {
+namespace provider {
+
+void SetTextZoomForWebState(web::WebState* web_state, int size) {
+  FontSizeJavaScriptFeature::GetInstance()->AdjustFontSize(web_state, size);
+}
+
+bool IsTextZoomEnabled() {
+  return ui::GetDeviceFormFactor() != ui::DEVICE_FORM_FACTOR_TABLET &&
+         base::FeatureList::IsEnabled(web::kWebPageTextAccessibility);
+}
+
+}  // namespace provider
+}  // namespace ios
diff --git a/ios/chrome/browser/screen_time/screen_time_history_deleter_factory.h b/ios/chrome/browser/screen_time/screen_time_history_deleter_factory.h
index ed12c17..7d8aefc 100644
--- a/ios/chrome/browser/screen_time/screen_time_history_deleter_factory.h
+++ b/ios/chrome/browser/screen_time/screen_time_history_deleter_factory.h
@@ -5,6 +5,8 @@
 #ifndef IOS_CHROME_BROWSER_SCREEN_TIME_SCREEN_TIME_HISTORY_DELETER_FACTORY_H_
 #define IOS_CHROME_BROWSER_SCREEN_TIME_SCREEN_TIME_HISTORY_DELETER_FACTORY_H_
 
+#include <CoreFoundation/CoreFoundation.h>
+
 #include "base/macros.h"
 #include "base/no_destructor.h"
 #include "components/keyed_service/ios/browser_state_keyed_service_factory.h"
diff --git a/ios/chrome/browser/send_tab_to_self/ios_send_tab_to_self_infobar_delegate.h b/ios/chrome/browser/send_tab_to_self/ios_send_tab_to_self_infobar_delegate.h
index 0809e184..86e7ea11 100644
--- a/ios/chrome/browser/send_tab_to_self/ios_send_tab_to_self_infobar_delegate.h
+++ b/ios/chrome/browser/send_tab_to_self/ios_send_tab_to_self_infobar_delegate.h
@@ -5,6 +5,8 @@
 #ifndef IOS_CHROME_BROWSER_SEND_TAB_TO_SELF_IOS_SEND_TAB_TO_SELF_INFOBAR_DELEGATE_H_
 #define IOS_CHROME_BROWSER_SEND_TAB_TO_SELF_IOS_SEND_TAB_TO_SELF_INFOBAR_DELEGATE_H_
 
+#include <CoreFoundation/CoreFoundation.h>
+
 #include <memory>
 #include <string>
 
diff --git a/ios/chrome/browser/send_tab_to_self/send_tab_to_self_browser_agent.h b/ios/chrome/browser/send_tab_to_self/send_tab_to_self_browser_agent.h
index 97bf755..89a9089 100644
--- a/ios/chrome/browser/send_tab_to_self/send_tab_to_self_browser_agent.h
+++ b/ios/chrome/browser/send_tab_to_self/send_tab_to_self_browser_agent.h
@@ -5,6 +5,8 @@
 #ifndef IOS_CHROME_BROWSER_SEND_TAB_TO_SELF_SEND_TAB_TO_SELF_BROWSER_AGENT_H_
 #define IOS_CHROME_BROWSER_SEND_TAB_TO_SELF_SEND_TAB_TO_SELF_BROWSER_AGENT_H_
 
+#include <CoreFoundation/CoreFoundation.h>
+
 #include <string>
 #include <vector>
 
diff --git a/ios/chrome/browser/sessions/session_restoration_browser_agent.h b/ios/chrome/browser/sessions/session_restoration_browser_agent.h
index 129536e..e5bd9033 100644
--- a/ios/chrome/browser/sessions/session_restoration_browser_agent.h
+++ b/ios/chrome/browser/sessions/session_restoration_browser_agent.h
@@ -5,6 +5,8 @@
 #ifndef IOS_CHROME_BROWSER_SESSIONS_SESSION_RESTORATION_BROWSER_AGENT_H_
 #define IOS_CHROME_BROWSER_SESSIONS_SESSION_RESTORATION_BROWSER_AGENT_H_
 
+#include <CoreFoundation/CoreFoundation.h>
+
 #include <memory>
 #include <string>
 #include <vector>
diff --git a/ios/chrome/browser/ui/activity_services/BUILD.gn b/ios/chrome/browser/ui/activity_services/BUILD.gn
index 1bfb5c107..afc359de 100644
--- a/ios/chrome/browser/ui/activity_services/BUILD.gn
+++ b/ios/chrome/browser/ui/activity_services/BUILD.gn
@@ -41,6 +41,7 @@
     "//ios/chrome/browser/ui/main:default_browser_scene_agent",
     "//ios/chrome/browser/ui/main:scene_state_header",
     "//ios/chrome/browser/ui/util",
+    "//ios/chrome/browser/ui/util:url_with_title",
     "//ios/chrome/browser/web_state_list",
     "//ui/base",
     "//url",
diff --git a/ios/chrome/browser/ui/activity_services/activity_params.h b/ios/chrome/browser/ui/activity_services/activity_params.h
index 4a81501c..365ac3a 100644
--- a/ios/chrome/browser/ui/activity_services/activity_params.h
+++ b/ios/chrome/browser/ui/activity_services/activity_params.h
@@ -8,7 +8,7 @@
 #import <UIKit/UIKit.h>
 
 #import "ios/chrome/browser/ui/activity_services/activity_scenario.h"
-#import "ios/chrome/browser/ui/activity_services/data/url_with_title.h"
+#import "ios/chrome/browser/ui/util/url_with_title.h"
 
 class GURL;
 
diff --git a/ios/chrome/browser/ui/activity_services/activity_params.mm b/ios/chrome/browser/ui/activity_services/activity_params.mm
index 4dbd0b376d..d4e13cc 100644
--- a/ios/chrome/browser/ui/activity_services/activity_params.mm
+++ b/ios/chrome/browser/ui/activity_services/activity_params.mm
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 #import "ios/chrome/browser/ui/activity_services/activity_params.h"
-#import "ios/chrome/browser/ui/activity_services/data/url_with_title.h"
+#import "ios/chrome/browser/ui/util/url_with_title.h"
 
 #include "url/gurl.h"
 
diff --git a/ios/chrome/browser/ui/activity_services/data/BUILD.gn b/ios/chrome/browser/ui/activity_services/data/BUILD.gn
index 5b477fc1..44ba412 100644
--- a/ios/chrome/browser/ui/activity_services/data/BUILD.gn
+++ b/ios/chrome/browser/ui/activity_services/data/BUILD.gn
@@ -20,8 +20,6 @@
     "share_to_data.mm",
     "share_to_data_builder.h",
     "share_to_data_builder.mm",
-    "url_with_title.h",
-    "url_with_title.mm",
   ]
   deps = [
     "//base",
@@ -31,6 +29,7 @@
     "//ios/chrome/browser/snapshots",
     "//ios/chrome/browser/tabs",
     "//ios/chrome/browser/ui/util",
+    "//ios/chrome/browser/ui/util:url_with_title",
     "//ios/web/common:user_agent",
     "//ios/web/public",
     "//ios/web/public:web_state_observer",
diff --git a/ios/chrome/browser/ui/activity_services/data/share_to_data_builder.mm b/ios/chrome/browser/ui/activity_services/data/share_to_data_builder.mm
index 4d08a932..d551856 100644
--- a/ios/chrome/browser/ui/activity_services/data/share_to_data_builder.mm
+++ b/ios/chrome/browser/ui/activity_services/data/share_to_data_builder.mm
@@ -12,7 +12,7 @@
 #import "ios/chrome/browser/tabs/tab_title_util.h"
 #include "ios/chrome/browser/ui/activity_services/data/chrome_activity_item_thumbnail_generator.h"
 #include "ios/chrome/browser/ui/activity_services/data/share_to_data.h"
-#import "ios/chrome/browser/ui/activity_services/data/url_with_title.h"
+#import "ios/chrome/browser/ui/util/url_with_title.h"
 #import "ios/web/public/navigation/navigation_item.h"
 #import "ios/web/public/navigation/navigation_manager.h"
 #import "ios/web/public/web_state.h"
diff --git a/ios/chrome/browser/ui/autofill/autofill_app_interface.mm b/ios/chrome/browser/ui/autofill/autofill_app_interface.mm
index edd083d..3fd1b103 100644
--- a/ios/chrome/browser/ui/autofill/autofill_app_interface.mm
+++ b/ios/chrome/browser/ui/autofill/autofill_app_interface.mm
@@ -147,7 +147,7 @@
 // Removes all credentials stored.
 void ClearPasswordStore() {
   GetPasswordStore()->RemoveLoginsCreatedBetween(base::Time(), base::Time(),
-                                                 base::OnceClosure());
+                                                 base::DoNothing());
   TestStoreConsumer consumer;
 }
 
diff --git a/ios/chrome/browser/ui/browser_view/BUILD.gn b/ios/chrome/browser/ui/browser_view/BUILD.gn
index f71f2b9..0a316e64 100644
--- a/ios/chrome/browser/ui/browser_view/BUILD.gn
+++ b/ios/chrome/browser/ui/browser_view/BUILD.gn
@@ -170,6 +170,7 @@
     "//ios/chrome/browser/ui/toolbar_container",
     "//ios/chrome/browser/ui/toolbar_container:feature_flags",
     "//ios/chrome/browser/ui/util",
+    "//ios/chrome/browser/ui/util:url_with_title",
     "//ios/chrome/browser/ui/voice",
     "//ios/chrome/browser/upgrade",
     "//ios/chrome/browser/url_loading",
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 2646c51..eb42f137 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -153,6 +153,7 @@
 #import "ios/chrome/browser/ui/util/page_animation_util.h"
 #import "ios/chrome/browser/ui/util/pasteboard_util.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
+#import "ios/chrome/browser/ui/util/url_with_title.h"
 #import "ios/chrome/browser/ui/voice/text_to_speech_playback_controller.h"
 #import "ios/chrome/browser/ui/voice/text_to_speech_playback_controller_factory.h"
 #include "ios/chrome/browser/upgrade/upgrade_center.h"
@@ -713,8 +714,8 @@
 
 // Reading List
 // ------------
-// Adds the given url to the reading list.
-- (void)addToReadingListURL:(const GURL&)URL title:(NSString*)title;
+// Adds the given urls to the reading list.
+- (void)addURLsToReadingList:(NSArray<URLWithTitle*>*)URLs;
 
 // The thumb strip's pan gesture handler that will be added to the toolbar and
 // tab strip.
@@ -2866,9 +2867,19 @@
 
 #pragma mark - Private Methods: Reading List
 
-- (void)addToReadingListURL:(const GURL&)URL title:(NSString*)title {
-  ReadingListModel* readingModel =
-      ReadingListModelFactory::GetForBrowserState(self.browserState);
+- (void)addURLsToReadingList:(NSArray<URLWithTitle*>*)URLs {
+  for (URLWithTitle* urlWithTitle in URLs) {
+    [self addURLToReadingList:urlWithTitle.URL withTitle:urlWithTitle.title];
+  }
+
+  [self.dispatcher triggerToolsMenuButtonAnimation];
+
+  TriggerHapticFeedbackForNotification(UINotificationFeedbackTypeSuccess);
+  [self showSnackbar:l10n_util::GetNSString(
+                         IDS_IOS_READING_LIST_SNACKBAR_MESSAGE)];
+}
+
+- (void)addURLToReadingList:(const GURL&)URL withTitle:(NSString*)title {
   if (self.currentWebState &&
       self.currentWebState->GetVisibleURL().spec() == URL.spec()) {
     // Log UKM if the current page is being added to Reading List.
@@ -2880,16 +2891,13 @@
           .Record(ukm::UkmRecorder::Get());
     }
   }
+
   base::RecordAction(UserMetricsAction("MobileReadingListAdd"));
 
+  ReadingListModel* readingModel =
+      ReadingListModelFactory::GetForBrowserState(self.browserState);
   readingModel->AddEntry(URL, base::SysNSStringToUTF8(title),
                          reading_list::ADDED_VIA_CURRENT_APP);
-
-  [self.dispatcher triggerToolsMenuButtonAnimation];
-
-  TriggerHapticFeedbackForNotification(UINotificationFeedbackTypeSuccess);
-  [self showSnackbar:l10n_util::GetNSString(
-                         IDS_IOS_READING_LIST_SNACKBAR_MESSAGE)];
 }
 
 #pragma mark - ** Protocol Implementations and Helpers **
@@ -3591,7 +3599,9 @@
           base::RecordAction(
               base::UserMetricsAction("MobileWebContextMenuReadLater"));
           Record(ACTION_READ_LATER, isImage, isLink);
-          [weakSelf addToReadingListURL:link title:innerText];
+          [weakSelf addURLsToReadingList:@[ [[URLWithTitle alloc]
+                                             initWithURL:link
+                                                   title:innerText] ]];
         };
         [_contextMenuCoordinator addItemWithTitle:title
                                            action:action
@@ -3850,7 +3860,9 @@
           // Add to reading list.
           UIAction* addToReadingList =
               [actionFactory actionToAddToReadingListWithBlock:^{
-                [weakSelf addToReadingListURL:link title:innerText];
+                  [weakSelf addURLsToReadingList:@[ [[URLWithTitle alloc]
+                                                     initWithURL:link
+                                                     title:innerText] ]];
               }];
           [menuElements addObject:addToReadingList];
         }
@@ -4584,7 +4596,7 @@
 }
 
 - (void)addToReadingList:(ReadingListAddCommand*)command {
-  [self addToReadingListURL:[command URL] title:[command title]];
+  [self addURLsToReadingList:command.URLs];
 }
 
 - (void)preloadVoiceSearch {
diff --git a/ios/chrome/browser/ui/commands/BUILD.gn b/ios/chrome/browser/ui/commands/BUILD.gn
index 74c59ec..7cb2cc2 100644
--- a/ios/chrome/browser/ui/commands/BUILD.gn
+++ b/ios/chrome/browser/ui/commands/BUILD.gn
@@ -48,6 +48,7 @@
   ]
 
   deps = [
+    "//ios/chrome/browser/ui/util:url_with_title",
     "//ios/public/provider/chrome/browser/user_feedback",
     "//ios/web",
     "//net",
diff --git a/ios/chrome/browser/ui/commands/reading_list_add_command.h b/ios/chrome/browser/ui/commands/reading_list_add_command.h
index 5ebb244..e0fbde3 100644
--- a/ios/chrome/browser/ui/commands/reading_list_add_command.h
+++ b/ios/chrome/browser/ui/commands/reading_list_add_command.h
@@ -8,17 +8,20 @@
 #import <Foundation/Foundation.h>
 
 class GURL;
+@class URLWithTitle;
 
 @interface ReadingListAddCommand : NSObject
 
-@property(nonatomic, readonly) const GURL& URL;
-@property(copy, nonatomic, readonly) NSString* title;
+@property(nonatomic, readonly) NSArray<URLWithTitle*>* URLs;
 
 - (instancetype)init NS_UNAVAILABLE;
 
 - (instancetype)initWithURL:(const GURL&)URL
                       title:(NSString*)title NS_DESIGNATED_INITIALIZER;
 
+- (instancetype)initWithURLs:(NSArray<URLWithTitle*>*)URL
+    NS_DESIGNATED_INITIALIZER;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_COMMANDS_READING_LIST_ADD_COMMAND_H_
diff --git a/ios/chrome/browser/ui/commands/reading_list_add_command.mm b/ios/chrome/browser/ui/commands/reading_list_add_command.mm
index feedae2a..20668612 100644
--- a/ios/chrome/browser/ui/commands/reading_list_add_command.mm
+++ b/ios/chrome/browser/ui/commands/reading_list_add_command.mm
@@ -4,23 +4,33 @@
 
 #import "ios/chrome/browser/ui/commands/reading_list_add_command.h"
 
+#import "ios/chrome/browser/ui/util/url_with_title.h"
 #include "url/gurl.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
-@implementation ReadingListAddCommand {
-  GURL _URL;
-}
+@interface ReadingListAddCommand ()
 
-@synthesize title = _title;
-@synthesize URL = _URL;
+@property(nonatomic, strong) NSArray<URLWithTitle*>* URLs;
+
+@end
+
+@implementation ReadingListAddCommand
+
+@synthesize URLs = _URLs;
 
 - (instancetype)initWithURL:(const GURL&)URL title:(NSString*)title {
   if (self = [super init]) {
-    _URL = URL;
-    _title = title;
+    _URLs = @[ [[URLWithTitle alloc] initWithURL:URL title:title] ];
+  }
+  return self;
+}
+
+- (instancetype)initWithURLs:(NSArray<URLWithTitle*>*)URLs {
+  if (self = [super init]) {
+    _URLs = [URLs copy];
   }
   return self;
 }
diff --git a/ios/chrome/browser/ui/infobars/test_infobar_delegate.h b/ios/chrome/browser/ui/infobars/test_infobar_delegate.h
index 22d24122..0e0db41 100644
--- a/ios/chrome/browser/ui/infobars/test_infobar_delegate.h
+++ b/ios/chrome/browser/ui/infobars/test_infobar_delegate.h
@@ -5,6 +5,8 @@
 #ifndef IOS_CHROME_BROWSER_UI_INFOBARS_TEST_INFOBAR_DELEGATE_H_
 #define IOS_CHROME_BROWSER_UI_INFOBARS_TEST_INFOBAR_DELEGATE_H_
 
+#include <CoreFoundation/CoreFoundation.h>
+
 #include "components/infobars/core/confirm_infobar_delegate.h"
 
 // An infobar that displays |infobar_message| and one button.
diff --git a/ios/chrome/browser/ui/settings/password/passwords_settings_app_interface.mm b/ios/chrome/browser/ui/settings/password/passwords_settings_app_interface.mm
index 1bc15b65..a400944 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_settings_app_interface.mm
+++ b/ios/chrome/browser/ui/settings/password/passwords_settings_app_interface.mm
@@ -137,7 +137,7 @@
 
 bool ClearPasswordStore() {
   GetPasswordStore()->RemoveLoginsCreatedBetween(base::Time(), base::Time(),
-                                                 base::OnceClosure());
+                                                 base::DoNothing());
   FakeStoreConsumer consumer;
   if (!consumer.FetchStoreResults()) {
     return false;
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/BUILD.gn b/ios/chrome/browser/ui/tab_switcher/tab_grid/BUILD.gn
index 1a73e763..d8f4b53 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/BUILD.gn
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/BUILD.gn
@@ -40,7 +40,6 @@
     "//ios/chrome/browser/tabs",
     "//ios/chrome/browser/ui:feature_flags",
     "//ios/chrome/browser/ui/activity_services",
-    "//ios/chrome/browser/ui/activity_services/data",
     "//ios/chrome/browser/ui/alert_coordinator",
     "//ios/chrome/browser/ui/bookmarks",
     "//ios/chrome/browser/ui/commands",
@@ -64,6 +63,7 @@
     "//ios/chrome/browser/ui/thumb_strip:feature_flags",
     "//ios/chrome/browser/ui/thumb_strip:public",
     "//ios/chrome/browser/ui/util",
+    "//ios/chrome/browser/ui/util:url_with_title",
     "//ios/chrome/browser/url_loading",
     "//ios/chrome/browser/web",
     "//ios/chrome/browser/web_state_list",
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
index 62cd0cf..5097c0b 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
@@ -975,12 +975,12 @@
 }
 
 - (void)addToReadingListURL:(const GURL&)URL title:(NSString*)title {
+  ReadingListAddCommand* command =
+      [[ReadingListAddCommand alloc] initWithURL:URL title:title];
   // TODO(crbug.com/1045047): Use HandlerForProtocol after commands
   // protocol clean up.
   id<BrowserCommands> readingListAdder = static_cast<id<BrowserCommands>>(
       self.regularBrowser->GetCommandDispatcher());
-  ReadingListAddCommand* command =
-      [[ReadingListAddCommand alloc] initWithURL:URL title:title];
   [readingListAdder addToReadingList:command];
 }
 
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_egtest.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_egtest.mm
index fc02c5f..1646352 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_egtest.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_egtest.mm
@@ -102,9 +102,10 @@
   }
 
   if ([self isRunningTest:@selector(testTabGridBulkActionCloseTabs)] ||
-      [self isRunningTest:@selector(testTabGridBulkActionSelectAll)]) {
+      [self isRunningTest:@selector(testTabGridBulkActionSelectAll)] ||
+      [self isRunningTest:@selector(testTabGridBulkActionAddToReadingList)]) {
     config.features_enabled.push_back(kTabsBulkActions);
-  }
+      }
 
   config.features_disabled.push_back(kStartSurface);
 
@@ -956,7 +957,7 @@
       assertWithMatcher:grey_notNil()];
 }
 
-// Tests selecting all items in the tab grdi edit mode using the "Select all"
+// Tests selecting all items in the tab grid edit mode using the "Select all"
 // button.
 - (void)testTabGridBulkActionSelectAll {
   if (!base::ios::IsRunningOnIOS14OrLater()) {
@@ -1005,6 +1006,44 @@
       assertWithMatcher:grey_notNil()];
 }
 
+// Tests adding items to the readinglist from the tab grid edit mode.
+- (void)testTabGridBulkActionAddToReadingList {
+  if (!base::ios::IsRunningOnIOS14OrLater()) {
+    EARL_GREY_TEST_SKIPPED(
+        @"Bulk actions are only supported on iOS 14 and later.");
+  }
+
+  [ChromeEarlGrey loadURL:_URL1];
+  [ChromeEarlGrey waitForWebStateContainingText:kResponse1];
+
+  [ChromeEarlGrey openNewTab];
+  [ChromeEarlGrey loadURL:_URL2];
+  [ChromeEarlGrey waitForWebStateContainingText:kResponse2];
+
+  [ChromeEarlGrey openNewTab];
+  [ChromeEarlGrey loadURL:_URL3];
+  [ChromeEarlGrey waitForWebStateContainingText:kResponse3];
+
+  [[EarlGrey selectElementWithMatcher:chrome_test_util::ShowTabsButton()]
+      performAction:grey_tap()];
+
+  [[EarlGrey selectElementWithMatcher:chrome_test_util::TabGridEditButton()]
+      performAction:grey_tap()];
+
+  // Select the first and last items.
+  [[EarlGrey selectElementWithMatcher:chrome_test_util::TabGridCellAtIndex(0)]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:chrome_test_util::TabGridCellAtIndex(2)]
+      performAction:grey_tap()];
+
+  [[EarlGrey
+      selectElementWithMatcher:chrome_test_util::TabGridEditAddToButton()]
+      performAction:grey_tap()];
+
+  [self waitForSnackBarMessage:IDS_IOS_READING_LIST_SNACKBAR_MESSAGE
+      triggeredByTappingItemWithMatcher:AddToReadingListButton()];
+}
+
 #pragma mark - Helper Methods
 
 - (void)loadTestURLs {
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_mediator.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_mediator.mm
index eda8168..8f0ff88 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_mediator.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_mediator.mm
@@ -30,12 +30,14 @@
 #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h"
 #include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/tabs/tab_title_util.h"
-#import "ios/chrome/browser/ui/activity_services/data/url_with_title.h"
+#import "ios/chrome/browser/ui/commands/browser_commands.h"
+#import "ios/chrome/browser/ui/commands/reading_list_add_command.h"
 #import "ios/chrome/browser/ui/menu/action_factory.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_consumer.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_item.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_switcher_item.h"
+#import "ios/chrome/browser/ui/util/url_with_title.h"
 #import "ios/chrome/browser/web/tab_id_tab_helper.h"
 #include "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h"
@@ -123,6 +125,8 @@
 @property(nonatomic, readonly) ChromeBrowserState* browserState;
 // The UI consumer to which updates are made.
 @property(nonatomic, weak) id<GridConsumer> consumer;
+// Handler for reading list command.
+@property(nonatomic, weak) id<BrowserCommands> readingListHandler;
 // The saved session window just before close all tabs is called.
 @property(nonatomic, strong) SessionWindowIOS* closedSessionWindow;
 // The number of tabs in |closedSessionWindow| that are synced by
@@ -171,9 +175,18 @@
   [self.snapshotCache removeObserver:self];
   _scopedWebStateListObservation->RemoveAllObservations();
   _scopedWebStateObservation->RemoveAllObservations();
+  _readingListHandler = nullptr;
+
   _browser = browser;
+
   _webStateList = browser ? browser->GetWebStateList() : nullptr;
   _browserState = browser ? browser->GetBrowserState() : nullptr;
+  if (_browser) {
+    // TODO(crbug.com/1045047): Use HandlerForProtocol after commands
+    // protocol clean up.
+    _readingListHandler =
+        static_cast<id<BrowserCommands>>(_browser->GetCommandDispatcher());
+  }
   [self.snapshotCache addObserver:self];
 
   if (_webStateList) {
@@ -701,7 +714,21 @@
 }
 
 - (void)addItemsToReadingList:(NSArray<NSString*>*)items {
-  // TODO(crbug.com/1196907): Implement add items to reading list.
+  if (!_readingListHandler) {
+    return;
+  }
+
+  NSMutableArray<URLWithTitle*>* URLs = [[NSMutableArray alloc] init];
+  for (NSString* itemIdentifier in items) {
+    GridItem* item = [self gridItemForCellIdentifier:itemIdentifier];
+    URLWithTitle* URL = [[URLWithTitle alloc] initWithURL:item.URL
+                                                    title:item.title];
+    [URLs addObject:URL];
+  }
+
+  ReadingListAddCommand* command =
+      [[ReadingListAddCommand alloc] initWithURLs:URLs];
+  [_readingListHandler addToReadingList:command];
 }
 
 - (void)addItemsToBookmarks:(NSArray<NSString*>*)items {
diff --git a/ios/chrome/browser/ui/util/BUILD.gn b/ios/chrome/browser/ui/util/BUILD.gn
index 37545ae3..5a8af4ca 100644
--- a/ios/chrome/browser/ui/util/BUILD.gn
+++ b/ios/chrome/browser/ui/util/BUILD.gn
@@ -103,6 +103,15 @@
   ]
 }
 
+source_set("url_with_title") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [
+    "url_with_title.h",
+    "url_with_title.mm",
+  ]
+  deps = [ "//url" ]
+}
+
 source_set("unit_tests") {
   configs += [ "//build/config/compiler:enable_arc" ]
   testonly = true
diff --git a/ios/chrome/browser/ui/util/ui_util.h b/ios/chrome/browser/ui/util/ui_util.h
index aa3088a..4b70376d 100644
--- a/ios/chrome/browser/ui/util/ui_util.h
+++ b/ios/chrome/browser/ui/util/ui_util.h
@@ -14,9 +14,6 @@
 // ui/base/device_form_factor.h instead.
 bool IsIPadIdiom();
 
-// Enum for arrays by UI idiom.
-enum InterfaceIdiom { IPHONE_IDIOM, IPAD_IDIOM, INTERFACE_IDIOM_COUNT };
-
 // Returns the height of the screen in the current orientation.
 CGFloat CurrentScreenHeight();
 
diff --git a/ios/chrome/browser/ui/activity_services/data/url_with_title.h b/ios/chrome/browser/ui/util/url_with_title.h
similarity index 74%
rename from ios/chrome/browser/ui/activity_services/data/url_with_title.h
rename to ios/chrome/browser/ui/util/url_with_title.h
index e25a4f21..3d9344fe 100644
--- a/ios/chrome/browser/ui/activity_services/data/url_with_title.h
+++ b/ios/chrome/browser/ui/util/url_with_title.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_CHROME_BROWSER_UI_ACTIVITY_SERVICES_DATA_URL_WITH_TITLE_H_
-#define IOS_CHROME_BROWSER_UI_ACTIVITY_SERVICES_DATA_URL_WITH_TITLE_H_
+#ifndef IOS_CHROME_BROWSER_UI_UTIL_URL_WITH_TITLE_H_
+#define IOS_CHROME_BROWSER_UI_UTIL_URL_WITH_TITLE_H_
 
 #include <url/gurl.h>
 
@@ -23,4 +23,4 @@
 
 @end
 
-#endif  // IOS_CHROME_BROWSER_UI_ACTIVITY_SERVICES_DATA_URL_WITH_TITLE_H_
+#endif  // IOS_CHROME_BROWSER_UI_UTIL_URL_WITH_TITLE_H_
diff --git a/ios/chrome/browser/ui/activity_services/data/url_with_title.mm b/ios/chrome/browser/ui/util/url_with_title.mm
similarity index 89%
rename from ios/chrome/browser/ui/activity_services/data/url_with_title.mm
rename to ios/chrome/browser/ui/util/url_with_title.mm
index 193b50a6..2111ba4 100644
--- a/ios/chrome/browser/ui/activity_services/data/url_with_title.mm
+++ b/ios/chrome/browser/ui/util/url_with_title.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ios/chrome/browser/ui/activity_services/data/url_with_title.h"
+#import "ios/chrome/browser/ui/util/url_with_title.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -31,4 +31,4 @@
   return _URL;
 }
 
-@end
\ No newline at end of file
+@end
diff --git a/ios/chrome/browser/web/web_navigation_ntp_delegate.h b/ios/chrome/browser/web/web_navigation_ntp_delegate.h
index a4c9499f..6a6e6f20 100644
--- a/ios/chrome/browser/web/web_navigation_ntp_delegate.h
+++ b/ios/chrome/browser/web/web_navigation_ntp_delegate.h
@@ -5,6 +5,8 @@
 #ifndef IOS_CHROME_BROWSER_WEB_WEB_NAVIGATION_NTP_DELEGATE_H_
 #define IOS_CHROME_BROWSER_WEB_WEB_NAVIGATION_NTP_DELEGATE_H_
 
+#include <CoreFoundation/CoreFoundation.h>
+
 namespace web {
 class WebState;
 }
diff --git a/ios/chrome/test/earl_grey/chrome_matchers.h b/ios/chrome/test/earl_grey/chrome_matchers.h
index 90d3097..7694acec 100644
--- a/ios/chrome/test/earl_grey/chrome_matchers.h
+++ b/ios/chrome/test/earl_grey/chrome_matchers.h
@@ -597,6 +597,9 @@
 // Returns a matcher for the button to enter the tab grid tab edit mode.
 id<GREYMatcher> TabGridEditButton();
 
+// Returns a matcher for the button to act on the selected tabs.
+id<GREYMatcher> TabGridEditAddToButton();
+
 // Returns a matcher for the button to close the selected tabs.
 id<GREYMatcher> TabGridEditCloseTabsButton();
 
diff --git a/ios/chrome/test/earl_grey/chrome_matchers.mm b/ios/chrome/test/earl_grey/chrome_matchers.mm
index 08885ac..db48b193 100644
--- a/ios/chrome/test/earl_grey/chrome_matchers.mm
+++ b/ios/chrome/test/earl_grey/chrome_matchers.mm
@@ -755,6 +755,10 @@
   return [ChromeMatchersAppInterface tabGridEditButton];
 }
 
+id<GREYMatcher> TabGridEditAddToButton() {
+  return [ChromeMatchersAppInterface tabGridEditAddToButton];
+}
+
 id<GREYMatcher> TabGridEditCloseTabsButton() {
   return [ChromeMatchersAppInterface tabGridEditCloseTabsButton];
 }
diff --git a/ios/chrome/test/earl_grey/chrome_matchers_app_interface.h b/ios/chrome/test/earl_grey/chrome_matchers_app_interface.h
index a98d663..c562a24 100644
--- a/ios/chrome/test/earl_grey/chrome_matchers_app_interface.h
+++ b/ios/chrome/test/earl_grey/chrome_matchers_app_interface.h
@@ -589,6 +589,9 @@
 // Returns a matcher for the button to enter the tab grid tab edit mode.
 + (id<GREYMatcher>)tabGridEditButton;
 
+// Returns a matcher for the button to act on the selected tabs.
++ (id<GREYMatcher>)tabGridEditAddToButton;
+
 // Returns a matcher for the button to close the selected tabs.
 + (id<GREYMatcher>)tabGridEditCloseTabsButton;
 
diff --git a/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm b/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm
index e45ca9a..66ea957 100644
--- a/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm
+++ b/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm
@@ -1136,6 +1136,11 @@
                     grey_sufficientlyVisible(), nil);
 }
 
++ (id<GREYMatcher>)tabGridEditAddToButton {
+  return grey_allOf(grey_accessibilityID(kTabGridEditAddToButtonIdentifier),
+                    grey_sufficientlyVisible(), nil);
+}
+
 + (id<GREYMatcher>)tabGridEditCloseTabsButton {
   return grey_allOf(grey_accessibilityID(kTabGridEditCloseTabsButtonIdentifier),
                     grey_sufficientlyVisible(), nil);
diff --git a/ios/chrome/test/wpt/cwt_request_handler.mm b/ios/chrome/test/wpt/cwt_request_handler.mm
index 3dc12c3..d1bcfa5a 100644
--- a/ios/chrome/test/wpt/cwt_request_handler.mm
+++ b/ios/chrome/test/wpt/cwt_request_handler.mm
@@ -428,7 +428,7 @@
 }
 
 base::Value CWTRequestHandler::SetTimeouts(const base::Value& timeouts) {
-  for (const auto& timeout : timeouts.DictItems()) {
+  for (const auto timeout : timeouts.DictItems()) {
     if (!timeout.second.is_int() || timeout.second.GetInt() < 0) {
       return CreateErrorValue(kWebDriverInvalidArgumentError,
                               kWebDriverInvalidTimeoutMessage);
diff --git a/ios/net/http_cache_helper.cc b/ios/net/http_cache_helper.cc
index 1936e99..a74887c 100644
--- a/ios/net/http_cache_helper.cc
+++ b/ios/net/http_cache_helper.cc
@@ -12,6 +12,7 @@
 #include "base/location.h"
 #include "base/task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
 #include "net/base/completion_repeating_callback.h"
 #include "net/disk_cache/disk_cache.h"
 #include "net/http/http_cache.h"
diff --git a/ios/net/http_cache_helper.h b/ios/net/http_cache_helper.h
index c8a7c77..9da4204 100644
--- a/ios/net/http_cache_helper.h
+++ b/ios/net/http_cache_helper.h
@@ -11,6 +11,7 @@
 
 namespace base {
 class TaskRunner;
+class Time;
 }
 
 namespace net {
diff --git a/ios/public/provider/chrome/browser/BUILD.gn b/ios/public/provider/chrome/browser/BUILD.gn
index c494a083..43fb8e0 100644
--- a/ios/public/provider/chrome/browser/BUILD.gn
+++ b/ios/public/provider/chrome/browser/BUILD.gn
@@ -38,14 +38,15 @@
   deps = [
     "//base",
     "//ios/web/public",
-    "//ios/web/public/js_messaging",
   ]
+  public_deps = [ "//ios/web/public/js_messaging" ]
 }
 
 group("provider_api") {
   deps = [
     # The individual APIs.
     "//ios/public/provider/chrome/browser/modals:modals_api",
+    "//ios/public/provider/chrome/browser/text_zoom:text_zoom_api",
   ]
 }
 
@@ -95,6 +96,7 @@
 
     # The individual API implementations.
     "//ios/public/provider/chrome/browser/modals:test_modals",
+    "//ios/public/provider/chrome/browser/text_zoom:test_text_zoom",
 
     # The provider API needs to provide MaterialDesignComponent API (as the
     # internal provider provides an alternate implementation).
diff --git a/ios/public/provider/chrome/browser/signin/chrome_identity_service.h b/ios/public/provider/chrome/browser/signin/chrome_identity_service.h
index fb78426f..3d6398b3 100644
--- a/ios/public/provider/chrome/browser/signin/chrome_identity_service.h
+++ b/ios/public/provider/chrome/browser/signin/chrome_identity_service.h
@@ -5,6 +5,8 @@
 #ifndef IOS_PUBLIC_PROVIDER_CHROME_BROWSER_SIGNIN_CHROME_IDENTITY_SERVICE_H_
 #define IOS_PUBLIC_PROVIDER_CHROME_BROWSER_SIGNIN_CHROME_IDENTITY_SERVICE_H_
 
+#include <CoreFoundation/CoreFoundation.h>
+
 #include <set>
 #include <string>
 #include <vector>
diff --git a/ios/public/provider/chrome/browser/signin/chrome_trusted_vault_service.h b/ios/public/provider/chrome/browser/signin/chrome_trusted_vault_service.h
index ef806f1..2a52356 100644
--- a/ios/public/provider/chrome/browser/signin/chrome_trusted_vault_service.h
+++ b/ios/public/provider/chrome/browser/signin/chrome_trusted_vault_service.h
@@ -5,6 +5,8 @@
 #ifndef IOS_PUBLIC_PROVIDER_CHROME_BROWSER_SIGNIN_CHROME_TRUSTED_VAULT_SERVICE_H_
 #define IOS_PUBLIC_PROVIDER_CHROME_BROWSER_SIGNIN_CHROME_TRUSTED_VAULT_SERVICE_H_
 
+#include <CoreFoundation/CoreFoundation.h>
+
 #include <memory>
 #include <vector>
 
diff --git a/ios/public/provider/chrome/browser/text_zoom/BUILD.gn b/ios/public/provider/chrome/browser/text_zoom/BUILD.gn
new file mode 100644
index 0000000..c339c5d
--- /dev/null
+++ b/ios/public/provider/chrome/browser/text_zoom/BUILD.gn
@@ -0,0 +1,18 @@
+# Copyright 2021 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("text_zoom_api") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [ "text_zoom_api.h" ]
+}
+
+source_set("test_text_zoom") {
+  testonly = true
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [ "test_text_zoom.mm" ]
+  deps = [
+    ":text_zoom_api",
+    "//ios/public/provider/chrome/browser:font_size_java_script_feature",
+  ]
+}
diff --git a/ios/public/provider/chrome/browser/text_zoom/test_text_zoom.mm b/ios/public/provider/chrome/browser/text_zoom/test_text_zoom.mm
new file mode 100644
index 0000000..4777b3b
--- /dev/null
+++ b/ios/public/provider/chrome/browser/text_zoom/test_text_zoom.mm
@@ -0,0 +1,24 @@
+// Copyright 2021 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/public/provider/chrome/browser/font_size_java_script_feature.h"
+#import "ios/public/provider/chrome/browser/text_zoom/text_zoom_api.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace ios {
+namespace provider {
+
+void SetTextZoomForWebState(web::WebState* web_state, int size) {
+  FontSizeJavaScriptFeature::GetInstance()->AdjustFontSize(web_state, size);
+}
+
+bool IsTextZoomEnabled() {
+  return true;
+}
+
+}  // namespace provider
+}  // namespace ios
diff --git a/ios/public/provider/chrome/browser/text_zoom/text_zoom_api.h b/ios/public/provider/chrome/browser/text_zoom/text_zoom_api.h
new file mode 100644
index 0000000..205c55d
--- /dev/null
+++ b/ios/public/provider/chrome/browser/text_zoom/text_zoom_api.h
@@ -0,0 +1,25 @@
+// Copyright 2021 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_PUBLIC_PROVIDER_CHROME_BROWSER_TEXT_ZOOM_TEXT_ZOOM_API_H_
+#define IOS_PUBLIC_PROVIDER_CHROME_BROWSER_TEXT_ZOOM_TEXT_ZOOM_API_H_
+
+namespace web {
+class WebState;
+}  // namespace web
+
+namespace ios {
+namespace provider {
+
+// Zooms the given web_state to the provided size as a percentage. I.e. a size
+// of 100 corresponds to a zoom of 100%.
+void SetTextZoomForWebState(web::WebState* web_state, int size);
+
+// Returns whether text zoom is enabled currently.
+bool IsTextZoomEnabled();
+
+}  // namespace provider
+}  // namespace ios
+
+#endif  // IOS_PUBLIC_PROVIDER_CHROME_BROWSER_TEXT_ZOOM_TEXT_ZOOM_API_H_
diff --git a/ios/web/js_messaging/java_script_feature.mm b/ios/web/js_messaging/java_script_feature.mm
index ac27113..9a65146 100644
--- a/ios/web/js_messaging/java_script_feature.mm
+++ b/ios/web/js_messaging/java_script_feature.mm
@@ -8,6 +8,7 @@
 
 #include "base/bind.h"
 #import "base/strings/sys_string_conversions.h"
+#include "base/time/time.h"
 #import "ios/web/js_messaging/java_script_content_world.h"
 #import "ios/web/js_messaging/java_script_feature_manager.h"
 #include "ios/web/js_messaging/page_script_util.h"
diff --git a/ios/web/public/js_messaging/BUILD.gn b/ios/web/public/js_messaging/BUILD.gn
index 8796351..1645c69 100644
--- a/ios/web/public/js_messaging/BUILD.gn
+++ b/ios/web/public/js_messaging/BUILD.gn
@@ -8,6 +8,7 @@
     "//ios/web/public/",
     "//url",
   ]
+  public_deps = [ "//third_party/abseil-cpp:absl" ]
 
   sources = [
     "java_script_feature.h",
diff --git a/ios/web/public/js_messaging/java_script_feature.h b/ios/web/public/js_messaging/java_script_feature.h
index 31728d5..7e320c6 100644
--- a/ios/web/public/js_messaging/java_script_feature.h
+++ b/ios/web/public/js_messaging/java_script_feature.h
@@ -15,6 +15,7 @@
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace base {
+class TimeDelta;
 class Value;
 }  // namespace base
 
diff --git a/ios/web/test/fakes/fake_java_script_feature.mm b/ios/web/test/fakes/fake_java_script_feature.mm
index 885ab1c9..27e3d83 100644
--- a/ios/web/test/fakes/fake_java_script_feature.mm
+++ b/ios/web/test/fakes/fake_java_script_feature.mm
@@ -4,6 +4,8 @@
 
 #import "ios/web/test/fakes/fake_java_script_feature.h"
 
+#include "base/time/time.h"
+
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
diff --git a/ios/web/web_state/ui/wk_web_view_configuration_provider.h b/ios/web/web_state/ui/wk_web_view_configuration_provider.h
index 9c67e519..af41db8 100644
--- a/ios/web/web_state/ui/wk_web_view_configuration_provider.h
+++ b/ios/web/web_state/ui/wk_web_view_configuration_provider.h
@@ -5,6 +5,8 @@
 #ifndef IOS_WEB_WEB_STATE_UI_WK_WEB_VIEW_CONFIGURATION_PROVIDER_H_
 #define IOS_WEB_WEB_STATE_UI_WK_WEB_VIEW_CONFIGURATION_PROVIDER_H_
 
+#include <CoreFoundation/CoreFoundation.h>
+
 #include "base/macros.h"
 #include "base/observer_list.h"
 #include "base/supports_user_data.h"
diff --git a/ios/web/webui/crw_web_ui_scheme_handler.mm b/ios/web/webui/crw_web_ui_scheme_handler.mm
index 824acb3..569206a9 100644
--- a/ios/web/webui/crw_web_ui_scheme_handler.mm
+++ b/ios/web/webui/crw_web_ui_scheme_handler.mm
@@ -6,6 +6,7 @@
 
 #include <map>
 
+#include "base/files/file_path.h"
 #import "ios/web/webui/url_fetcher_block_adapter.h"
 #include "ios/web/webui/web_ui_ios_controller_factory_registry.h"
 #import "net/base/mac/url_conversions.h"
diff --git a/ios/web/webui/mojo_facade.mm b/ios/web/webui/mojo_facade.mm
index 7ed844bf..3ea9d20 100644
--- a/ios/web/webui/mojo_facade.mm
+++ b/ios/web/webui/mojo_facade.mm
@@ -148,7 +148,7 @@
   }
 
   std::vector<uint8_t> bytes(buffer->DictSize());
-  for (const auto& item : buffer->DictItems()) {
+  for (const auto item : buffer->DictItems()) {
     size_t index = std::numeric_limits<size_t>::max();
     CHECK(base::StringToSizeT(item.first, &index));
     CHECK(index < bytes.size());
diff --git a/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm_to_proto_macros.tmpl b/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm_to_proto_macros.tmpl
index 38c68ea2..f50b9ef 100644
--- a/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm_to_proto_macros.tmpl
+++ b/mojo/public/tools/bindings/generators/mojolpm_templates/mojolpm_to_proto_macros.tmpl
@@ -83,7 +83,7 @@
   {{type}}& output) {
   bool result = true;
 
-  for ({{maybe_const}}auto& in_value : input) {
+  for (auto&& in_value : input) {
 {%-   if kind.kind|is_nullable_kind %}
     {{type}}Entry* out_value = output.mutable_values()->Add();
     if ({{util.not_null(kind.kind, 'in_value')}}) {
diff --git a/net/http/http_server_properties_manager_unittest.cc b/net/http/http_server_properties_manager_unittest.cc
index 6789101..5db0412 100644
--- a/net/http/http_server_properties_manager_unittest.cc
+++ b/net/http/http_server_properties_manager_unittest.cc
@@ -1515,8 +1515,8 @@
       "\"isolation\":[],"
       "\"server\":\"https://www.google.com:80\"},"
       "{\"alternative_service\":[{"
-      "\"advertised_alpns\":[\"h3-Q050\",\"h3-29\"],\"expiration\":"
-      "\"9223372036854775807\","
+      "\"advertised_alpns\":[\"h3\",\"h3-29\",\"h3-Q050\"],"
+      "\"expiration\":\"9223372036854775807\","
       "\"host\":\"foo.google.com\",\"port\":444,\"protocol_str\":\"quic\"}],"
       "\"isolation\":[],"
       "\"network_stats\":{\"srtt\":42},"
@@ -1627,7 +1627,8 @@
       "\"server_id\":\"https://mail.google.com:80\","
       "\"server_info\":\"quic_server_info1\"}],"
       "\"servers\":["
-      "{\"alternative_service\":[{\"advertised_alpns\":[\"h3-Q050\",\"h3-29\"],"
+      "{\"alternative_service\":[{"
+      "\"advertised_alpns\":[\"h3\",\"h3-29\",\"h3-Q050\"],"
       "\"expiration\":\"13756212000000000\",\"port\":443,"
       "\"protocol_str\":\"quic\"}],"
       "\"isolation\":[],"
diff --git a/net/http/http_stream_factory_job_controller_unittest.cc b/net/http/http_stream_factory_job_controller_unittest.cc
index 21308bf..623db362 100644
--- a/net/http/http_stream_factory_job_controller_unittest.cc
+++ b/net/http/http_stream_factory_job_controller_unittest.cc
@@ -200,6 +200,7 @@
   HttpStreamFactoryJobControllerTest()
       : TestWithTaskEnvironment(
             base::test::TaskEnvironment::TimeSource::MOCK_TIME) {
+    FLAGS_quic_enable_http3_grease_randomness = false;
     session_deps_.enable_quic = true;
     session_deps_.host_resolver->set_synchronous_mode(true);
   }
@@ -2934,7 +2935,14 @@
       [](const quic::ParsedQuicVersion& a, const quic::ParsedQuicVersion& b) {
         return a.transport_version < b.transport_version;
       });
-  EXPECT_EQ(supported_versions, alt_svc_info.advertised_versions());
+  quic::ParsedQuicVersionVector advertised_versions =
+      alt_svc_info.advertised_versions();
+  std::sort(
+      advertised_versions.begin(), advertised_versions.end(),
+      [](const quic::ParsedQuicVersion& a, const quic::ParsedQuicVersion& b) {
+        return a.transport_version < b.transport_version;
+      });
+  EXPECT_EQ(supported_versions, advertised_versions);
 
   quic::ParsedQuicVersion unsupported_version_1 =
       quic::ParsedQuicVersion::Unsupported();
@@ -3107,8 +3115,15 @@
       [](const quic::ParsedQuicVersion& a, const quic::ParsedQuicVersion& b) {
         return a.transport_version < b.transport_version;
       });
+  quic::ParsedQuicVersionVector advertised_versions =
+      alt_svc_info.advertised_versions();
+  std::sort(
+      advertised_versions.begin(), advertised_versions.end(),
+      [](const quic::ParsedQuicVersion& a, const quic::ParsedQuicVersion& b) {
+        return a.transport_version < b.transport_version;
+      });
   EXPECT_EQ(kProtoQUIC, alt_svc_info.alternative_service().protocol);
-  EXPECT_EQ(supported_versions, alt_svc_info.advertised_versions());
+  EXPECT_EQ(supported_versions, advertised_versions);
 
   session_->http_server_properties()->SetQuicAlternativeService(
       server, NetworkIsolationKey(),
diff --git a/net/quic/quic_context.h b/net/quic/quic_context.h
index 403b4a5..736440f8 100644
--- a/net/quic/quic_context.h
+++ b/net/quic/quic_context.h
@@ -20,12 +20,10 @@
   // The ordering of this list does not matter for Chrome because it respects
   // the ordering received from the server via Alt-Svc. However, cronet offers
   // an addQuicHint() API which uses the first version from this list until
-  // it receives Alt-Svc from the server. We therefore list Q050 first here
-  // because there are some cronet applications which communicate with servers
-  // that speak Q050 but not Draft29.
-  // TODO(dschinazi) Move Draft29 first once those servers support it.
-  return quic::ParsedQuicVersionVector{quic::ParsedQuicVersion::Q050(),
-                                       quic::ParsedQuicVersion::Draft29()};
+  // it receives Alt-Svc from the server.
+  return quic::ParsedQuicVersionVector{quic::ParsedQuicVersion::RFCv1(),
+                                       quic::ParsedQuicVersion::Draft29(),
+                                       quic::ParsedQuicVersion::Q050()};
 }
 
 // Obsolete QUIC supported versions are versions that are supported by the
diff --git a/rlz/chromeos/lib/rlz_value_store_chromeos.cc b/rlz/chromeos/lib/rlz_value_store_chromeos.cc
index 58c00703..62ec0a9 100644
--- a/rlz/chromeos/lib/rlz_value_store_chromeos.cc
+++ b/rlz/chromeos/lib/rlz_value_store_chromeos.cc
@@ -163,7 +163,7 @@
     case base::Value::Type::DICTIONARY: {
       base::Value::DictStorage storage;
 
-      for (const auto& key_value_pair : value.DictItems()) {
+      for (const auto key_value_pair : value.DictItems()) {
         absl::optional<base::Value> item_copy =
             CopyWithoutEmptyChildren(key_value_pair.second);
         if (item_copy)
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index e458ba1..ace74b8 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -1050,8 +1050,8 @@
 void NetworkContext::GetDomainReliabilityJSON(
     GetDomainReliabilityJSONCallback callback) {
   if (!domain_reliability_monitor_) {
-    base::DictionaryValue data;
-    data.SetString("error", "no_service");
+    base::Value data(base::Value::Type::DICTIONARY);
+    data.SetStringKey("error", "no_service");
     std::move(callback).Run(std::move(data));
     return;
   }
@@ -1221,7 +1221,7 @@
     const std::string& domain,
     const net::NetworkIsolationKey& network_isolation_key,
     GetExpectCTStateCallback callback) {
-  base::DictionaryValue result;
+  base::Value result(base::Value::Type::DICTIONARY);
   if (base::IsStringASCII(domain)) {
     net::TransportSecurityState* transport_security_state =
         url_request_context()->transport_security_state();
@@ -1232,23 +1232,23 @@
 
       // TODO(estark): query static Expect-CT state as well.
       if (found) {
-        result.SetString("dynamic_expect_ct_domain", domain);
-        result.SetDouble("dynamic_expect_ct_observed",
-                         dynamic_expect_ct_state.last_observed.ToDoubleT());
-        result.SetDouble("dynamic_expect_ct_expiry",
-                         dynamic_expect_ct_state.expiry.ToDoubleT());
-        result.SetBoolean("dynamic_expect_ct_enforce",
+        result.SetStringKey("dynamic_expect_ct_domain", domain);
+        result.SetDoubleKey("dynamic_expect_ct_observed",
+                            dynamic_expect_ct_state.last_observed.ToDoubleT());
+        result.SetDoubleKey("dynamic_expect_ct_expiry",
+                            dynamic_expect_ct_state.expiry.ToDoubleT());
+        result.SetBoolKey("dynamic_expect_ct_enforce",
                           dynamic_expect_ct_state.enforce);
-        result.SetString("dynamic_expect_ct_report_uri",
-                         dynamic_expect_ct_state.report_uri.spec());
+        result.SetStringKey("dynamic_expect_ct_report_uri",
+                            dynamic_expect_ct_state.report_uri.spec());
       }
 
-      result.SetBoolean("result", found);
+      result.SetBoolKey("result", found);
     } else {
-      result.SetString("error", "no Expect-CT state active");
+      result.SetStringKey("error", "no Expect-CT state active");
     }
   } else {
-    result.SetString("error", "non-ASCII domain name");
+    result.SetStringKey("error", "non-ASCII domain name");
   }
 
   std::move(callback).Run(std::move(result));
@@ -1559,7 +1559,7 @@
 
 void NetworkContext::GetHSTSState(const std::string& domain,
                                   GetHSTSStateCallback callback) {
-  base::DictionaryValue result;
+  base::Value result(base::Value::Type::DICTIONARY);
 
   if (base::IsStringASCII(domain)) {
     net::TransportSecurityState* transport_security_state =
@@ -1570,24 +1570,24 @@
       bool found_static = transport_security_state->GetStaticDomainState(
           domain, &static_sts_state, &static_pkp_state);
       if (found_static) {
-        result.SetInteger("static_upgrade_mode",
-                          static_cast<int>(static_sts_state.upgrade_mode));
-        result.SetBoolean("static_sts_include_subdomains",
+        result.SetIntKey("static_upgrade_mode",
+                         static_cast<int>(static_sts_state.upgrade_mode));
+        result.SetBoolKey("static_sts_include_subdomains",
                           static_sts_state.include_subdomains);
-        result.SetDouble("static_sts_observed",
-                         static_sts_state.last_observed.ToDoubleT());
-        result.SetDouble("static_sts_expiry",
-                         static_sts_state.expiry.ToDoubleT());
-        result.SetBoolean("static_pkp_include_subdomains",
+        result.SetDoubleKey("static_sts_observed",
+                            static_sts_state.last_observed.ToDoubleT());
+        result.SetDoubleKey("static_sts_expiry",
+                            static_sts_state.expiry.ToDoubleT());
+        result.SetBoolKey("static_pkp_include_subdomains",
                           static_pkp_state.include_subdomains);
-        result.SetDouble("static_pkp_observed",
-                         static_pkp_state.last_observed.ToDoubleT());
-        result.SetDouble("static_pkp_expiry",
-                         static_pkp_state.expiry.ToDoubleT());
-        result.SetString("static_spki_hashes",
-                         HashesToBase64String(static_pkp_state.spki_hashes));
-        result.SetString("static_sts_domain", static_sts_state.domain);
-        result.SetString("static_pkp_domain", static_pkp_state.domain);
+        result.SetDoubleKey("static_pkp_observed",
+                            static_pkp_state.last_observed.ToDoubleT());
+        result.SetDoubleKey("static_pkp_expiry",
+                            static_pkp_state.expiry.ToDoubleT());
+        result.SetStringKey("static_spki_hashes",
+                            HashesToBase64String(static_pkp_state.spki_hashes));
+        result.SetStringKey("static_sts_domain", static_sts_state.domain);
+        result.SetStringKey("static_pkp_domain", static_pkp_state.domain);
       }
 
       net::TransportSecurityState::STSState dynamic_sts_state;
@@ -1598,36 +1598,37 @@
       bool found_pkp_dynamic = transport_security_state->GetDynamicPKPState(
           domain, &dynamic_pkp_state);
       if (found_sts_dynamic) {
-        result.SetInteger("dynamic_upgrade_mode",
-                          static_cast<int>(dynamic_sts_state.upgrade_mode));
-        result.SetBoolean("dynamic_sts_include_subdomains",
+        result.SetIntKey("dynamic_upgrade_mode",
+                         static_cast<int>(dynamic_sts_state.upgrade_mode));
+        result.SetBoolKey("dynamic_sts_include_subdomains",
                           dynamic_sts_state.include_subdomains);
-        result.SetDouble("dynamic_sts_observed",
-                         dynamic_sts_state.last_observed.ToDoubleT());
-        result.SetDouble("dynamic_sts_expiry",
-                         dynamic_sts_state.expiry.ToDoubleT());
-        result.SetString("dynamic_sts_domain", dynamic_sts_state.domain);
+        result.SetDoubleKey("dynamic_sts_observed",
+                            dynamic_sts_state.last_observed.ToDoubleT());
+        result.SetDoubleKey("dynamic_sts_expiry",
+                            dynamic_sts_state.expiry.ToDoubleT());
+        result.SetStringKey("dynamic_sts_domain", dynamic_sts_state.domain);
       }
 
       if (found_pkp_dynamic) {
-        result.SetBoolean("dynamic_pkp_include_subdomains",
+        result.SetBoolKey("dynamic_pkp_include_subdomains",
                           dynamic_pkp_state.include_subdomains);
-        result.SetDouble("dynamic_pkp_observed",
-                         dynamic_pkp_state.last_observed.ToDoubleT());
-        result.SetDouble("dynamic_pkp_expiry",
-                         dynamic_pkp_state.expiry.ToDoubleT());
-        result.SetString("dynamic_spki_hashes",
-                         HashesToBase64String(dynamic_pkp_state.spki_hashes));
-        result.SetString("dynamic_pkp_domain", dynamic_pkp_state.domain);
+        result.SetDoubleKey("dynamic_pkp_observed",
+                            dynamic_pkp_state.last_observed.ToDoubleT());
+        result.SetDoubleKey("dynamic_pkp_expiry",
+                            dynamic_pkp_state.expiry.ToDoubleT());
+        result.SetStringKey(
+            "dynamic_spki_hashes",
+            HashesToBase64String(dynamic_pkp_state.spki_hashes));
+        result.SetStringKey("dynamic_pkp_domain", dynamic_pkp_state.domain);
       }
 
-      result.SetBoolean("result",
+      result.SetBoolKey("result",
                         found_static || found_sts_dynamic || found_pkp_dynamic);
     } else {
-      result.SetString("error", "no TransportSecurityState active");
+      result.SetStringKey("error", "no TransportSecurityState active");
     }
   } else {
-    result.SetString("error", "non-ASCII domain name");
+    result.SetStringKey("error", "non-ASCII domain name");
   }
 
   std::move(callback).Run(std::move(result));
diff --git a/skia/OWNERS b/skia/OWNERS
index dd0fc59..7fec08d 100644
--- a/skia/OWNERS
+++ b/skia/OWNERS
@@ -1,5 +1,4 @@
 set noparent
-alokp@chromium.org
 borenet@google.com
 brianosman@google.com
 bsalomon@google.com
diff --git a/sql/meta_table.cc b/sql/meta_table.cc
index f43d43e..c11e85b 100644
--- a/sql/meta_table.cc
+++ b/sql/meta_table.cc
@@ -68,23 +68,31 @@
 }
 
 // static
-void MetaTable::RazeIfDeprecated(Database* db, int deprecated_version) {
-  DCHECK_GT(deprecated_version, 0);
-  DCHECK_EQ(0, db->transaction_nesting());
-
-  if (!DoesTableExist(db))
+void MetaTable::RazeIfIncompatible(Database* db,
+                                   int lowest_supported_version,
+                                   int current_version) {
+  if (!sql::MetaTable::DoesTableExist(db))
     return;
 
-  // TODO(shess): Share sql with PrepareGetStatement().
-  sql::Statement s(db->GetUniqueStatement(
-                       "SELECT value FROM meta WHERE key=?"));
+  // TODO(crbug.com/1228463): Share sql with PrepareGetStatement().
+  sql::Statement s(
+      db->GetUniqueStatement("SELECT value FROM meta WHERE key=?"));
   s.BindCString(0, kVersionKey);
   if (!s.Step())
     return;
+  int on_disk_schema_version = s.ColumnInt(0);
 
-  int version = s.ColumnInt(0);
+  s.Assign(db->GetUniqueStatement("SELECT value FROM meta WHERE key=?"));
+  s.BindCString(0, kCompatibleVersionKey);
+  if (!s.Step())
+    return;
+  int on_disk_compatible_version = s.ColumnInt(0);
+
   s.Clear();  // Clear potential automatic transaction for Raze().
-  if (version <= deprecated_version) {
+
+  if ((lowest_supported_version != kNoLowestSupportedVersion &&
+       lowest_supported_version > on_disk_schema_version) ||
+      (current_version < on_disk_compatible_version)) {
     db->Raze();
     return;
   }
@@ -205,15 +213,15 @@
 
 void MetaTable::PrepareSetStatement(Statement* statement, const char* key) {
   DCHECK(db_ && statement);
-  statement->Assign(db_->GetCachedStatement(SQL_FROM_HERE,
-      "INSERT OR REPLACE INTO meta (key,value) VALUES (?,?)"));
+  statement->Assign(db_->GetCachedStatement(
+      SQL_FROM_HERE, "INSERT OR REPLACE INTO meta (key,value) VALUES (?,?)"));
   statement->BindCString(0, key);
 }
 
 bool MetaTable::PrepareGetStatement(Statement* statement, const char* key) {
   DCHECK(db_ && statement);
-  statement->Assign(db_->GetCachedStatement(SQL_FROM_HERE,
-      "SELECT value FROM meta WHERE key=?"));
+  statement->Assign(db_->GetCachedStatement(
+      SQL_FROM_HERE, "SELECT value FROM meta WHERE key=?"));
   statement->BindCString(0, key);
   return statement->Step();
 }
diff --git a/sql/meta_table.h b/sql/meta_table.h
index 8ffbc8b..f723ea8 100644
--- a/sql/meta_table.h
+++ b/sql/meta_table.h
@@ -9,6 +9,8 @@
 #include <string>
 
 #include "base/component_export.h"
+#include "base/macros.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace sql {
 
@@ -28,9 +30,9 @@
   MetaTable& operator=(const MetaTable&) = delete;
   ~MetaTable();
 
-  // Values for Get/SetMmapStatus(). |kMmapFailure| indicates that there was at
+  // Values for Get/SetMmapStatus(). `kMmapFailure` indicates that there was at
   // some point a read error and the database should not be memory-mapped, while
-  // |kMmapSuccess| indicates that the entire file was read at some point and
+  // `kMmapSuccess` indicates that the entire file was read at some point and
   // can be memory-mapped without constraint.
   static constexpr int64_t kMmapFailure = -2;
   static constexpr int64_t kMmapSuccess = -1;
@@ -43,32 +45,37 @@
   // table existed).
   static bool DeleteTableForTesting(Database* db);
 
-  // If the current version of the database is less than or equal to
-  // |deprecated_version|, raze the database. Must be called outside of a
-  // transaction.
-  // TODO(shess): At this time the database is razed IFF meta exists and
-  // contains a version row with value <= deprecated_version. It may make sense
-  // to also raze if meta exists but has no version row, or if meta doesn't
-  // exist. In those cases if the database is not already empty, it probably
-  // resulted from a broken initialization.
-  // TODO(shess): Folding this into Init() would allow enforcing
-  // |deprecated_version|<|version|. But Init() is often called in a
-  // transaction.
-  static void RazeIfDeprecated(Database* db, int deprecated_version);
+  // If the current version of the database is less than
+  // `lowest_supported_version`, or the current version is less than the
+  // database's least compatible version, razes the database. To only enforce
+  // the latter, pass `kNoLowestSupportedVersion` for
+  // `lowest_supported_version`.
+  //
+  // TODO(crbug.com/1228463): At this time the database is razed IFF meta exists
+  // and contains a version row with the value not satisfying the constraints.
+  // It may make sense to also raze if meta exists but has no version row, or if
+  // meta doesn't exist. In those cases if the database is not already empty, it
+  // probably resulted from a broken initialization.
+  // TODO(crbug.com/1228463): Folding this into Init() would allow enforcing
+  // the version constraint, but Init() is often called in a transaction.
+  static constexpr int kNoLowestSupportedVersion = 0;
+  static void RazeIfIncompatible(Database* db,
+                                 int lowest_supported_version,
+                                 int current_version);
 
   // Used to tuck some data into the meta table about mmap status. The value
   // represents how much data in bytes has successfully been read from the
-  // database, or |kMmapFailure| or |kMmapSuccess|.
+  // database, or `kMmapFailure` or `kMmapSuccess`.
   static bool GetMmapStatus(Database* db, int64_t* status);
   static bool SetMmapStatus(Database* db, int64_t status);
 
-  // Initializes the MetaTableHelper, providing the |Database| pointer and
+  // Initializes the MetaTableHelper, providing the `Database` pointer and
   // creating the meta table if necessary. Must be called before any other
   // non-static methods. For new tables, it will initialize the version number
-  // to |version| and the compatible version number to |compatible_version|.
+  // to `version` and the compatible version number to `compatible_version`.
   // Versions must be greater than 0 to distinguish missing versions (see
   // GetVersionNumber()). If there was no meta table (proxy for a fresh
-  // database), mmap status is set to |kMmapSuccess|.
+  // database), mmap status is set to `kMmapSuccess`.
   bool Init(Database* db, int version, int compatible_version);
 
   // Resets this MetaTable object, making another call to Init() possible.
diff --git a/sql/meta_table_unittest.cc b/sql/meta_table_unittest.cc
index 19a3d1f..4f7ff2e 100644
--- a/sql/meta_table_unittest.cc
+++ b/sql/meta_table_unittest.cc
@@ -50,62 +50,97 @@
   EXPECT_FALSE(MetaTable::DoesTableExist(&db_));
 }
 
-TEST_F(SQLMetaTableTest, RazeIfDeprecated) {
-  const int kDeprecatedVersion = 1;
-  const int kVersion = 2;
+TEST_F(SQLMetaTableTest, RazeIfIncompatiblePreservesDatabasesWithoutMetadata) {
+  EXPECT_TRUE(db_.Execute("CREATE TABLE data(id INTEGER PRIMARY KEY)"));
+  ASSERT_TRUE(db_.DoesTableExist("data"));
+
+  // The table should not have been cleared, since the database does not have a
+  // metadata table.
+  MetaTable::RazeIfIncompatible(&db_, 1,
+                                /*current_version=*/1);
+  EXPECT_TRUE(db_.DoesTableExist("data"));
+}
+
+TEST_F(SQLMetaTableTest, RazeIfIncompatibleRazesIncompatiblyOldTables) {
+  constexpr int kWrittenVersion = 1;
+  constexpr int kCompatibleVersion = 1;
 
   // Setup a current database.
   {
     MetaTable meta_table;
-    EXPECT_TRUE(meta_table.Init(&db_, kVersion, kVersion));
-    EXPECT_TRUE(db_.Execute("CREATE TABLE t(c)"));
-    EXPECT_TRUE(db_.DoesTableExist("t"));
+    EXPECT_TRUE(meta_table.Init(&db_, kWrittenVersion, kCompatibleVersion));
+    EXPECT_TRUE(db_.Execute("CREATE TABLE data(id INTEGER PRIMARY KEY)"));
+    ASSERT_TRUE(db_.DoesTableExist("data"));
   }
 
-  // Table should should still exist if the database version is new enough.
-  MetaTable::RazeIfDeprecated(&db_, kDeprecatedVersion);
-  EXPECT_TRUE(db_.DoesTableExist("t"));
+  // The table should have been cleared, since the least version compatible with
+  // the written database is greater than the current version.
+  MetaTable::RazeIfIncompatible(&db_, kWrittenVersion + 1,
+                                /*current_version=*/kWrittenVersion + 1);
+  EXPECT_FALSE(db_.DoesTableExist("data"));
+}
 
-  // TODO(shess): It may make sense to Raze() if meta isn't present or
-  // version isn't present.  See meta_table.h TODO on RazeIfDeprecated().
+TEST_F(SQLMetaTableTest, RazeIfIncompatibleRazesIncompatiblyNewTables) {
+  constexpr int kCompatibleVersion = 2;
+  constexpr int kWrittenVersion = 3;
 
-  // Table should still exist if the version is not available.
-  EXPECT_TRUE(db_.Execute("DELETE FROM meta WHERE key = 'version'"));
+  // Setup a current database.
   {
     MetaTable meta_table;
-    EXPECT_TRUE(meta_table.Init(&db_, kVersion, kVersion));
-    EXPECT_EQ(0, meta_table.GetVersionNumber());
+    EXPECT_TRUE(meta_table.Init(&db_, kWrittenVersion, kCompatibleVersion));
+    EXPECT_TRUE(db_.Execute("CREATE TABLE data(id INTEGER PRIMARY KEY)"));
+    ASSERT_TRUE(db_.DoesTableExist("data"));
   }
-  MetaTable::RazeIfDeprecated(&db_, kDeprecatedVersion);
-  EXPECT_TRUE(db_.DoesTableExist("t"));
 
-  // Table should still exist if meta table is missing.
-  EXPECT_TRUE(db_.Execute("DROP TABLE meta"));
-  MetaTable::RazeIfDeprecated(&db_, kDeprecatedVersion);
-  EXPECT_TRUE(db_.DoesTableExist("t"));
+  // The table should have been cleared, since the least version compatible with
+  // the written database is greater than the current version.
+  MetaTable::RazeIfIncompatible(&db_, MetaTable::kNoLowestSupportedVersion,
+                                /*current_version=*/kCompatibleVersion - 1);
+  EXPECT_FALSE(db_.DoesTableExist("data"));
+}
 
-  // Setup meta with deprecated version.
+TEST_F(SQLMetaTableTest, RazeIfIncompatibleDoesntRazeWhenItShouldnt) {
+  constexpr int kVersion = 2;
+
   {
     MetaTable meta_table;
-    EXPECT_TRUE(meta_table.Init(&db_, kDeprecatedVersion, kDeprecatedVersion));
+    EXPECT_TRUE(
+        meta_table.Init(&db_, kVersion, /*compatible_version=*/kVersion - 1));
+    EXPECT_TRUE(db_.Execute("CREATE TABLE data(id INTEGER PRIMARY KEY)"));
+    EXPECT_TRUE(db_.DoesTableExist("data"));
   }
 
-  // Deprecation check should remove the table.
-  EXPECT_TRUE(db_.DoesTableExist("t"));
-  MetaTable::RazeIfDeprecated(&db_, kDeprecatedVersion);
-  EXPECT_FALSE(MetaTable::DoesTableExist(&db_));
-  EXPECT_FALSE(db_.DoesTableExist("t"));
+  MetaTable::RazeIfIncompatible(&db_, kVersion,
+                                /*current_version=*/kVersion);
+  EXPECT_TRUE(db_.DoesTableExist("data"))
+      << "Table should still exist if the database version is exactly right.";
+
+  MetaTable::RazeIfIncompatible(&db_, kVersion - 1,
+                                /*current_version=*/kVersion);
+  EXPECT_TRUE(db_.DoesTableExist("data"))
+      << "... or if the lower bound is less than the actual version";
+
+  MetaTable::RazeIfIncompatible(&db_, MetaTable::kNoLowestSupportedVersion,
+                                /*current_version=*/kVersion);
+  EXPECT_TRUE(db_.DoesTableExist("data"))
+      << "... or if the lower bound is not set";
+
+  MetaTable::RazeIfIncompatible(&db_, MetaTable::kNoLowestSupportedVersion,
+                                /*current_version=*/kVersion - 1);
+  EXPECT_TRUE(db_.DoesTableExist("data"))
+      << "... even if the current version exactly matches the written "
+         "database's least compatible version.";
 }
 
 TEST_F(SQLMetaTableTest, VersionNumber) {
   // Compatibility versions one less than the main versions to make
   // sure the values aren't being crossed with each other.
-  const int kVersionFirst = 2;
-  const int kCompatVersionFirst = kVersionFirst - 1;
-  const int kVersionSecond = 4;
-  const int kCompatVersionSecond = kVersionSecond - 1;
-  const int kVersionThird = 6;
-  const int kCompatVersionThird = kVersionThird - 1;
+  constexpr int kVersionFirst = 2;
+  constexpr int kCompatVersionFirst = kVersionFirst - 1;
+  constexpr int kVersionSecond = 4;
+  constexpr int kCompatVersionSecond = kVersionSecond - 1;
+  constexpr int kVersionThird = 6;
+  constexpr int kCompatVersionThird = kVersionThird - 1;
 
   // First Init() sets the version info as expected.
   {
@@ -178,8 +213,8 @@
 
 TEST_F(SQLMetaTableTest, IntValue) {
   static const char kKey[] = "Int Key";
-  const int kFirstValue = 17;
-  const int kSecondValue = 23;
+  constexpr int kFirstValue = 17;
+  constexpr int kSecondValue = 23;
 
   // Initially, the value isn't there until set.
   {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index ea0a554..479fd38 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -83276,6 +83276,2105 @@
       }
     ]
   },
+  "linux-exp-code-coverage": {
+    "gtest_tests": [
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "absl_hardening_tests",
+        "test_id_prefix": "ninja://third_party/abseil-cpp:absl_hardening_tests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "accessibility_unittests",
+        "test_id_prefix": "ninja://ui/accessibility:accessibility_unittests/"
+      },
+      {
+        "args": [
+          "angle_unittests"
+        ],
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "angle_unittests",
+        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_unittests/",
+        "use_isolated_scripts_api": true
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "app_shell_unittests",
+        "test_id_prefix": "ninja://extensions/shell:app_shell_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "aura_unittests",
+        "test_id_prefix": "ninja://ui/aura:aura_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "base_unittests",
+        "test_id_prefix": "ninja://base:base_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "base_util_unittests",
+        "test_id_prefix": "ninja://base/util:base_util_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "blink_common_unittests",
+        "test_id_prefix": "ninja://third_party/blink/common:blink_common_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "blink_fuzzer_unittests",
+        "test_id_prefix": "ninja://third_party/blink/renderer/platform:blink_fuzzer_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "blink_heap_unittests",
+        "test_id_prefix": "ninja://third_party/blink/renderer/platform/heap:blink_heap_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "blink_platform_unittests",
+        "test_id_prefix": "ninja://third_party/blink/renderer/platform:blink_platform_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "webkit_unit_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "blink_unittests",
+        "test_id_prefix": "ninja://third_party/blink/renderer/controller:blink_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "boringssl_crypto_tests",
+        "test_id_prefix": "ninja://third_party/boringssl:boringssl_crypto_tests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "boringssl_ssl_tests",
+        "test_id_prefix": "ninja://third_party/boringssl:boringssl_ssl_tests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 10
+        },
+        "test": "browser_tests",
+        "test_id_prefix": "ninja://chrome/test:browser_tests/"
+      },
+      {
+        "args": [
+          "--gtest_filter=-*UsingRealWebcam*"
+        ],
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "capture_unittests",
+        "test_id_prefix": "ninja://media/capture:capture_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "cast_unittests",
+        "test_id_prefix": "ninja://media/cast:cast_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "cc_unittests",
+        "test_id_prefix": "ninja://cc:cc_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "chrome_app_unittests",
+        "test_id_prefix": "ninja://chrome/test:chrome_app_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "chromedriver_unittests",
+        "test_id_prefix": "ninja://chrome/test/chromedriver:chromedriver_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "color_unittests",
+        "test_id_prefix": "ninja://ui/color:color_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "components_browsertests",
+        "test_id_prefix": "ninja://components:components_browsertests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "components_unittests",
+        "test_id_prefix": "ninja://components:components_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "compositor_unittests",
+        "test_id_prefix": "ninja://ui/compositor:compositor_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 6
+        },
+        "test": "content_browsertests",
+        "test_id_prefix": "ninja://content/test:content_browsertests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "content_unittests",
+        "test_id_prefix": "ninja://content/test:content_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "crashpad_tests",
+        "test_id_prefix": "ninja://third_party/crashpad/crashpad:crashpad_tests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "cronet_tests",
+        "test_id_prefix": "ninja://components/cronet:cronet_tests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "cronet_unittests",
+        "test_id_prefix": "ninja://components/cronet:cronet_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "crypto_unittests",
+        "test_id_prefix": "ninja://crypto:crypto_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "dbus_unittests",
+        "test_id_prefix": "ninja://dbus:dbus_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "device_unittests",
+        "test_id_prefix": "ninja://device:device_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "display_unittests",
+        "test_id_prefix": "ninja://ui/display:display_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "events_unittests",
+        "test_id_prefix": "ninja://ui/events:events_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "extensions_browsertests",
+        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "extensions_unittests",
+        "test_id_prefix": "ninja://extensions:extensions_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "filesystem_service_unittests",
+        "test_id_prefix": "ninja://components/services/filesystem:filesystem_service_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "gcm_unit_tests",
+        "test_id_prefix": "ninja://google_apis/gcm:gcm_unit_tests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "gfx_unittests",
+        "test_id_prefix": "ninja://ui/gfx:gfx_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "gin_unittests",
+        "test_id_prefix": "ninja://gin:gin_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "google_apis_unittests",
+        "test_id_prefix": "ninja://google_apis:google_apis_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "gpu_unittests",
+        "test_id_prefix": "ninja://gpu:gpu_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "gtk_unittests",
+        "test_id_prefix": "ninja://ui/gtk:gtk_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "gwp_asan_unittests",
+        "test_id_prefix": "ninja://components/gwp_asan:gwp_asan_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "headless_browsertests",
+        "test_id_prefix": "ninja://headless:headless_browsertests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "headless_unittests",
+        "test_id_prefix": "ninja://headless:headless_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 3
+        },
+        "test": "interactive_ui_tests",
+        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "ipc_tests",
+        "test_id_prefix": "ninja://ipc:ipc_tests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "jingle_unittests",
+        "test_id_prefix": "ninja://jingle:jingle_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "latency_unittests",
+        "test_id_prefix": "ninja://ui/latency:latency_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "libjingle_xmpp_unittests",
+        "test_id_prefix": "ninja://third_party/libjingle_xmpp:libjingle_xmpp_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "liburlpattern_unittests",
+        "test_id_prefix": "ninja://third_party/liburlpattern:liburlpattern_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "media_unittests",
+        "test_id_prefix": "ninja://media:media_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "message_center_unittests",
+        "test_id_prefix": "ninja://ui/message_center:message_center_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "midi_unittests",
+        "test_id_prefix": "ninja://media/midi:midi_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "mojo_core_unittests",
+        "test_id_prefix": "ninja://mojo/core:mojo_core_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "mojo_unittests",
+        "test_id_prefix": "ninja://mojo:mojo_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "nacl_helper_nonsfi_unittests",
+        "test_id_prefix": "ninja://components/nacl/loader:nacl_helper_nonsfi_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "nacl_loader_unittests",
+        "test_id_prefix": "ninja://components/nacl/loader:nacl_loader_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "native_theme_unittests",
+        "test_id_prefix": "ninja://ui/native_theme:native_theme_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "net_unittests",
+        "test_id_prefix": "ninja://net:net_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "openscreen_unittests",
+        "test_id_prefix": "ninja://chrome/browser/media/router:openscreen_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "pdf_unittests",
+        "test_id_prefix": "ninja://pdf:pdf_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "perfetto_unittests",
+        "test_id_prefix": "ninja://third_party/perfetto:perfetto_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "ppapi_unittests",
+        "test_id_prefix": "ninja://ppapi:ppapi_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "printing_unittests",
+        "test_id_prefix": "ninja://printing:printing_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "remoting_unittests",
+        "test_id_prefix": "ninja://remoting:remoting_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "sandbox_linux_unittests",
+        "test_id_prefix": "ninja://sandbox/linux:sandbox_linux_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "service_manager_unittests",
+        "test_id_prefix": "ninja://services/service_manager/tests:service_manager_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "services_unittests",
+        "test_id_prefix": "ninja://services:services_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "shell_dialogs_unittests",
+        "test_id_prefix": "ninja://ui/shell_dialogs:shell_dialogs_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "skia_unittests",
+        "test_id_prefix": "ninja://skia:skia_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "snapshot_unittests",
+        "test_id_prefix": "ninja://ui/snapshot:snapshot_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "sql_unittests",
+        "test_id_prefix": "ninja://sql:sql_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "storage_unittests",
+        "test_id_prefix": "ninja://storage:storage_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "sync_integration_tests",
+        "test_id_prefix": "ninja://chrome/test:sync_integration_tests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "traffic_annotation_auditor_unittests",
+        "test_id_prefix": "ninja://tools/traffic_annotation/auditor:traffic_annotation_auditor_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "ui_base_unittests",
+        "test_id_prefix": "ninja://ui/base:ui_base_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "ui_touch_selection_unittests",
+        "test_id_prefix": "ninja://ui/touch_selection:ui_touch_selection_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "unit_tests",
+        "test_id_prefix": "ninja://chrome/test:unit_tests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "url_unittests",
+        "test_id_prefix": "ninja://url:url_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "views_unittests",
+        "test_id_prefix": "ninja://ui/views:views_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "viz_unittests",
+        "test_id_prefix": "ninja://components/viz:viz_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "vr_common_unittests",
+        "test_id_prefix": "ninja://chrome/browser/vr:vr_common_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "vr_pixeltests",
+        "test_id_prefix": "ninja://chrome/browser/vr:vr_pixeltests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "weblayer_browsertests",
+        "test_id_prefix": "ninja://weblayer/test:weblayer_browsertests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "weblayer_unittests",
+        "test_id_prefix": "ninja://weblayer/test:weblayer_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "wm_unittests",
+        "test_id_prefix": "ninja://ui/wm:wm_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "wtf_unittests",
+        "test_id_prefix": "ninja://third_party/blink/renderer/platform/wtf:wtf_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "x11_unittests",
+        "test_id_prefix": "ninja://ui/platform_window/x11:x11_unittests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "xr_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "xr_browser_tests",
+        "test_id_prefix": "ninja://chrome/test:xr_browser_tests/"
+      },
+      {
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "zlib_unittests",
+        "test_id_prefix": "ninja://third_party/zlib:zlib_unittests/"
+      }
+    ],
+    "isolated_scripts": [
+      {
+        "isolate_name": "blink_python_tests",
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "blink_python_tests",
+        "resultdb": {
+          "enable": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test_id_prefix": "ninja://:blink_python_tests/"
+      },
+      {
+        "args": [
+          "--num-retries=3",
+          "--additional-env-var=LLVM_PROFILE_FILE=${ISOLATED_OUTDIR}/profraw/default-%2m.profraw"
+        ],
+        "isolate_name": "blink_web_tests",
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [
+            "--verbose"
+          ],
+          "script": "//third_party/blink/tools/merge_web_test_results.py"
+        },
+        "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
+        "results_handler": "layout tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 20
+        },
+        "test_id_prefix": "ninja://:blink_web_tests/"
+      },
+      {
+        "args": [
+          "--test-type=integration"
+        ],
+        "isolate_name": "chromedriver_py_tests",
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "chromedriver_py_tests",
+        "resultdb": {
+          "enable": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test_id_prefix": "ninja://chrome/test/chromedriver:chromedriver_py_tests/"
+      },
+      {
+        "isolate_name": "chromedriver_replay_unittests",
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "chromedriver_replay_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test_id_prefix": "ninja://chrome/test/chromedriver:chromedriver_replay_unittests/"
+      },
+      {
+        "isolate_name": "content_shell_crash_test",
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "content_shell_crash_test",
+        "resultdb": {
+          "enable": true,
+          "result_format": "single"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test_id_prefix": "ninja://content/shell:content_shell_crash_test/"
+      },
+      {
+        "isolate_name": "flatbuffers_unittests",
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "flatbuffers_unittests",
+        "resultdb": {
+          "enable": true,
+          "result_format": "single"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test_id_prefix": "ninja://third_party/flatbuffers:flatbuffers_unittests/"
+      },
+      {
+        "isolate_name": "grit_python_unittests",
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "grit_python_unittests",
+        "resultdb": {
+          "enable": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test_id_prefix": "ninja://tools/grit:grit_python_unittests/"
+      },
+      {
+        "isolate_name": "mojo_python_unittests",
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "mojo_python_unittests",
+        "resultdb": {
+          "enable": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test_id_prefix": "ninja://mojo/public/tools:mojo_python_unittests/"
+      },
+      {
+        "args": [
+          "--additional-driver-flag",
+          "--disable-site-isolation-trials",
+          "--additional-expectations=../../third_party/blink/web_tests/FlagExpectations/disable-site-isolation-trials",
+          "--num-retries=3"
+        ],
+        "isolate_name": "blink_web_tests",
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [
+            "--verbose"
+          ],
+          "script": "//third_party/blink/tools/merge_web_test_results.py"
+        },
+        "name": "not_site_per_process_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
+        "results_handler": "layout tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 10
+        },
+        "test_id_prefix": "ninja://:blink_web_tests/"
+      },
+      {
+        "isolate_name": "telemetry_gpu_unittests",
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "telemetry_gpu_unittests",
+        "resultdb": {
+          "enable": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "idempotent": false,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_unittests/"
+      },
+      {
+        "args": [
+          "--extra-browser-args=--enable-crashpad"
+        ],
+        "isolate_name": "telemetry_perf_unittests",
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "telemetry_perf_unittests",
+        "resultdb": {
+          "enable": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "idempotent": false,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 12
+        },
+        "test_id_prefix": "ninja://chrome/test:telemetry_perf_unittests/"
+      },
+      {
+        "args": [
+          "--jobs=1",
+          "--extra-browser-args=--disable-gpu"
+        ],
+        "isolate_name": "telemetry_unittests",
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "telemetry_unittests",
+        "resultdb": {
+          "enable": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "idempotent": false,
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 8
+        },
+        "test_id_prefix": "ninja://chrome/test:telemetry_unittests/"
+      },
+      {
+        "args": [
+          "--gtest-benchmark-name=views_perftests"
+        ],
+        "isolate_name": "views_perftests",
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [
+            "--smoke-test-mode"
+          ],
+          "script": "//tools/perf/process_perf_results.py"
+        },
+        "name": "views_perftests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test_id_prefix": "ninja://ui/views:views_perftests/"
+      },
+      {
+        "args": [
+          "--num-retries=3",
+          "--additional-driver-flag=--enable-gpu-rasterization",
+          "--additional-driver-flag=--enable-features=UseSkiaRenderer,Vulkan",
+          "--additional-driver-flag=--enable-oop-rasterization",
+          "--additional-driver-flag=--use-vulkan=swiftshader",
+          "--additional-driver-flag=--disable-vulkan-fallback-to-gl-for-testing",
+          "--fuzzy-diff",
+          "--skipped=always",
+          "--test-list=../../testing/buildbot/filters/gpu.skiarenderer_vulkan_blink_web_tests.filter",
+          "--additional-expectations=../../third_party/blink/web_tests/FlagExpectations/enable-features=UseSkiaRenderer",
+          "--additional-expectations=../../third_party/blink/web_tests/FlagExpectations/enable-gpu-rasterization",
+          "--additional-expectations=../../third_party/blink/web_tests/FlagExpectations/use-vulkan=swiftshader"
+        ],
+        "isolate_name": "blink_web_tests",
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [
+            "--verbose"
+          ],
+          "script": "//third_party/blink/tools/merge_web_test_results.py"
+        },
+        "name": "vulkan_swiftshader_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
+        "results_handler": "layout tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test_id_prefix": "ninja://:blink_web_tests/"
+      },
+      {
+        "isolate_name": "webdriver_wpt_tests",
+        "isolate_profile_data": true,
+        "merge": {
+          "args": [
+            "--verbose"
+          ],
+          "script": "//third_party/blink/tools/merge_web_test_results.py"
+        },
+        "name": "webdriver_tests_suite",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-18.04"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 4
+        },
+        "test_id_prefix": "ninja://:webdriver_wpt_tests/"
+      }
+    ],
+    "scripts": [
+      {
+        "isolate_profile_data": true,
+        "name": "check_network_annotations",
+        "script": "check_network_annotations.py",
+        "swarming": {}
+      },
+      {
+        "isolate_profile_data": true,
+        "name": "check_static_initializers",
+        "script": "check_static_initializers.py",
+        "swarming": {}
+      },
+      {
+        "isolate_profile_data": true,
+        "name": "checkdeps",
+        "script": "checkdeps.py",
+        "swarming": {}
+      },
+      {
+        "isolate_profile_data": true,
+        "name": "checkperms",
+        "script": "checkperms.py",
+        "swarming": {}
+      },
+      {
+        "isolate_profile_data": true,
+        "name": "headless_python_unittests",
+        "script": "headless_python_unittests.py",
+        "swarming": {}
+      },
+      {
+        "isolate_profile_data": true,
+        "name": "metrics_python_tests",
+        "script": "metrics_python_tests.py",
+        "swarming": {}
+      },
+      {
+        "isolate_profile_data": true,
+        "name": "webkit_lint",
+        "script": "blink_lint_expectations.py",
+        "swarming": {}
+      }
+    ]
+  },
   "linux-fieldtrial-rel": {
     "gtest_tests": [
       {
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 908c240..3c8f996c 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -479,6 +479,14 @@
           'shards': 20,
         },
       },
+      'linux-exp-code-coverage': {
+        'args': [
+          '--additional-env-var=LLVM_PROFILE_FILE=${ISOLATED_OUTDIR}/profraw/default-%2m.profraw',
+        ],
+        'swarming': {
+          'shards': 20,
+        },
+      },
       'linux-layout-tests-edit-ng': {
         'args': [
           '--additional-driver-flag=--enable-blink-features=EditingNG',
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index c6511f56..f332f26 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -3183,6 +3183,17 @@
           'gtest_tests': 'linux_example_builder_gtests',
         },
       },
+      'linux-exp-code-coverage': {
+        'mixins': [
+          'isolate_profile_data',
+          'linux-bionic',
+        ],
+        'test_suites': {
+          'gtest_tests': 'chromium_linux_gtests',
+          'isolated_scripts': 'chromium_linux_rel_isolated_scripts',
+          'scripts': 'chromium_linux_scripts',
+        },
+      },
       'linux-fieldtrial-rel': {
         'mixins': [
           'linux-bionic',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index bf7bc0d..7fd1b1b 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -6647,7 +6647,7 @@
                     "name": "Enabled",
                     "params": {
                         "enable_quic": "true",
-                        "quic_version": "h3-29,h3-Q050",
+                        "quic_version": "h3,h3-29,h3-Q050",
                         "retransmittable_on_wire_timeout_milliseconds": "200"
                     },
                     "enable_features": [
diff --git a/third_party/blink/public/mojom/link_to_text/link_to_text.mojom b/third_party/blink/public/mojom/link_to_text/link_to_text.mojom
index 048ad17..ffecbad 100644
--- a/third_party/blink/public/mojom/link_to_text/link_to_text.mojom
+++ b/third_party/blink/public/mojom/link_to_text/link_to_text.mojom
@@ -8,8 +8,10 @@
 import "ui/gfx/geometry/mojom/geometry.mojom";
 
 // TextFragmentReceiver is used for requesting renderer to perform text fragment
-// operations on the main frame, mainly generating and removing fragments.
-// Implemented in renderer.
+// operations on the frame that interacts with the link-to-text/shared-highlighting
+// feature, mainly generating and removing fragments. A text fragment receiver is
+// associated with exactly one frame but a frame will only create its receiver
+// lazily when needed.
 interface TextFragmentReceiver {
   // Cancel text fragment generation if in progress.
   Cancel();
@@ -19,7 +21,7 @@
   // https://github.com/WICG/scroll-to-text-fragment.
   RequestSelector() => (string selector);
 
-  // Dismiss all text fragments from the current main frame at the time the
+  // Dismiss all text fragments from this frame at the time the
   // context menu was invoked.
   RemoveFragments();
 
diff --git a/third_party/blink/public/mojom/webid/federated_auth_request.mojom b/third_party/blink/public/mojom/webid/federated_auth_request.mojom
index ffef84f..2753124 100644
--- a/third_party/blink/public/mojom/webid/federated_auth_request.mojom
+++ b/third_party/blink/public/mojom/webid/federated_auth_request.mojom
@@ -40,10 +40,18 @@
 // This interface is called from a renderer process and implemented in the
 // browser process.
 interface FederatedAuthRequest {
-  // Requests an IdToken to be generated, given an IDP URL and an OAuth request.
+  // Requests an IdToken to be generated, given an IDP URL, some request
+  // parameters, and a mode that specifies the UI flow.
+  // |client_id| and |nonce| can be empty strings to omit the fields in the
+  // request sent to the provider.
   // Returns the raw content of the IdToken.
-  RequestIdToken(url.mojom.Url provider, string id_request, RequestMode mode) => (RequestIdTokenStatus status, string? id_token);
+  RequestIdToken(url.mojom.Url provider,
+                 string client_id,
+                 string nonce,
+                 RequestMode mode) =>
+      (RequestIdTokenStatus status, string? id_token);
 
-  // Contact the list of Relying Party logout endpoints to attempt to initiate user logout.
+  // Contact the list of Relying Party logout endpoints to attempt to initiate
+  // user logout.
   Logout(array<string> rp_logout_endpoints) => (LogoutStatus status);
 };
diff --git a/third_party/blink/renderer/bindings/generated_in_modules.gni b/third_party/blink/renderer/bindings/generated_in_modules.gni
index 3b34900..0d57134 100644
--- a/third_party/blink/renderer/bindings/generated_in_modules.gni
+++ b/third_party/blink/renderer/bindings/generated_in_modules.gni
@@ -391,6 +391,8 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_extent_3d_dict.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_external_texture_binding_layout.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_external_texture_binding_layout.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_external_texture_descriptor.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_external_texture_descriptor.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_fragment_state.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_fragment_state.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_image_copy_buffer.cc",
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index 15cf975..d7c3833f 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -1391,7 +1391,6 @@
     "layout/ng/ng_column_layout_algorithm_test.cc",
     "layout/ng/ng_constraint_space_builder_test.cc",
     "layout/ng/ng_fieldset_layout_algorithm_test.cc",
-    "layout/ng/ng_fragment_child_iterator_test.cc",
     "layout/ng/ng_fragmentation_test.cc",
     "layout/ng/ng_ink_overflow_test.cc",
     "layout/ng/ng_inline_layout_test.cc",
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index 1305ec45..2b96901 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -473,11 +473,8 @@
           GetTaskRunner(blink::TaskType::kInternalDefault)));
   GetInterfaceRegistry()->AddAssociatedInterface(WTF::BindRepeating(
       &LocalFrame::BindToReceiver, WrapWeakPersistent(this)));
-
-  if (IsMainFrame()) {
-    GetInterfaceRegistry()->AddInterface(WTF::BindRepeating(
-        &LocalFrame::BindTextFragmentReceiver, WrapWeakPersistent(this)));
-  }
+  GetInterfaceRegistry()->AddInterface(WTF::BindRepeating(
+      &LocalFrame::BindTextFragmentReceiver, WrapWeakPersistent(this)));
   DCHECK(!mojo_receiver_);
   mojo_receiver_ = MakeGarbageCollected<LocalFrameMojoReceiver>(*this);
 
@@ -3880,9 +3877,13 @@
 
 void LocalFrame::BindTextFragmentReceiver(
     mojo::PendingReceiver<mojom::blink::TextFragmentReceiver> receiver) {
-  if (IsDetached() || !text_fragment_handler_)
+  if (IsDetached())
     return;
 
+  if (!text_fragment_handler_) {
+    text_fragment_handler_ = MakeGarbageCollected<TextFragmentHandler>(this);
+  }
+
   text_fragment_handler_->BindTextFragmentReceiver(std::move(receiver));
 }
 
diff --git a/third_party/blink/renderer/core/frame/local_frame.h b/third_party/blink/renderer/core/frame/local_frame.h
index 9f6c04d..1e7189a 100644
--- a/third_party/blink/renderer/core/frame/local_frame.h
+++ b/third_party/blink/renderer/core/frame/local_frame.h
@@ -798,6 +798,9 @@
   // https://github.com/jeremyroman/alternate-loading-modes/blob/main/browsing-context.md#session-history
   bool ShouldMaintainTrivialSessionHistory() const;
 
+  void BindTextFragmentReceiver(
+      mojo::PendingReceiver<mojom::blink::TextFragmentReceiver> receiver);
+
  private:
   friend class FrameNavigationDisabler;
   FRIEND_TEST_ALL_PREFIXES(LocalFrameTest, CharacterIndexAtPointWithPinchZoom);
@@ -905,8 +908,6 @@
   static void BindToReceiver(
       blink::LocalFrame* frame,
       mojo::PendingAssociatedReceiver<mojom::blink::LocalFrame> receiver);
-  void BindTextFragmentReceiver(
-      mojo::PendingReceiver<mojom::blink::TextFragmentReceiver> receiver);
 
   // Whether a navigation should replace the current history entry or not.
   // Note this isn't exhaustive; there are other cases where a navigation does a
diff --git a/third_party/blink/renderer/core/layout/build.gni b/third_party/blink/renderer/core/layout/build.gni
index cf2afc0..a827731 100644
--- a/third_party/blink/renderer/core/layout/build.gni
+++ b/third_party/blink/renderer/core/layout/build.gni
@@ -498,8 +498,6 @@
   "ng/ng_floats_utils.h",
   "ng/ng_fragment.h",
   "ng/ng_fragment_builder.h",
-  "ng/ng_fragment_child_iterator.cc",
-  "ng/ng_fragment_child_iterator.h",
   "ng/ng_fragmentation_utils.cc",
   "ng/ng_fragmentation_utils.h",
   "ng/ng_ink_overflow.cc",
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc
index c668328..f6bfc7c1 100644
--- a/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -473,14 +473,6 @@
   NOT_DESTROYED();
   if (!PaintInvalidationStateIsDirty() || ChildPrePaintBlockedByDisplayLock())
     return;
-  // NG text objects are exempt, as pre-paint walking doesn't visit those with
-  // no paint effects (only white-space, for instance).
-  if ((IsText() && IsLayoutNGObject()) ||
-      // and culled inline boxes too.
-      (IsInLayoutNGInlineFormattingContext() && IsLayoutInline()) ||
-      // TablesNG columns are also not visited.
-      (IsLayoutTableCol() && IsLayoutNGObject()))
-    return;
   ShowLayoutTreeForThis();
   NOTREACHED();
 }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.cc b/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.cc
deleted file mode 100644
index bfa773e6..0000000
--- a/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.cc
+++ /dev/null
@@ -1,188 +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.
-
-#include "third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.h"
-
-#include "third_party/blink/renderer/core/layout/layout_box.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h"
-
-namespace blink {
-
-NGFragmentChildIterator::NGFragmentChildIterator(
-    const NGPhysicalBoxFragment& parent,
-    const NGBlockBreakToken* parent_break_token)
-    : parent_fragment_(&parent),
-      parent_break_token_(parent_break_token),
-      is_fragmentation_context_root_(parent.IsFragmentationContextRoot()) {
-  current_.link_.fragment = nullptr;
-  if (parent_break_token)
-    child_break_tokens_ = parent_break_token->ChildBreakTokens();
-  if (parent.HasItems()) {
-    current_.cursor_.emplace(parent);
-    current_.block_break_token_ = parent_break_token;
-    UpdateSelfFromCursor();
-  } else {
-    UpdateSelfFromFragment();
-  }
-}
-
-NGFragmentChildIterator::NGFragmentChildIterator(
-    const NGInlineCursor& parent,
-    const NGBlockBreakToken* parent_break_token,
-    base::span<const NGBreakToken* const> child_break_tokens)
-    : parent_break_token_(parent_break_token),
-      child_break_tokens_(child_break_tokens) {
-  current_.block_break_token_ = parent_break_token;
-  current_.link_.fragment = nullptr;
-  current_.cursor_ = parent.CursorForDescendants();
-  UpdateSelfFromCursor();
-}
-
-NGFragmentChildIterator NGFragmentChildIterator::Descend() const {
-  if (current_.cursor_) {
-    const NGFragmentItem* item = current_.cursor_->CurrentItem();
-    // Descend using the cursor if the current item doesn't establish a new
-    // formatting context.
-    if (!item->IsFormattingContextRoot()) {
-      return NGFragmentChildIterator(
-          *current_.cursor_,
-          current_.BlockBreakToken() ? parent_break_token_ : nullptr,
-          child_break_tokens_.subspan(child_break_token_idx_));
-    }
-  }
-  DCHECK(current_.BoxFragment());
-  return NGFragmentChildIterator(*current_.BoxFragment(),
-                                 current_.BlockBreakToken());
-}
-
-bool NGFragmentChildIterator::AdvanceChildFragment() {
-  DCHECK(parent_fragment_);
-  const auto children = parent_fragment_->Children();
-  const NGPhysicalBoxFragment* previous_fragment =
-      To<NGPhysicalBoxFragment>(current_.link_.fragment);
-  DCHECK(previous_fragment);
-  if (child_fragment_idx_ < children.size())
-    child_fragment_idx_++;
-  // There may be line box fragments among the children, and we're not
-  // interested in them (lines will already have been handled by the inline
-  // cursor).
-  SkipToBoxFragment();
-  if (child_fragment_idx_ >= children.size())
-    return false;
-  if (child_break_token_idx_ < child_break_tokens_.size())
-    child_break_token_idx_++;
-  UpdateSelfFromFragment(previous_fragment);
-  return true;
-}
-
-void NGFragmentChildIterator::UpdateSelfFromFragment(
-    const NGPhysicalBoxFragment* previous_fragment) {
-  DCHECK(parent_fragment_);
-  const auto children = parent_fragment_->Children();
-  if (child_fragment_idx_ >= children.size())
-    return;
-  current_.link_ = children[child_fragment_idx_];
-  DCHECK(current_.link_.fragment);
-  SkipToBlockBreakToken();
-  if (child_break_token_idx_ < child_break_tokens_.size()) {
-    current_.block_break_token_ =
-        To<NGBlockBreakToken>(child_break_tokens_[child_break_token_idx_]);
-    // TODO(mstensho): Clean up this. What we're trying to do here is to detect
-    // whether the incoming break token matches the current fragment or not.
-    // Figuring out if a fragment is generated from a given node is currently
-    // not possible without checking the LayoutObject associated.
-    const auto* layout_object = current_.link_.fragment->GetLayoutObject();
-    if (layout_object &&
-        layout_object !=
-            current_.block_break_token_->InputNode().GetLayoutBox()) {
-      DCHECK(current_.link_.fragment->IsColumnSpanAll() ||
-             // List markers are |IsMonolithic| that the flag doesn't matter.
-             current_.link_.fragment->IsListMarker());
-      current_.break_token_for_fragmentainer_only_ = true;
-    } else {
-      current_.break_token_for_fragmentainer_only_ = false;
-    }
-  } else if (is_fragmentation_context_root_ && previous_fragment) {
-    // The outgoing break token from one fragmentainer is the incoming break
-    // token to the next one. This is also true when there are column spanners
-    // (and other types of non-fragmentainers) between two columns
-    // (fragmentainers); the outgoing break token from the former column will be
-    // ignored by any intervening spanners (and other non-fragmentainers), and
-    // then fed into the first column that comes after them, as an incoming
-    // break token.
-    //
-    // A multicol container may contain other kinds of children than
-    // fragmentainers, such as a column spanner, a list item marker (if the
-    // multicol container is a list item), a rendered legend (if the parent
-    // fieldset also establishes a multicol container), or an out-of-flow
-    // positioned fragment whose containing block is the multicol container
-    // itself (in which case the OOF doesn't participate in the fragmentation
-    // context established by the multicol container). We'll leave
-    // |current_.block_break_token_| alone then, as it will be used as an
-    // incoming break token when we get to the next column.
-    if (previous_fragment->IsFragmentainerBox()) {
-      current_.block_break_token_ =
-          To<NGBlockBreakToken>(previous_fragment->BreakToken());
-      current_.break_token_for_fragmentainer_only_ = true;
-    }
-  } else {
-    current_.block_break_token_ = nullptr;
-  }
-}
-
-bool NGFragmentChildIterator::AdvanceWithCursor() {
-  DCHECK(current_.cursor_);
-  current_.cursor_->MoveToNextSkippingChildren();
-  UpdateSelfFromCursor();
-  if (current_.cursor_->CurrentItem())
-    return true;
-  // If there are more items, proceed and see if we have box fragment
-  // children. There may be out-of-flow positioned child fragments.
-  if (!parent_fragment_)
-    return false;
-  current_.cursor_.reset();
-  SkipToBoxFragment();
-  UpdateSelfFromFragment();
-  return !IsAtEnd();
-}
-
-void NGFragmentChildIterator::UpdateSelfFromCursor() {
-  DCHECK(current_.cursor_);
-  // For inline items we just use the incoming break token to the containing
-  // block.
-  current_.block_break_token_ = parent_break_token_;
-  const NGFragmentItem* item = current_.cursor_->CurrentItem();
-  if (!item) {
-    current_.link_.fragment = nullptr;
-    return;
-  }
-  current_.link_ = {item->BoxFragment(), item->OffsetInContainerFragment()};
-}
-
-void NGFragmentChildIterator::SkipToBoxFragment() {
-  for (const auto children = parent_fragment_->Children();
-       child_fragment_idx_ < children.size(); child_fragment_idx_++) {
-    if (children[child_fragment_idx_].fragment->IsBox())
-      break;
-  }
-}
-
-void NGFragmentChildIterator::SkipToBlockBreakToken() {
-  // There may be inline break tokens here. Ignore them.
-  while (child_break_token_idx_ < child_break_tokens_.size()) {
-    const auto* current_break_token = DynamicTo<NGBlockBreakToken>(
-        child_break_tokens_[child_break_token_idx_]);
-    // Skip over any out-of-flow positioned break tokens that are the result of
-    // a break before.
-    if (current_break_token &&
-        (!current_break_token->InputNode().IsOutOfFlowPositioned() ||
-         !current_break_token->IsBreakBefore()))
-      return;
-    child_break_token_idx_++;
-  }
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.h b/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.h
deleted file mode 100644
index 435a0af..0000000
--- a/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.h
+++ /dev/null
@@ -1,143 +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.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_FRAGMENT_CHILD_ITERATOR_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_FRAGMENT_CHILD_ITERATOR_H_
-
-#include "base/containers/span.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_link.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
-
-namespace blink {
-
-class LayoutObject;
-class NGBlockBreakToken;
-
-// Iterator for children of a box fragment. Supports fragment items and break
-// tokens. To advance to the next sibling, call |Advance()|. To descend into
-// children of the current child, call |Descend()|.
-//
-// Using this class requires LayoutNGFragmentItem to be enabled. While fragment
-// items are in a flat list representing the contents of an inline formatting
-// context, the iterator will to a certain extent restore the object hierarchy,
-// so that we can calculate the global offset of children of a relatively
-// positioned inline correctly.
-class CORE_EXPORT NGFragmentChildIterator {
-  STACK_ALLOCATED();
-
- public:
-  explicit NGFragmentChildIterator(
-      const NGPhysicalBoxFragment& parent,
-      const NGBlockBreakToken* parent_break_token = nullptr);
-
-  // Create a child iterator for the current child.
-  NGFragmentChildIterator Descend() const;
-
-  // Move to the next sibling. Return false if there's no next sibling. Once
-  // false is returned, this object is in an unusable state, with the exception
-  // that calling IsAtEnd() is allowed.
-  bool Advance() {
-    if (current_.cursor_)
-      return AdvanceWithCursor();
-    return AdvanceChildFragment();
-  }
-
-  bool IsAtEnd() {
-    if (current_.cursor_)
-      return !*current_.cursor_;
-    DCHECK(parent_fragment_);
-    const auto children = parent_fragment_->Children();
-    return child_fragment_idx_ >= children.size();
-  }
-
-  class Current {
-    STACK_ALLOCATED();
-
-    friend class NGFragmentChildIterator;
-
-   public:
-    // Return the current NGLink. Note that its offset is relative to the inline
-    // formatting context root, if the fragment / item participates in one.
-    const NGLink& Link() const { return link_; }
-
-    const NGPhysicalBoxFragment* BoxFragment() const {
-      return To<NGPhysicalBoxFragment>(link_.fragment);
-    }
-    const NGFragmentItem* FragmentItem() const {
-      if (!cursor_)
-        return nullptr;
-      return cursor_->CurrentItem();
-    }
-
-    // Get the incoming break token for the current child, i.e. the context at
-    // which layout of this child's node was resumed. Note that for text and
-    // non-atomic inlines this will be the incoming block break token to the
-    // inline formatting context root. For monolithic content, no break token
-    // will be returned (since such content isn't considered to participate in a
-    // fragmentation context).
-    const NGBlockBreakToken* BlockBreakToken() const {
-      if (LIKELY(!block_break_token_))
-        return nullptr;
-      if (link_.fragment) {
-        // Don't pass the break token into monolithic content.
-        if (link_.fragment->IsMonolithic())
-          return nullptr;
-        // If the break token we've found is from a fragmentainer, it's only to
-        // be used by a subsequent fragmentainer. Other fragment types (such as
-        // column spanners) need to ignore it.
-        if (break_token_for_fragmentainer_only_ &&
-            !link_.fragment->IsFragmentainerBox())
-          return nullptr;
-      }
-      return block_break_token_;
-    }
-
-    const LayoutObject* GetLayoutObject() const {
-      if (const NGFragmentItem* item = FragmentItem())
-        return item->GetLayoutObject();
-      return BoxFragment()->GetLayoutObject();
-    }
-
-   private:
-    NGLink link_;
-    absl::optional<NGInlineCursor> cursor_;
-    const NGBlockBreakToken* block_break_token_ = nullptr;
-    bool break_token_for_fragmentainer_only_ = false;
-  };
-
-  const Current& GetCurrent() const { return current_; }
-  const Current& operator*() const { return current_; }
-  const Current* operator->() const { return &current_; }
-
- private:
-  NGFragmentChildIterator(
-      const NGInlineCursor& parent,
-      const NGBlockBreakToken* parent_break_token,
-      base::span<const NGBreakToken* const> child_break_tokens);
-
-  bool AdvanceChildFragment();
-  void UpdateSelfFromFragment(
-      const NGPhysicalBoxFragment* previous_fragment = nullptr);
-
-  bool AdvanceWithCursor();
-  void UpdateSelfFromCursor();
-  void SkipToBoxFragment();
-  void SkipToBlockBreakToken();
-
-  const NGPhysicalBoxFragment* parent_fragment_ = nullptr;
-  const NGBlockBreakToken* parent_break_token_ = nullptr;
-  Current current_;
-  base::span<const NGBreakToken* const> child_break_tokens_;
-  wtf_size_t child_fragment_idx_ = 0;
-  wtf_size_t child_break_token_idx_ = 0;
-  bool is_fragmentation_context_root_ = false;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_FRAGMENT_CHILD_ITERATOR_H_
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator_test.cc b/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator_test.cc
deleted file mode 100644
index 68de9194..0000000
--- a/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator_test.cc
+++ /dev/null
@@ -1,806 +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.
-
-#include "third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
-#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
-
-namespace blink {
-namespace {
-
-class NGFragmentChildIteratorTest
-    : public NGBaseLayoutAlgorithmTest,
-      private ScopedLayoutNGBlockFragmentationForTest {
- protected:
-  NGFragmentChildIteratorTest()
-      : ScopedLayoutNGBlockFragmentationForTest(true) {}
-
-  scoped_refptr<const NGPhysicalBoxFragment> RunBlockLayoutAlgorithm(
-      Element* element) {
-    NGBlockNode container(element->GetLayoutBox());
-    NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
-        {WritingMode::kHorizontalTb, TextDirection::kLtr},
-        LogicalSize(LayoutUnit(1000), kIndefiniteSize));
-    return NGBaseLayoutAlgorithmTest::RunBlockLayoutAlgorithm(container, space);
-  }
-};
-
-TEST_F(NGFragmentChildIteratorTest, Basic) {
-  SetBodyInnerHTML(R"HTML(
-    <div id="container">
-      <div id="child1">
-        <div id="grandchild"></div>
-      </div>
-      <div id="child2"></div>
-    </div>
-  )HTML");
-
-  const LayoutObject* child1 = GetLayoutObjectByElementId("child1");
-  const LayoutObject* child2 = GetLayoutObjectByElementId("child2");
-  const LayoutObject* grandchild = GetLayoutObjectByElementId("grandchild");
-
-  scoped_refptr<const NGPhysicalBoxFragment> container =
-      RunBlockLayoutAlgorithm(GetElementById("container"));
-  NGFragmentChildIterator iterator1(*container.get());
-  EXPECT_FALSE(iterator1.IsAtEnd());
-
-  const NGPhysicalBoxFragment* fragment = iterator1->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->GetLayoutObject(), child1);
-  EXPECT_FALSE(iterator1.IsAtEnd());
-
-  NGFragmentChildIterator iterator2 = iterator1.Descend();
-  EXPECT_FALSE(iterator2.IsAtEnd());
-  fragment = iterator2->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->GetLayoutObject(), grandchild);
-  EXPECT_FALSE(iterator2.IsAtEnd());
-  EXPECT_FALSE(iterator2.Advance());
-  EXPECT_TRUE(iterator2.IsAtEnd());
-
-  EXPECT_TRUE(iterator1.Advance());
-  fragment = iterator1->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->GetLayoutObject(), child2);
-  EXPECT_FALSE(iterator1.IsAtEnd());
-
-  // #child2 has no children.
-  EXPECT_TRUE(iterator1.Descend().IsAtEnd());
-
-  // No more children left.
-  EXPECT_FALSE(iterator1.Advance());
-  EXPECT_TRUE(iterator1.IsAtEnd());
-}
-
-TEST_F(NGFragmentChildIteratorTest, BasicInline) {
-  SetBodyInnerHTML(R"HTML(
-    <div id="container">
-      xxx
-      <span id="span1" style="border:solid;">
-        <div id="float1" style="float:left;"></div>
-        xxx
-      </span>
-      xxx
-    </div>
-  )HTML");
-
-  const LayoutObject* span1 = GetLayoutObjectByElementId("span1");
-  const LayoutObject* float1 = GetLayoutObjectByElementId("float1");
-
-  scoped_refptr<const NGPhysicalBoxFragment> container =
-      RunBlockLayoutAlgorithm(GetElementById("container"));
-  NGFragmentChildIterator iterator1(*container.get());
-
-  EXPECT_FALSE(iterator1->BoxFragment());
-  const NGFragmentItem* fragment_item = iterator1->FragmentItem();
-  ASSERT_TRUE(fragment_item);
-  EXPECT_EQ(fragment_item->Type(), NGFragmentItem::kLine);
-
-  // Descend into the line box.
-  NGFragmentChildIterator iterator2 = iterator1.Descend();
-  fragment_item = iterator2->FragmentItem();
-  ASSERT_TRUE(fragment_item);
-  EXPECT_TRUE(fragment_item->IsText());
-
-  EXPECT_TRUE(iterator2.Advance());
-  const NGPhysicalBoxFragment* fragment = iterator2->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->GetLayoutObject(), span1);
-
-  // Descend into children of #span1.
-  NGFragmentChildIterator iterator3 = iterator2.Descend();
-  fragment = iterator3->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->GetLayoutObject(), float1);
-
-  EXPECT_TRUE(iterator3.Advance());
-  fragment_item = iterator3->FragmentItem();
-  ASSERT_TRUE(fragment_item);
-  EXPECT_TRUE(fragment_item->IsText());
-  EXPECT_FALSE(iterator3.Advance());
-
-  // Continue with siblings of #span1.
-  EXPECT_TRUE(iterator2.Advance());
-  fragment_item = iterator2->FragmentItem();
-  ASSERT_TRUE(fragment_item);
-  EXPECT_TRUE(fragment_item->IsText());
-
-  EXPECT_FALSE(iterator2.Advance());
-  EXPECT_FALSE(iterator1.Advance());
-}
-
-TEST_F(NGFragmentChildIteratorTest, InlineBlock) {
-  SetBodyInnerHTML(R"HTML(
-    <div id="container">
-      xxx
-      <span id="inlineblock">
-        <div id="float1" style="float:left;"></div>
-      </span>
-      xxx
-    </div>
-  )HTML");
-
-  const LayoutObject* inlineblock = GetLayoutObjectByElementId("inlineblock");
-  const LayoutObject* float1 = GetLayoutObjectByElementId("float1");
-
-  scoped_refptr<const NGPhysicalBoxFragment> container =
-      RunBlockLayoutAlgorithm(GetElementById("container"));
-  NGFragmentChildIterator iterator1(*container.get());
-
-  EXPECT_FALSE(iterator1->BoxFragment());
-  const NGFragmentItem* fragment_item = iterator1->FragmentItem();
-  ASSERT_TRUE(fragment_item);
-  EXPECT_EQ(fragment_item->Type(), NGFragmentItem::kLine);
-
-  // Descend into the line box.
-  NGFragmentChildIterator iterator2 = iterator1.Descend();
-  fragment_item = iterator2->FragmentItem();
-  ASSERT_TRUE(fragment_item);
-  EXPECT_TRUE(fragment_item->IsText());
-
-  EXPECT_TRUE(iterator2.Advance());
-  const NGPhysicalBoxFragment* fragment = iterator2->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->GetLayoutObject(), inlineblock);
-
-  // Descend into children of #inlineblock.
-  NGFragmentChildIterator iterator3 = iterator2.Descend();
-  fragment = iterator3->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->GetLayoutObject(), float1);
-  EXPECT_FALSE(iterator3.Advance());
-
-  // Continue with siblings of #inlineblock.
-  EXPECT_TRUE(iterator2.Advance());
-  fragment_item = iterator2->FragmentItem();
-  ASSERT_TRUE(fragment_item);
-  EXPECT_TRUE(fragment_item->IsText());
-
-  EXPECT_FALSE(iterator2.Advance());
-  EXPECT_FALSE(iterator1.Advance());
-}
-
-TEST_F(NGFragmentChildIteratorTest, FloatsInInline) {
-  SetBodyInnerHTML(R"HTML(
-    <div id="container">
-      <span id="span1" style="border:solid;">
-        <div id="float1" style="float:left;">
-          <div id="child"></div>
-        </div>
-      </span>
-    </div>
-  )HTML");
-
-  const LayoutObject* span1 = GetLayoutObjectByElementId("span1");
-  const LayoutObject* float1 = GetLayoutObjectByElementId("float1");
-  const LayoutObject* child = GetLayoutObjectByElementId("child");
-
-  scoped_refptr<const NGPhysicalBoxFragment> container =
-      RunBlockLayoutAlgorithm(GetElementById("container"));
-  NGFragmentChildIterator iterator1(*container.get());
-
-  const NGPhysicalBoxFragment* fragment = iterator1->BoxFragment();
-  EXPECT_FALSE(fragment);
-  const NGFragmentItem* item = iterator1->FragmentItem();
-  ASSERT_TRUE(item);
-  EXPECT_EQ(item->Type(), NGFragmentItem::kLine);
-
-  // Descend into the line box.
-  NGFragmentChildIterator iterator2 = iterator1.Descend();
-  fragment = iterator2->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->GetLayoutObject(), span1);
-
-  // Descend into children of #span1.
-  NGFragmentChildIterator iterator3 = iterator2.Descend();
-  fragment = iterator3->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->GetLayoutObject(), float1);
-
-  // Descend into children of #float1.
-  NGFragmentChildIterator iterator4 = iterator3.Descend();
-  fragment = iterator4->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->GetLayoutObject(), child);
-
-  EXPECT_FALSE(iterator4.Advance());
-  EXPECT_FALSE(iterator3.Advance());
-  EXPECT_FALSE(iterator2.Advance());
-  EXPECT_FALSE(iterator1.Advance());
-}
-
-TEST_F(NGFragmentChildIteratorTest, AbsposAndLine) {
-  SetBodyInnerHTML(R"HTML(
-    <div id="container" style="position:relative;">
-      <div id="abspos" style="position:absolute;"></div>
-      xxx
-    </div>
-  )HTML");
-
-  const LayoutObject* abspos = GetLayoutObjectByElementId("abspos");
-
-  scoped_refptr<const NGPhysicalBoxFragment> container =
-      RunBlockLayoutAlgorithm(GetElementById("container"));
-  NGFragmentChildIterator iterator1(*container.get());
-
-  const NGPhysicalBoxFragment* fragment = iterator1->BoxFragment();
-  EXPECT_FALSE(fragment);
-  const NGFragmentItem* item = iterator1->FragmentItem();
-  ASSERT_TRUE(item);
-  EXPECT_EQ(item->Type(), NGFragmentItem::kLine);
-
-  // Descend into the line box.
-  NGFragmentChildIterator iterator2 = iterator1.Descend();
-
-  fragment = iterator2->BoxFragment();
-  EXPECT_FALSE(fragment);
-  item = iterator2->FragmentItem();
-  ASSERT_TRUE(item);
-  EXPECT_TRUE(item->IsText());
-  EXPECT_FALSE(iterator2.Advance());
-
-  // The abspos is a sibling of the line box.
-  EXPECT_TRUE(iterator1.Advance());
-  fragment = iterator1->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->GetLayoutObject(), abspos);
-  EXPECT_FALSE(iterator1.Advance());
-}
-
-TEST_F(NGFragmentChildIteratorTest, BasicMulticol) {
-  SetBodyInnerHTML(R"HTML(
-    <div id="container">
-      <div id="mc" style="columns:3; padding:2px; column-fill:auto; column-gap:10px; width:320px; height:100px;">
-        <div id="child" style="margin-top:30px; margin-left:4px; height:200px;"></div>
-      </div>
-    </div>
-  )HTML");
-
-  const LayoutObject* mc = GetLayoutObjectByElementId("mc");
-  const LayoutObject* child = GetLayoutObjectByElementId("child");
-
-  scoped_refptr<const NGPhysicalBoxFragment> container =
-      RunBlockLayoutAlgorithm(GetElementById("container"));
-  NGFragmentChildIterator iterator(*container.get());
-
-  const NGPhysicalBoxFragment* fragment = iterator->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->GetLayoutObject(), mc);
-
-  // First column.
-  NGFragmentChildIterator child_iterator = iterator.Descend();
-  fragment = child_iterator->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_TRUE(fragment->IsColumnBox());
-  EXPECT_EQ(child_iterator->Link().offset.top, LayoutUnit(2));
-  EXPECT_EQ(child_iterator->Link().offset.left, LayoutUnit(2));
-  EXPECT_EQ(fragment->Size().height, LayoutUnit(100));
-  EXPECT_FALSE(fragment->GetLayoutObject());
-  EXPECT_FALSE(child_iterator->BlockBreakToken());
-
-  NGFragmentChildIterator grandchild_iterator = child_iterator.Descend();
-  fragment = grandchild_iterator->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(grandchild_iterator->Link().offset.top, LayoutUnit(30));
-  EXPECT_EQ(grandchild_iterator->Link().offset.left, LayoutUnit(4));
-  EXPECT_EQ(fragment->Size().height, LayoutUnit(70));
-  EXPECT_EQ(fragment->GetLayoutObject(), child);
-  EXPECT_FALSE(grandchild_iterator.Advance());
-  EXPECT_FALSE(grandchild_iterator->BlockBreakToken());
-
-  // Second column.
-  ASSERT_TRUE(child_iterator.Advance());
-  fragment = child_iterator->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_TRUE(fragment->IsColumnBox());
-  EXPECT_EQ(child_iterator->Link().offset.top, LayoutUnit(2));
-  EXPECT_EQ(child_iterator->Link().offset.left, LayoutUnit(112));
-  EXPECT_EQ(fragment->Size().height, LayoutUnit(100));
-  EXPECT_FALSE(fragment->GetLayoutObject());
-  const auto* break_token = child_iterator->BlockBreakToken();
-  ASSERT_TRUE(break_token);
-  EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(100));
-  EXPECT_EQ(break_token->InputNode().GetLayoutBox(), mc);
-
-  grandchild_iterator = child_iterator.Descend();
-  fragment = grandchild_iterator->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(grandchild_iterator->Link().offset.top, LayoutUnit(0));
-  EXPECT_EQ(grandchild_iterator->Link().offset.left, LayoutUnit(4));
-  EXPECT_EQ(fragment->Size().height, LayoutUnit(100));
-  EXPECT_EQ(fragment->GetLayoutObject(), child);
-  EXPECT_FALSE(grandchild_iterator.Advance());
-  break_token = grandchild_iterator->BlockBreakToken();
-  ASSERT_TRUE(break_token);
-  EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(70));
-  EXPECT_EQ(break_token->InputNode().GetLayoutBox(), child);
-
-  // Third column.
-  ASSERT_TRUE(child_iterator.Advance());
-  fragment = child_iterator->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_TRUE(fragment->IsColumnBox());
-  EXPECT_EQ(child_iterator->Link().offset.top, LayoutUnit(2));
-  EXPECT_EQ(child_iterator->Link().offset.left, LayoutUnit(222));
-  EXPECT_EQ(fragment->Size().height, LayoutUnit(100));
-  EXPECT_FALSE(fragment->GetLayoutObject());
-  break_token = child_iterator->BlockBreakToken();
-  ASSERT_TRUE(break_token);
-  EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(200));
-  EXPECT_EQ(break_token->InputNode().GetLayoutBox(), mc);
-
-  grandchild_iterator = child_iterator.Descend();
-  fragment = grandchild_iterator->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(grandchild_iterator->Link().offset.top, LayoutUnit(0));
-  EXPECT_EQ(grandchild_iterator->Link().offset.left, LayoutUnit(4));
-  EXPECT_EQ(fragment->Size().height, LayoutUnit(30));
-  EXPECT_EQ(fragment->GetLayoutObject(), child);
-  EXPECT_FALSE(grandchild_iterator.Advance());
-  break_token = grandchild_iterator->BlockBreakToken();
-  ASSERT_TRUE(break_token);
-  EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(170));
-  EXPECT_EQ(break_token->InputNode().GetLayoutBox(), child);
-
-  EXPECT_FALSE(child_iterator.Advance());
-  EXPECT_FALSE(iterator.Advance());
-}
-
-TEST_F(NGFragmentChildIteratorTest, ColumnSpanner) {
-  SetBodyInnerHTML(R"HTML(
-    <div id="container">
-      <div id="mc" style="columns:2;">
-        <div id="child">
-          <div id="grandchild1" style="height:150px;"></div>
-          <div id="spanner" style="column-span:all; height:11px;"></div>
-          <div id="grandchild2" style="height:66px;"></div>
-        </div>
-      </div>
-    </div>
-  )HTML");
-
-  scoped_refptr<const NGPhysicalBoxFragment> container =
-      RunBlockLayoutAlgorithm(GetElementById("container"));
-  NGFragmentChildIterator iterator1(*container.get());
-
-  const LayoutObject* mc = GetLayoutObjectByElementId("mc");
-  const LayoutObject* child = GetLayoutObjectByElementId("child");
-  const LayoutObject* spanner = GetLayoutObjectByElementId("spanner");
-  const LayoutObject* grandchild1 = GetLayoutObjectByElementId("grandchild1");
-  const LayoutObject* grandchild2 = GetLayoutObjectByElementId("grandchild2");
-
-  const NGPhysicalBoxFragment* fragment = iterator1->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->GetLayoutObject(), mc);
-
-  // First column before spanner.
-  NGFragmentChildIterator iterator2 = iterator1.Descend();
-  fragment = iterator2->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_TRUE(fragment->IsColumnBox());
-  EXPECT_EQ(fragment->Size().height, LayoutUnit(75));
-  EXPECT_FALSE(fragment->GetLayoutObject());
-  EXPECT_FALSE(iterator2->BlockBreakToken());
-
-  // First fragment for #child.
-  NGFragmentChildIterator iterator3 = iterator2.Descend();
-  fragment = iterator3->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->Size().height, LayoutUnit(75));
-  EXPECT_EQ(fragment->GetLayoutObject(), child);
-  EXPECT_FALSE(iterator3->BlockBreakToken());
-
-  // First fragment for #grandchild1.
-  NGFragmentChildIterator iterator4 = iterator3.Descend();
-  fragment = iterator4->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->Size().height, LayoutUnit(75));
-  EXPECT_EQ(fragment->GetLayoutObject(), grandchild1);
-  EXPECT_FALSE(iterator4->BlockBreakToken());
-  EXPECT_FALSE(iterator4.Advance());
-  EXPECT_FALSE(iterator3.Advance());
-
-  // Second column before spanner.
-  EXPECT_TRUE(iterator2.Advance());
-  fragment = iterator2->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_TRUE(fragment->IsColumnBox());
-  EXPECT_EQ(fragment->Size().height, LayoutUnit(75));
-  EXPECT_FALSE(fragment->GetLayoutObject());
-  const auto* break_token = iterator2->BlockBreakToken();
-  ASSERT_TRUE(break_token);
-  EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(75));
-  EXPECT_EQ(break_token->InputNode().GetLayoutBox(), mc);
-
-  // Second fragment for #child.
-  iterator3 = iterator2.Descend();
-  fragment = iterator3->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->Size().height, LayoutUnit(75));
-  EXPECT_EQ(fragment->GetLayoutObject(), child);
-  break_token = iterator3->BlockBreakToken();
-  ASSERT_TRUE(break_token);
-  EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(75));
-  EXPECT_EQ(break_token->InputNode().GetLayoutBox(), child);
-
-  // Second fragment for #grandchild1.
-  iterator4 = iterator3.Descend();
-  fragment = iterator4->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->Size().height, LayoutUnit(75));
-  EXPECT_EQ(fragment->GetLayoutObject(), grandchild1);
-  break_token = iterator4->BlockBreakToken();
-  ASSERT_TRUE(break_token);
-  EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(75));
-  EXPECT_EQ(break_token->InputNode().GetLayoutBox(), grandchild1);
-  EXPECT_FALSE(iterator4.Advance());
-  EXPECT_FALSE(iterator3.Advance());
-
-  // The spanner.
-  EXPECT_TRUE(iterator2.Advance());
-  fragment = iterator2->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->Size().height, LayoutUnit(11));
-  EXPECT_EQ(fragment->GetLayoutObject(), spanner);
-  EXPECT_FALSE(iterator2->BlockBreakToken());
-
-  // First column after spanner.
-  EXPECT_TRUE(iterator2.Advance());
-  fragment = iterator2->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_TRUE(fragment->IsColumnBox());
-  EXPECT_EQ(fragment->Size().height, LayoutUnit(33));
-  EXPECT_FALSE(fragment->GetLayoutObject());
-  break_token = iterator2->BlockBreakToken();
-  ASSERT_TRUE(break_token);
-  EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(150));
-  EXPECT_EQ(break_token->InputNode().GetLayoutBox(), mc);
-
-  // Third fragment for #child.
-  iterator3 = iterator2.Descend();
-  fragment = iterator3->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->Size().height, LayoutUnit(33));
-  EXPECT_EQ(fragment->GetLayoutObject(), child);
-  break_token = iterator3->BlockBreakToken();
-  ASSERT_TRUE(break_token);
-  EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(150));
-  EXPECT_EQ(break_token->InputNode().GetLayoutBox(), child);
-
-  // First fragment for #grandchild2.
-  iterator4 = iterator3.Descend();
-  fragment = iterator4->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->Size().height, LayoutUnit(33));
-  EXPECT_EQ(fragment->GetLayoutObject(), grandchild2);
-  break_token = iterator4->BlockBreakToken();
-  ASSERT_TRUE(break_token);
-  EXPECT_TRUE(break_token->IsBreakBefore());
-  EXPECT_EQ(break_token->InputNode().GetLayoutBox(), grandchild2);
-  EXPECT_FALSE(iterator4.Advance());
-  EXPECT_FALSE(iterator3.Advance());
-
-  // Second column after spanner.
-  EXPECT_TRUE(iterator2.Advance());
-  fragment = iterator2->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_TRUE(fragment->IsColumnBox());
-  EXPECT_EQ(fragment->Size().height, LayoutUnit(33));
-  EXPECT_FALSE(fragment->GetLayoutObject());
-  break_token = iterator2->BlockBreakToken();
-  ASSERT_TRUE(break_token);
-  EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(183));
-  EXPECT_EQ(break_token->InputNode().GetLayoutBox(), mc);
-
-  // Fourth fragment for #child.
-  iterator3 = iterator2.Descend();
-  fragment = iterator3->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->Size().height, LayoutUnit(33));
-  EXPECT_EQ(fragment->GetLayoutObject(), child);
-  break_token = iterator3->BlockBreakToken();
-  ASSERT_TRUE(break_token);
-  EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(183));
-  EXPECT_EQ(break_token->InputNode().GetLayoutBox(), child);
-
-  // Second fragment for #grandchild2.
-  iterator4 = iterator3.Descend();
-  fragment = iterator4->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->Size().height, LayoutUnit(33));
-  EXPECT_EQ(fragment->GetLayoutObject(), grandchild2);
-  break_token = iterator4->BlockBreakToken();
-  ASSERT_TRUE(break_token);
-  EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(33));
-  EXPECT_EQ(break_token->InputNode().GetLayoutBox(), grandchild2);
-  EXPECT_FALSE(iterator4.Advance());
-  EXPECT_FALSE(iterator3.Advance());
-
-  EXPECT_FALSE(iterator2.Advance());
-  EXPECT_FALSE(iterator1.Advance());
-}
-
-TEST_F(NGFragmentChildIteratorTest, NestedWithColumnSpanner) {
-  SetBodyInnerHTML(R"HTML(
-    <div id="container">
-      <div id="mc1" style="columns:2; column-fill:auto; height:100px;">
-        <div id="mc2" style="columns:2;">
-          <div id="child1" style="height:150px;"></div>
-          <div id="spanner1" style="column-span:all;">
-            <div id="spanner1child" style="height:55px;"></div>
-          </div>
-          <div id="child2" style="height:50px;"></div>
-          <div id="spanner2" style="column-span:all;">
-            <div id="spanner2child" style="height:20px;"></div>
-          </div>
-          <div id="child3" style="height:20px;"></div>
-        </div>
-      </div>
-    </div>
-  )HTML");
-
-  scoped_refptr<const NGPhysicalBoxFragment> container =
-      RunBlockLayoutAlgorithm(GetElementById("container"));
-  NGFragmentChildIterator iterator1(*container.get());
-
-  const LayoutObject* mc1 = GetLayoutObjectByElementId("mc1");
-  const LayoutObject* mc2 = GetLayoutObjectByElementId("mc2");
-  const LayoutObject* child1 = GetLayoutObjectByElementId("child1");
-  const LayoutObject* child2 = GetLayoutObjectByElementId("child2");
-  const LayoutObject* child3 = GetLayoutObjectByElementId("child3");
-  const LayoutObject* spanner1 = GetLayoutObjectByElementId("spanner1");
-  const LayoutObject* spanner2 = GetLayoutObjectByElementId("spanner2");
-  const LayoutObject* spanner1child =
-      GetLayoutObjectByElementId("spanner1child");
-  const LayoutObject* spanner2child =
-      GetLayoutObjectByElementId("spanner2child");
-
-  const NGPhysicalBoxFragment* fragment = iterator1->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->GetLayoutObject(), mc1);
-
-  // First outer column.
-  NGFragmentChildIterator iterator2 = iterator1.Descend();
-  fragment = iterator2->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_TRUE(fragment->IsColumnBox());
-  EXPECT_FALSE(fragment->GetLayoutObject());
-  EXPECT_FALSE(iterator2->BlockBreakToken());
-
-  // First fragment for #mc2.
-  NGFragmentChildIterator iterator3 = iterator2.Descend();
-  fragment = iterator3->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->GetLayoutObject(), mc2);
-  EXPECT_FALSE(iterator3->BlockBreakToken());
-
-  // First inner column in first outer column.
-  NGFragmentChildIterator iterator4 = iterator3.Descend();
-  fragment = iterator4->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_TRUE(fragment->IsColumnBox());
-  EXPECT_FALSE(fragment->GetLayoutObject());
-  EXPECT_FALSE(iterator4->BlockBreakToken());
-
-  // First fragment for #child1.
-  NGFragmentChildIterator iterator5 = iterator4.Descend();
-  fragment = iterator5->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->GetLayoutObject(), child1);
-  EXPECT_FALSE(iterator5->BlockBreakToken());
-  EXPECT_FALSE(iterator5.Advance());
-
-  // Second inner column in first outer column.
-  EXPECT_TRUE(iterator4.Advance());
-  fragment = iterator4->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_TRUE(fragment->IsColumnBox());
-  EXPECT_FALSE(fragment->GetLayoutObject());
-  const auto* break_token = iterator4->BlockBreakToken();
-  ASSERT_TRUE(break_token);
-  EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(75));
-  EXPECT_EQ(break_token->InputNode().GetLayoutBox(), mc2);
-
-  // Second fragment for #child1.
-  iterator5 = iterator4.Descend();
-  fragment = iterator5->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->GetLayoutObject(), child1);
-  break_token = iterator5->BlockBreakToken();
-  ASSERT_TRUE(break_token);
-  EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(75));
-  EXPECT_EQ(break_token->InputNode().GetLayoutBox(), child1);
-
-  // First fragment for #spanner1 (it's split into the first and second outer
-  // columns).
-  EXPECT_TRUE(iterator4.Advance());
-  fragment = iterator4->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->GetLayoutObject(), spanner1);
-  EXPECT_FALSE(iterator4->BlockBreakToken());
-
-  // First fragment for #spanner1child
-  iterator5 = iterator4.Descend();
-  fragment = iterator5->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->GetLayoutObject(), spanner1child);
-  EXPECT_FALSE(iterator5->BlockBreakToken());
-  EXPECT_FALSE(iterator5.Advance());
-  EXPECT_FALSE(iterator4.Advance());
-  EXPECT_FALSE(iterator3.Advance());
-
-  // Second outer column
-  EXPECT_TRUE(iterator2.Advance());
-  fragment = iterator2->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_TRUE(fragment->IsColumnBox());
-  EXPECT_FALSE(fragment->GetLayoutObject());
-  break_token = iterator2->BlockBreakToken();
-  ASSERT_TRUE(break_token);
-  EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(100));
-  EXPECT_EQ(break_token->InputNode().GetLayoutBox(), mc1);
-
-  // Second fragment for #mc2.
-  iterator3 = iterator2.Descend();
-  fragment = iterator3->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->GetLayoutObject(), mc2);
-  break_token = iterator3->BlockBreakToken();
-  ASSERT_TRUE(break_token);
-  EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(100));
-  EXPECT_EQ(break_token->InputNode().GetLayoutBox(), mc2);
-
-  // Second fragment for #spanner1 (it's split into the first and second outer
-  // columns).
-  iterator4 = iterator3.Descend();
-  fragment = iterator4->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->GetLayoutObject(), spanner1);
-  break_token = iterator4->BlockBreakToken();
-  ASSERT_TRUE(break_token);
-  EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(25));
-  EXPECT_EQ(break_token->InputNode().GetLayoutBox(), spanner1);
-
-  // Second fragment for #spanner1child.
-  iterator5 = iterator4.Descend();
-  fragment = iterator5->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->GetLayoutObject(), spanner1child);
-  break_token = iterator5->BlockBreakToken();
-  ASSERT_TRUE(break_token);
-  EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(25));
-  EXPECT_EQ(break_token->InputNode().GetLayoutBox(), spanner1child);
-  EXPECT_FALSE(iterator5.Advance());
-
-  // First inner column after first spanner in second outer column.
-  EXPECT_TRUE(iterator4.Advance());
-  fragment = iterator4->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_TRUE(fragment->IsColumnBox());
-  EXPECT_FALSE(fragment->GetLayoutObject());
-  break_token = iterator4->BlockBreakToken();
-  ASSERT_TRUE(break_token);
-  EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(150));
-  EXPECT_EQ(break_token->InputNode().GetLayoutBox(), mc2);
-
-  // First fragment for #child2.
-  iterator5 = iterator4.Descend();
-  fragment = iterator5->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->GetLayoutObject(), child2);
-  break_token = iterator5->BlockBreakToken();
-  EXPECT_TRUE(break_token);
-  EXPECT_TRUE(break_token->IsBreakBefore());
-  EXPECT_EQ(break_token->InputNode().GetLayoutBox(), child2);
-  EXPECT_FALSE(iterator5.Advance());
-
-  // Second inner column after first spanner in second outer column.
-  EXPECT_TRUE(iterator4.Advance());
-  fragment = iterator4->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_TRUE(fragment->IsColumnBox());
-  EXPECT_FALSE(fragment->GetLayoutObject());
-  break_token = iterator4->BlockBreakToken();
-  ASSERT_TRUE(break_token);
-  EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(175));
-  EXPECT_EQ(break_token->InputNode().GetLayoutBox(), mc2);
-
-  // Second fragment for #child2.
-  iterator5 = iterator4.Descend();
-  fragment = iterator5->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->GetLayoutObject(), child2);
-  break_token = iterator5->BlockBreakToken();
-  ASSERT_TRUE(break_token);
-  EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(25));
-  EXPECT_EQ(break_token->InputNode().GetLayoutBox(), child2);
-  EXPECT_FALSE(iterator5.Advance());
-
-  // The only fragment for #spanner2
-  EXPECT_TRUE(iterator4.Advance());
-  fragment = iterator4->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->GetLayoutObject(), spanner2);
-  EXPECT_FALSE(iterator4->BlockBreakToken());
-
-  // First fragment for #spanner2child
-  iterator5 = iterator4.Descend();
-  fragment = iterator5->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->GetLayoutObject(), spanner2child);
-  EXPECT_FALSE(iterator5->BlockBreakToken());
-  EXPECT_FALSE(iterator5.Advance());
-
-  // First inner column after second spanner in second outer column.
-  EXPECT_TRUE(iterator4.Advance());
-  fragment = iterator4->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_TRUE(fragment->IsColumnBox());
-  EXPECT_FALSE(fragment->GetLayoutObject());
-  break_token = iterator4->BlockBreakToken();
-  ASSERT_TRUE(break_token);
-  EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(200));
-  EXPECT_EQ(break_token->InputNode().GetLayoutBox(), mc2);
-
-  // First fragment for #child3.
-  iterator5 = iterator4.Descend();
-  fragment = iterator5->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->GetLayoutObject(), child3);
-  break_token = iterator5->BlockBreakToken();
-  EXPECT_TRUE(break_token);
-  EXPECT_TRUE(break_token->IsBreakBefore());
-  EXPECT_EQ(break_token->InputNode().GetLayoutBox(), child3);
-  EXPECT_FALSE(iterator5.Advance());
-
-  // Second inner column after second spanner in second outer column.
-  EXPECT_TRUE(iterator4.Advance());
-  fragment = iterator4->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_TRUE(fragment->IsColumnBox());
-  EXPECT_FALSE(fragment->GetLayoutObject());
-  break_token = iterator4->BlockBreakToken();
-  ASSERT_TRUE(break_token);
-  EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(210));
-  EXPECT_EQ(break_token->InputNode().GetLayoutBox(), mc2);
-
-  // Second fragment for #child3.
-  iterator5 = iterator4.Descend();
-  fragment = iterator5->BoxFragment();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(fragment->GetLayoutObject(), child3);
-  break_token = iterator5->BlockBreakToken();
-  ASSERT_TRUE(break_token);
-  EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(10));
-  EXPECT_EQ(break_token->InputNode().GetLayoutBox(), child3);
-  EXPECT_FALSE(iterator5.Advance());
-  EXPECT_FALSE(iterator4.Advance());
-  EXPECT_FALSE(iterator3.Advance());
-  EXPECT_FALSE(iterator2.Advance());
-  EXPECT_FALSE(iterator1.Advance());
-}
-
-}  // anonymous namespace
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc b/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc
index 5aea7279..1c85994 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h"
 
+#include "base/containers/adapters.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_box_fragment.h"
@@ -862,4 +863,73 @@
   return previous_break_token;
 }
 
+const NGBlockBreakToken* FindPreviousBreakToken(
+    const NGPhysicalBoxFragment& fragment) {
+  const LayoutBox* box = To<LayoutBox>(fragment.GetLayoutObject());
+  DCHECK(box);
+  DCHECK_GE(box->PhysicalFragmentCount(), 1u);
+
+  // Bail early if this is the first fragment. There'll be no previous break
+  // token then.
+  if (fragment.IsFirstForNode())
+    return nullptr;
+
+  // If this isn't the first fragment, it means that there has to be multiple
+  // fragments.
+  DCHECK_GT(box->PhysicalFragmentCount(), 1u);
+
+  const NGPhysicalBoxFragment* previous_fragment;
+  if (const auto* break_token = To<NGBlockBreakToken>(fragment.BreakToken())) {
+    // The sequence number of the outgoing break token is the same as the index
+    // of this fragment.
+    DCHECK_GE(break_token->SequenceNumber(), 1u);
+    previous_fragment =
+        box->GetPhysicalFragment(break_token->SequenceNumber() - 1);
+  } else {
+    // This is the last fragment, so its incoming break token will be the
+    // outgoing one from the penultimate fragment.
+    previous_fragment =
+        box->GetPhysicalFragment(box->PhysicalFragmentCount() - 2);
+  }
+  return To<NGBlockBreakToken>(previous_fragment->BreakToken());
+}
+
+wtf_size_t PreviousInnerFragmentainerIndex(
+    const NGPhysicalBoxFragment& fragment) {
+  // This should be a fragmentation context root, typically a multicol
+  // container.
+  DCHECK(fragment.IsFragmentationContextRoot());
+
+  const LayoutBox* box = To<LayoutBox>(fragment.GetLayoutObject());
+  DCHECK_GE(box->PhysicalFragmentCount(), 1u);
+  if (box->PhysicalFragmentCount() == 1)
+    return 0;
+
+  wtf_size_t idx = 0;
+  // Walk the list of fragments generated by the node, until we reach the
+  // specified one. Note that some fragments may not contain any fragmentainers
+  // at all, if all the space is taken up by column spanners, for instance.
+  for (const NGPhysicalBoxFragment& walker : box->PhysicalFragments()) {
+    if (&walker == &fragment)
+      return idx;
+    const auto* break_token = To<NGBlockBreakToken>(walker.BreakToken());
+
+    // Find the last fragmentainer inside this fragment.
+    const auto children = break_token->ChildBreakTokens();
+    for (scoped_refptr<const NGBreakToken> child_token :
+         base::Reversed(children)) {
+      DCHECK(child_token->IsBlockType());
+      if (child_token->InputNode() != break_token->InputNode()) {
+        // Not a fragmentainer (probably a spanner)
+        continue;
+      }
+      idx = To<NGBlockBreakToken>(child_token.get())->SequenceNumber() + 1;
+      break;
+    }
+  }
+
+  NOTREACHED();
+  return idx;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h b/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h
index 2b7f1f3..5dabb13 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h
@@ -351,6 +351,19 @@
     const NGBoxFragmentBuilder& container_builder,
     wtf_size_t index);
 
+// Return the break token that led to the creation of the fragment specified, or
+// nullptr if this is the first fragment. Note that this operation is O(n)
+// (number of fragments generated from the node), and should be avoided when
+// possible. This function should no longer be necessary once everything has
+// been properly converted to LayoutNG, and we have also gotten rid of the
+// fragment stitching of composited objects (will be fixed by
+// CompositeAfterPaint).
+const NGBlockBreakToken* FindPreviousBreakToken(const NGPhysicalBoxFragment&);
+
+// Return the index of the fragmentainer preceding the first fragmentainer
+// inside this fragment. Used by nested block fragmentation.
+wtf_size_t PreviousInnerFragmentainerIndex(const NGPhysicalBoxFragment&);
+
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_FRAGMENTATION_UTILS_H_
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
index 21333b4a..20e15e4 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
@@ -459,7 +459,6 @@
 }
 
 const FragmentData* NGPhysicalFragment::GetFragmentData() const {
-  DCHECK(CanTraverse());
   const LayoutBox* box = DynamicTo<LayoutBox>(GetLayoutObject());
   if (!box) {
     DCHECK(!GetLayoutObject());
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
index 0cdd681..851f3c40 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
@@ -133,6 +133,9 @@
   bool IsOutOfFlowPositioned() const {
     return IsBox() && BoxType() == NGBoxType::kOutOfFlowPositioned;
   }
+  bool IsFixedPositioned() const {
+    return IsCSSBox() && layout_object_->IsFixedPositioned();
+  }
   bool IsFloatingOrOutOfFlowPositioned() const {
     return IsFloating() || IsOutOfFlowPositioned();
   }
diff --git a/third_party/blink/renderer/core/page/context_menu_controller.cc b/third_party/blink/renderer/core/page/context_menu_controller.cc
index a8ade0d8..3d6ffff 100644
--- a/third_party/blink/renderer/core/page/context_menu_controller.cc
+++ b/third_party/blink/renderer/core/page/context_menu_controller.cc
@@ -642,12 +642,6 @@
         << "]\nVisibleSelection: "
         << selected_frame->Selection()
                .ComputeVisibleSelectionInDOMTreeDeprecated();
-    if (!result.IsContentEditable()) {
-      // Store text selection when it happens as it might be cleared when the
-      // browser will request |TextFragmentHandler| to generate
-      // selector.
-      UpdateTextFragmentHandler(selected_frame);
-    }
   }
 
   // If there is a text fragment at the same location as the click indicate that
@@ -784,16 +778,4 @@
   return true;
 }
 
-void ContextMenuController::UpdateTextFragmentHandler(
-    LocalFrame* selected_frame) {
-  if (!selected_frame->GetTextFragmentHandler())
-    return;
-
-  VisibleSelectionInFlatTree selection =
-      selected_frame->Selection().ComputeVisibleSelectionInFlatTree();
-  EphemeralRangeInFlatTree selection_range(selection.Start(), selection.End());
-  selected_frame->GetTextFragmentHandler()->MainFrameDidUpdateSelection(
-      selection_range);
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/page/context_menu_controller.h b/third_party/blink/renderer/core/page/context_menu_controller.h
index 008ded23..63a00e8 100644
--- a/third_party/blink/renderer/core/page/context_menu_controller.h
+++ b/third_party/blink/renderer/core/page/context_menu_controller.h
@@ -129,8 +129,6 @@
 
   Node* GetContextMenuNodeWithImageContents();
 
-  void UpdateTextFragmentHandler(LocalFrame*);
-
   HeapMojoAssociatedReceiver<mojom::blink::ContextMenuClient,
                              ContextMenuController>
       context_menu_client_receiver_{this, nullptr};
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_handler.cc b/third_party/blink/renderer/core/page/scrolling/text_fragment_handler.cc
index aceb9cf..a5e18427 100644
--- a/third_party/blink/renderer/core/page/scrolling/text_fragment_handler.cc
+++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_handler.cc
@@ -13,6 +13,7 @@
 #include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h"
 #include "third_party/blink/renderer/core/editing/position_with_affinity.h"
 #include "third_party/blink/renderer/core/editing/range_in_flat_tree.h"
+#include "third_party/blink/renderer/core/editing/selection_editor.h"
 #include "third_party/blink/renderer/core/editing/visible_units.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h"
@@ -32,6 +33,7 @@
 
 void TextFragmentHandler::BindTextFragmentReceiver(
     mojo::PendingReceiver<mojom::blink::TextFragmentReceiver> producer) {
+  StartPreemptiveGenerationIfNeeded();
   selector_producer_.reset();
   selector_producer_.Bind(
       std::move(producer),
@@ -46,6 +48,7 @@
 void TextFragmentHandler::RequestSelector(RequestSelectorCallback callback) {
   DCHECK(shared_highlighting::ShouldOfferLinkToText(
       GetFrame()->GetDocument()->Url()));
+  DCHECK(!GetFrame()->Selection().SelectedText().IsEmpty());
 
   if (PreemptiveGenerationEnabled()) {
     GetTextFragmentSelectorGenerator()->RecordSelectorStateUma();
@@ -56,9 +59,9 @@
 
     // If preemptive link generation is enabled, the generator would have
     // already been invoked when the selection was updated in
-    // MainFrameDidUpdateSelection. If that generation finished simply respond
-    // with the result. Otherwise, the response callback is stored so that we
-    // reply on completion.
+    // StartPreemptiveGenerationIfNeeded. If that generation finished simply
+    // respond with the result. Otherwise, the response callback is stored so
+    // that we reply on completion.
     if (!selector_requested_before_ready_.value())
       InvokeReplyCallback(preemptive_generation_result_.value());
   } else {
@@ -185,8 +188,17 @@
 }
 
 void TextFragmentHandler::StartGeneratingForCurrentSelection() {
+  if (GetFrame()->Selection().SelectedText().IsEmpty())
+    return;
+
+  VisibleSelectionInFlatTree selection =
+      GetFrame()->Selection().ComputeVisibleSelectionInFlatTree();
+  EphemeralRangeInFlatTree selection_range(selection.Start(), selection.End());
+  RangeInFlatTree* current_selection_range =
+      MakeGarbageCollected<RangeInFlatTree>(selection_range.StartPosition(),
+                                            selection_range.EndPosition());
   GetTextFragmentSelectorGenerator()->Generate(
-      *current_selection_range_,
+      *current_selection_range,
       WTF::Bind(&TextFragmentHandler::DidFinishSelectorGeneration,
                 WrapWeakPersistent(this)));
 }
@@ -219,12 +231,7 @@
   }
 }
 
-void TextFragmentHandler::MainFrameDidUpdateSelection(
-    const EphemeralRangeInFlatTree& selection_range) {
-  // TODO(bokan): Why can't we query this rather than trying to keep track of
-  // it?
-  current_selection_range_ = MakeGarbageCollected<RangeInFlatTree>(
-      selection_range.StartPosition(), selection_range.EndPosition());
+void TextFragmentHandler::StartPreemptiveGenerationIfNeeded() {
   if (PreemptiveGenerationEnabled() &&
       shared_highlighting::ShouldOfferLinkToText(
           GetFrame()->GetDocument()->Url())) {
@@ -235,16 +242,10 @@
 
 void TextFragmentHandler::Trace(Visitor* visitor) const {
   visitor->Trace(text_fragment_selector_generator_);
-  visitor->Trace(current_selection_range_);
   visitor->Trace(selector_producer_);
 }
 
 void TextFragmentHandler::DidDetachDocumentOrFrame() {
-  // A frame (and thus, this object) can survive multiple documents. When a
-  // document is detached we need to explicitly clear the selection range so
-  // that we don't keep alive a stale range.
-  current_selection_range_ = nullptr;
-
   // Clear out any state in the generator and cancel pending tasks so they
   // don't run after frame detachment.
   GetTextFragmentSelectorGenerator()->Reset();
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_handler.h b/third_party/blink/renderer/core/page/scrolling/text_fragment_handler.h
index 62e9fc80..6a74f84 100644
--- a/third_party/blink/renderer/core/page/scrolling/text_fragment_handler.h
+++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_handler.h
@@ -12,14 +12,14 @@
 namespace blink {
 
 class LocalFrame;
-class RangeInFlatTree;
 class TextFragmentAnchor;
 
 // TextFragmentHandler is responsible for handling requests from the
 // browser-side link-to-text/shared-highlighting feature. It is responsible for
 // generating a text fragment URL based on the current selection as well as
 // collecting information about and modifying text fragments on the current
-// page. This class is registered on and owned by the main frame of a page.
+// page. This class is registered on and owned by the frame that interacts with
+// the link-to-text/shared-highlighting feature.
 class CORE_EXPORT TextFragmentHandler final
     : public GarbageCollected<TextFragmentHandler>,
       public blink::mojom::blink::TextFragmentReceiver {
@@ -41,9 +41,9 @@
   void ExtractFirstFragmentRect(
       ExtractFirstFragmentRectCallback callback) override;
 
-  // Called by Blink when the selection in the main frame changes.
-  void MainFrameDidUpdateSelection(
-      const EphemeralRangeInFlatTree& selection_range);
+  // This starts the preemptive generation on the current selection if it is not
+  // empty.
+  void StartPreemptiveGenerationIfNeeded();
 
   void BindTextFragmentReceiver(
       mojo::PendingReceiver<mojom::blink::TextFragmentReceiver> producer);
@@ -61,9 +61,8 @@
   // result.
   void DidFinishSelectorGeneration(const TextFragmentSelector& selector);
 
-  // This starts running the generator over the selection in
-  // |current_selection_range_|. The result will be returned by invoking
-  // DidFinishSelectorGeneration().
+  // This starts running the generator over the current selection.
+  // The result will be returned by invoking DidFinishSelectorGeneration().
   void StartGeneratingForCurrentSelection();
 
   void RecordPreemptiveGenerationMetrics(const TextFragmentSelector& selector);
@@ -81,11 +80,6 @@
   // selection.
   Member<TextFragmentSelectorGenerator> text_fragment_selector_generator_;
 
-  // The Range of DOM currently selected by the user in the main frame. This
-  // class may preemptively start generating a selector based on this
-  // selection.
-  Member<RangeInFlatTree> current_selection_range_;
-
   // The result of preemptively generating on selection changes will be stored
   // in this member when completed. Used only in preemptive link generation
   // mode.
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_handler_test.cc b/third_party/blink/renderer/core/page/scrolling/text_fragment_handler_test.cc
index d247421..bb32852 100644
--- a/third_party/blink/renderer/core/page/scrolling/text_fragment_handler_test.cc
+++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_handler_test.cc
@@ -17,8 +17,10 @@
 #include "third_party/blink/renderer/bindings/core/v8/v8_union_arraybuffer_arraybufferview_string.h"
 #include "third_party/blink/renderer/core/css/css_font_face.h"
 #include "third_party/blink/renderer/core/css/font_face_set_document.h"
+#include "third_party/blink/renderer/core/editing/frame_selection.h"
 #include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h"
 #include "third_party/blink/renderer/core/editing/visible_units.h"
+#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
 #include "third_party/blink/renderer/core/testing/sim/sim_request.h"
 #include "third_party/blink/renderer/core/testing/sim/sim_test.h"
 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
@@ -50,6 +52,17 @@
     feature_list_.InitWithFeatures(enabled, disabled);
   }
 
+  void BeginEmptyFrame() {
+    // If a test case doesn't find a match and therefore doesn't schedule the
+    // beforematch event, we should still render a second frame as if we did
+    // schedule the event to retain test coverage.
+    // When the beforematch event is not scheduled, a DCHECK will fail on
+    // BeginFrame() because no event was scheduled, so we schedule an empty task
+    // here.
+    GetDocument().EnqueueAnimationFrameTask(WTF::Bind([]() {}));
+    Compositor().BeginFrame();
+  }
+
   void RunAsyncMatchingTasks() {
     auto* scheduler =
         ThreadScheduler::Current()->GetWebMainThreadSchedulerForTest();
@@ -58,9 +71,16 @@
     RunPendingTasks();
   }
 
+  void SetSelection(const Position& start, const Position& end) {
+    GetDocument().GetFrame()->Selection().SetSelection(
+        SelectionInDOMTree::Builder().SetBaseAndExtent(start, end).Build(),
+        SetSelectionOptions());
+  }
+
   String SelectThenRequestSelector(const Position& start, const Position& end) {
-    GetTextFragmentHandler().MainFrameDidUpdateSelection(
-        ToEphemeralRangeInFlatTree(EphemeralRange(start, end)));
+    SetSelection(start, end);
+
+    GetTextFragmentHandler().StartPreemptiveGenerationIfNeeded();
 
     bool callback_called = false;
     String selector;
@@ -171,6 +191,10 @@
     return *GetDocument().GetFrame()->GetTextFragmentHandler();
   }
 
+  bool HasTextFragmentHandler(LocalFrame* frame) {
+    return frame->GetTextFragmentHandler();
+  }
+
  protected:
   base::HistogramTester histogram_tester_;
   base::test::ScopedFeatureList feature_list_;
@@ -603,8 +627,9 @@
   const auto& selected_end = Position(first_paragraph, 5);
   ASSERT_EQ("First", PlainText(EphemeralRange(selected_start, selected_end)));
 
-  GetTextFragmentHandler().MainFrameDidUpdateSelection(
-      ToEphemeralRangeInFlatTree(EphemeralRange(selected_start, selected_end)));
+  SetSelection(selected_start, selected_end);
+  GetTextFragmentHandler().StartPreemptiveGenerationIfNeeded();
+
   base::RunLoop().RunUntilIdle();
 
   histogram_tester_.ExpectTotalCount("SharedHighlights.LinkGenerated", 1);
@@ -628,8 +653,9 @@
   const auto& selected_end = Position(first_paragraph, 5);
   ASSERT_EQ("First", PlainText(EphemeralRange(selected_start, selected_end)));
 
-  GetTextFragmentHandler().MainFrameDidUpdateSelection(
-      ToEphemeralRangeInFlatTree(EphemeralRange(selected_start, selected_end)));
+  SetSelection(selected_start, selected_end);
+  GetTextFragmentHandler().StartPreemptiveGenerationIfNeeded();
+
   base::RunLoop().RunUntilIdle();
 
   histogram_tester_.ExpectTotalCount("SharedHighlights.LinkGenerated", 0);
@@ -656,8 +682,9 @@
   ASSERT_EQ("default text",
             PlainText(EphemeralRange(selected_start, selected_end)));
 
-  GetTextFragmentHandler().MainFrameDidUpdateSelection(
-      ToEphemeralRangeInFlatTree(EphemeralRange(selected_start, selected_end)));
+  SetSelection(selected_start, selected_end);
+  GetTextFragmentHandler().StartPreemptiveGenerationIfNeeded();
+
   base::RunLoop().RunUntilIdle();
 
   histogram_tester_.ExpectTotalCount("SharedHighlights.LinkGenerated", 0);
@@ -679,6 +706,7 @@
   const auto& start = Position(p->lastChild(), 0);
   const auto& end = Position(p->lastChild(), 15);
   ASSERT_EQ("First paragraph", PlainText(EphemeralRange(start, end)));
+  SetSelection(start, end);
 
   auto callback = WTF::Bind([](const TextFragmentSelector& selector) {});
   GetDocument()
@@ -688,8 +716,7 @@
       ->SetCallbackForTesting(std::move(callback));
 
   // This shouldn't crash.
-  GetTextFragmentHandler().MainFrameDidUpdateSelection(
-      ToEphemeralRangeInFlatTree(EphemeralRange(start, end)));
+  GetTextFragmentHandler().StartPreemptiveGenerationIfNeeded();
   base::RunLoop().RunUntilIdle();
 }
 
@@ -740,6 +767,157 @@
   VerifyPreemptiveGenerationMetrics(false);
 }
 
+TEST_P(TextFragmentHandlerTest,
+       ShouldCreateTextFragmentHandlerAndRemoveHighlightForIframes) {
+  base::test::ScopedFeatureList feature_list_;
+  feature_list_.InitAndEnableFeature(
+      shared_highlighting::kSharedHighlightingAmp);
+  SimRequest main_request("https://example.com/test.html", "text/html");
+  SimRequest child_request("https://example.com/child.html#:~:text=test",
+                           "text/html");
+  LoadURL("https://example.com/test.html");
+  main_request.Complete(R"HTML(
+    <!DOCTYPE html>
+    <iframe id="iframe" src="child.html#:~:text=test"></iframe>
+  )HTML");
+
+  child_request.Complete(R"HTML(
+    <!DOCTYPE html>
+    <style>
+      p {
+        margin-top: 1000px;
+      }
+    </style>
+    <p>
+      test
+    </p>
+  )HTML");
+  RunAsyncMatchingTasks();
+
+  // Render two frames to handle the async step added by the beforematch event.
+  Compositor().BeginFrame();
+  BeginEmptyFrame();
+
+  Element* iframe = GetDocument().getElementById("iframe");
+  auto* child_frame =
+      To<LocalFrame>(To<HTMLFrameOwnerElement>(iframe)->ContentFrame());
+
+  EXPECT_EQ(1u, child_frame->GetDocument()->Markers().Markers().size());
+  EXPECT_FALSE(HasTextFragmentHandler(child_frame));
+
+  mojo::Remote<mojom::blink::TextFragmentReceiver> remote;
+  EXPECT_FALSE(remote.is_bound());
+  child_frame->BindTextFragmentReceiver(remote.BindNewPipeAndPassReceiver());
+
+  EXPECT_TRUE(HasTextFragmentHandler(child_frame));
+  EXPECT_TRUE(remote.is_bound());
+  remote.get()->RemoveFragments();
+
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(0u, child_frame->GetDocument()->Markers().Markers().size());
+
+  // Ensure the fragment is uninstalled
+  EXPECT_FALSE(child_frame->GetDocument()->View()->GetFragmentAnchor());
+}
+
+TEST_P(TextFragmentHandlerTest,
+       ShouldCreateTextFragmentHandlerAndRemoveHighlight) {
+  SimRequest request(
+      "https://example.com/"
+      "test.html#:~:text=test%20page&text=more%20text",
+      "text/html");
+  LoadURL(
+      "https://example.com/"
+      "test.html#:~:text=test%20page&text=more%20text");
+  request.Complete(R"HTML(
+    <!DOCTYPE html>
+    <style>
+      body {
+        height: 2200px;
+      }
+      #first {
+        position: absolute;
+        top: 1000px;
+      }
+      #second {
+        position: absolute;
+        top: 2000px;
+      }
+    </style>
+    <p id="first">This is a test page</p>
+    <p id="second">With some more text</p>
+  )HTML");
+  RunAsyncMatchingTasks();
+
+  // Render two frames to handle the async step added by the beforematch event.
+  Compositor().BeginFrame();
+  Compositor().BeginFrame();
+
+  EXPECT_EQ(2u, GetDocument().Markers().Markers().size());
+  EXPECT_TRUE(HasTextFragmentHandler(GetDocument().GetFrame()));
+
+  mojo::Remote<mojom::blink::TextFragmentReceiver> remote;
+  EXPECT_FALSE(remote.is_bound());
+  GetDocument().GetFrame()->BindTextFragmentReceiver(
+      remote.BindNewPipeAndPassReceiver());
+
+  EXPECT_TRUE(HasTextFragmentHandler(GetDocument().GetFrame()));
+  EXPECT_TRUE(remote.is_bound());
+  remote.get()->RemoveFragments();
+
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(0u, GetDocument().Markers().Markers().size());
+
+  // Ensure the fragment is uninstalled
+  EXPECT_FALSE(GetDocument().View()->GetFragmentAnchor());
+}
+
+TEST_P(TextFragmentHandlerTest,
+       ShouldCreateTextFragmentHandlerAndRequestSelector) {
+  SimRequest request("https://example.com/test.html", "text/html");
+  LoadURL("https://example.com/test.html");
+  request.Complete(R"HTML(
+    <!DOCTYPE html>
+    <div>Test page</div>
+    <p id='first'>First paragraph text that is longer than 20 chars</p>
+    <p id='second'>Second paragraph text</p>
+  )HTML");
+
+  Node* first_paragraph = GetDocument().getElementById("first")->firstChild();
+  const auto& selected_start = Position(first_paragraph, 0);
+  const auto& selected_end = Position(first_paragraph, 28);
+  ASSERT_EQ("First paragraph text that is",
+            PlainText(EphemeralRange(selected_start, selected_end)));
+
+  SetSelection(selected_start, selected_end);
+
+  mojo::Remote<mojom::blink::TextFragmentReceiver> remote;
+  EXPECT_TRUE(HasTextFragmentHandler(GetDocument().GetFrame()));
+  EXPECT_FALSE(remote.is_bound());
+
+  GetDocument().GetFrame()->BindTextFragmentReceiver(
+      remote.BindNewPipeAndPassReceiver());
+
+  EXPECT_TRUE(HasTextFragmentHandler(GetDocument().GetFrame()));
+  EXPECT_TRUE(remote.is_bound());
+
+  bool callback_called = false;
+  String selector;
+  auto lambda = [](bool& callback_called, String& selector,
+                   const String& generated_selector) {
+    selector = generated_selector;
+    callback_called = true;
+  };
+  auto callback =
+      WTF::Bind(lambda, std::ref(callback_called), std::ref(selector));
+  remote->RequestSelector(std::move(callback));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(callback_called);
+
+  EXPECT_EQ(selector, "First%20paragraph%20text%20that%20is");
+  VerifyPreemptiveGenerationMetrics(true);
+}
+
 struct PreemptiveLinkGenerationTestPassToString {
   std::string operator()(const testing::TestParamInfo<bool> b) const {
     return b.param ? "Preemptive" : "NonPreemptive";
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc b/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc
index 05923aa..5dc11019 100644
--- a/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc
+++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc
@@ -187,8 +187,12 @@
 TextFragmentSelectorGenerator::TextFragmentSelectorGenerator(
     LocalFrame* main_frame)
     : frame_(main_frame) {
-  // Scroll-to-text doesn't support iframes.
-  DCHECK(main_frame->IsMainFrame());
+  // Links are generally generated in the main frame except when the main frame
+  // delegates the text fragment to an iframe (e.g AMP Viewer pages).
+  if (!base::FeatureList::IsEnabled(
+          shared_highlighting::kSharedHighlightingAmp)) {
+    DCHECK(main_frame->IsMainFrame());
+  }
 }
 
 void TextFragmentSelectorGenerator::Generate(const RangeInFlatTree& range,
diff --git a/third_party/blink/renderer/core/paint/cull_rect_updater.cc b/third_party/blink/renderer/core/paint/cull_rect_updater.cc
index 3ff3e60d..c744e2a5 100644
--- a/third_party/blink/renderer/core/paint/cull_rect_updater.cc
+++ b/third_party/blink/renderer/core/paint/cull_rect_updater.cc
@@ -196,8 +196,7 @@
     if (should_match_fragments) {
       for (parent_fragment = &first_parent_fragment; parent_fragment;
            parent_fragment = parent_fragment->NextFragment()) {
-        if (parent_fragment->LogicalTopInFlowThread() ==
-            fragment->LogicalTopInFlowThread())
+        if (parent_fragment->FragmentID() == fragment->FragmentID())
           break;
       }
     } else {
diff --git a/third_party/blink/renderer/core/paint/fragment_data.h b/third_party/blink/renderer/core/paint/fragment_data.h
index e54f4b3..641bc33c1 100644
--- a/third_party/blink/renderer/core/paint/fragment_data.h
+++ b/third_party/blink/renderer/core/paint/fragment_data.h
@@ -52,12 +52,32 @@
   }
   void SetLayer(std::unique_ptr<PaintLayer>);
 
-  LayoutUnit LogicalTopInFlowThread() const {
-    return rare_data_ ? rare_data_->logical_top_in_flow_thread : LayoutUnit();
+  // A fragment ID unique within the LayoutObject. In NG block fragmentation,
+  // this is the fragmentainer index. In legacy block fragmentation, it's the
+  // flow thread block-offset.
+  wtf_size_t FragmentID() const {
+    return rare_data_ ? rare_data_->fragment_id : 0;
   }
+  void SetFragmentID(wtf_size_t id) {
+    if (!rare_data_ && id == 0)
+      return;
+    EnsureRareData().fragment_id = id;
+  }
+
+  LayoutUnit LogicalTopInFlowThread() const {
+#if DCHECK_IS_ON()
+    DCHECK(!rare_data_ || rare_data_->has_set_flow_thread_offset_ ||
+           !rare_data_->fragment_id);
+#endif
+    return LayoutUnit::FromRawValue(static_cast<int>(FragmentID()));
+  }
+
   void SetLogicalTopInFlowThread(LayoutUnit top) {
-    if (rare_data_ || top)
-      EnsureRareData().logical_top_in_flow_thread = top;
+    SetFragmentID(top.RawValue());
+#if DCHECK_IS_ON()
+    if (rare_data_)
+      rare_data_->has_set_flow_thread_offset_ = true;
+#endif
   }
 
   // The pagination offset is the additional factor to add in to map from flow
@@ -225,7 +245,7 @@
 
     // Fragment specific data.
     PhysicalOffset legacy_pagination_offset;
-    LayoutUnit logical_top_in_flow_thread;
+    wtf_size_t fragment_id = 0;
     std::unique_ptr<ObjectPaintProperties> paint_properties;
     std::unique_ptr<RefCountedPropertyTreeState> local_border_box_properties;
     bool is_clip_path_cache_valid = false;
@@ -234,6 +254,15 @@
     CullRect cull_rect_;
     CullRect contents_cull_rect_;
     std::unique_ptr<FragmentData> next_fragment_;
+
+#if DCHECK_IS_ON()
+    // Legacy block fragmentation sets the flow thread offset for each
+    // FragmentData object, and this is used as its fragment_id, whereas NG
+    // block fragmentation uses the fragmentainer index instead. Here's a flag
+    // which can be used to assert that legacy code which expects flow thread
+    // offsets actually gets that.
+    bool has_set_flow_thread_offset_ = false;
+#endif
   };
 
   RareData& EnsureRareData();
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
index b39306e..8d40c18 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
@@ -727,6 +727,7 @@
                                               PhysicalOffset paint_offset) {
   DCHECK(!box_fragment_.IsInlineFormattingContext());
   PaintInfo paint_info_for_descendants = paint_info.ForDescendants();
+  paint_info_for_descendants.SetIsInFragmentTraversal();
   for (const NGLink& child : box_fragment_.Children()) {
     const NGPhysicalFragment& child_fragment = *child;
     DCHECK(child_fragment.IsBox());
diff --git a/third_party/blink/renderer/core/paint/paint_info.h b/third_party/blink/renderer/core/paint/paint_info.h
index 37f14981..b6e1c70 100644
--- a/third_party/blink/renderer/core/paint/paint_info.h
+++ b/third_party/blink/renderer/core/paint/paint_info.h
@@ -28,8 +28,8 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_PAINT_INFO_H_
 
 #include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/layout/layout_object.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h"
+#include "third_party/blink/renderer/core/layout/layout_box.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
 // TODO(jchaffraix): Once we unify PaintBehavior and PaintLayerFlags, we should
 // move PaintLayerFlags to PaintPhase and rename it. Thus removing the need for
 // this #include
@@ -59,14 +59,11 @@
             PaintPhase phase,
             GlobalPaintFlags global_paint_flags,
             PaintLayerFlags paint_flags,
-            const LayoutBoxModelObject* paint_container = nullptr,
-            LayoutUnit fragment_logical_top_in_flow_thread = LayoutUnit())
+            const LayoutBoxModelObject* paint_container = nullptr)
       : context(context),
         phase(phase),
         cull_rect_(cull_rect),
         paint_container_(paint_container),
-        fragment_logical_top_in_flow_thread_(
-            fragment_logical_top_in_flow_thread),
         paint_flags_(paint_flags),
         global_paint_flags_(global_paint_flags) {}
 
@@ -76,8 +73,7 @@
         phase(copy_other_fields_from.phase),
         cull_rect_(copy_other_fields_from.cull_rect_),
         paint_container_(copy_other_fields_from.paint_container_),
-        fragment_logical_top_in_flow_thread_(
-            copy_other_fields_from.fragment_logical_top_in_flow_thread_),
+        fragment_id_(copy_other_fields_from.fragment_id_),
         paint_flags_(copy_other_fields_from.paint_flags_),
         global_paint_flags_(copy_other_fields_from.global_paint_flags_) {
     // We should never pass is_painting_scrolling_background_ other PaintInfo.
@@ -152,11 +148,16 @@
 
   // Returns the fragment of the current painting object matching the current
   // layer fragment.
-  const FragmentData* FragmentToPaint(const LayoutObject& object) const {
+  const FragmentData* LegacyFragmentToPaint(const LayoutObject& object) const {
+    if (fragment_id_ == WTF::kNotFound) {
+      // We haven't been set up for legacy block fragmentation, so the object
+      // better not be fragmented, then.
+      DCHECK(!object.FirstFragment().NextFragment());
+      return &object.FirstFragment();
+    }
     for (const auto* fragment = &object.FirstFragment(); fragment;
          fragment = fragment->NextFragment()) {
-      if (fragment->LogicalTopInFlowThread() ==
-          fragment_logical_top_in_flow_thread_)
+      if (fragment->FragmentID() == fragment_id_)
         return fragment;
     }
     // No fragment of the current painting object matches the layer fragment,
@@ -164,20 +165,43 @@
     return nullptr;
   }
 
-  // Returns the FragmentData of the specified physical fragment. If fragment
-  // traversal is supported, it will map directly to the right FragmentData.
-  // Otherwise we'll fall back to matching against the current
+  const FragmentData* FragmentToPaint(const LayoutObject& object) const {
+    if (const auto* box = DynamicTo<LayoutBox>(&object)) {
+      // We're are looking up FragmentData via LayoutObject, even though the
+      // object has NG fragments. This happens with objects that don't support
+      // fragment traversal, such as replaced content. We cannot use legacy-
+      // based lookup in such cases, as we might not have set a fragment ID to
+      // match against. Since we got here, though, it has to mean that we should
+      // paint the one and only fragment.
+      if (box->PhysicalFragmentCount()) {
+        // TODO(mstensho): We should DCHECK that box->PhysicalFragmentCount() is
+        // exactly 1 here (i.e. that the object is monolithic), but we are not
+        // ready for that yet, as there's code that enters legacy paint
+        // functions when we're traversing the fragment tree. See
+        // e.g. NGBoxFragmentPainter::RecordScrollHitTestData(), and how it does
+        // the job by invoking BoxPainter, which has no concept of
+        // fragments. One of the tests that would fail with such a DCHECK here
+        // is:
+        // virtual/layout_ng_block_frag/fast/multicol/overflow-across-columns.html
+        return &box->FirstFragment();
+      }
+    }
+    return LegacyFragmentToPaint(object);
+  }
+
+  // Returns the FragmentData of the specified physical fragment. If we're
+  // performing fragment traversal, it will map directly to the right
+  // FragmentData. Otherwise we'll fall back to matching against the current
   // PaintLayerFragment.
   const FragmentData* FragmentToPaint(
       const NGPhysicalFragment& fragment) const {
-    if (fragment.CanTraverse())
+    if (fragment_id_ == WTF::kNotFound)
       return fragment.GetFragmentData();
-    return FragmentToPaint(*fragment.GetLayoutObject());
+    return LegacyFragmentToPaint(*fragment.GetLayoutObject());
   }
 
-  void SetFragmentLogicalTopInFlowThread(LayoutUnit fragment_logical_top) {
-    fragment_logical_top_in_flow_thread_ = fragment_logical_top;
-  }
+  void SetFragmentID(wtf_size_t id) { fragment_id_ = id; }
+  void SetIsInFragmentTraversal() { fragment_id_ = WTF::kNotFound; }
 
   bool IsPaintingScrollingBackground() const {
     DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
@@ -206,9 +230,13 @@
   // The box model object that originates the current painting.
   const LayoutBoxModelObject* paint_container_;
 
-  // The logical top of the current fragment of the self-painting PaintLayer
-  // which initiated the current painting, in the containing flow thread.
-  LayoutUnit fragment_logical_top_in_flow_thread_;
+  // The ID of the fragment that we're currently painting.
+  //
+  // This is always used in legacy block fragmentation. In NG block
+  // fragmentation, it's only used when painting self-painting non-atomic
+  // inlines (because we currently have no way of mapping from
+  // NGPhysicalFragment to FragmentData in such cases).
+  wtf_size_t fragment_id_ = WTF::kNotFound;
 
   PaintLayerFlags paint_flags_;
   const GlobalPaintFlags global_paint_flags_;
diff --git a/third_party/blink/renderer/core/paint/paint_invalidator.cc b/third_party/blink/renderer/core/paint/paint_invalidator.cc
index 7affc79..8289b31 100644
--- a/third_party/blink/renderer/core/paint/paint_invalidator.cc
+++ b/third_party/blink/renderer/core/paint/paint_invalidator.cc
@@ -17,7 +17,6 @@
 #include "third_party/blink/renderer/core/layout/layout_view.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h"
 #include "third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
 #include "third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.h"
 #include "third_party/blink/renderer/core/page/link_highlight.h"
@@ -32,14 +31,12 @@
 namespace blink {
 
 void PaintInvalidator::UpdatePaintingLayer(const LayoutObject& object,
-                                           PaintInvalidatorContext& context,
-                                           bool is_ng_painting) {
+                                           PaintInvalidatorContext& context) {
   if (object.HasLayer() &&
       To<LayoutBoxModelObject>(object).HasSelfPaintingLayer()) {
     context.painting_layer = To<LayoutBoxModelObject>(object).Layer();
-  } else if (!is_ng_painting &&
-             (object.IsColumnSpanAll() ||
-              object.IsFloatingWithNonContainingBlockParent())) {
+  } else if (object.IsColumnSpanAll() ||
+             object.IsFloatingWithNonContainingBlockParent()) {
     // See |LayoutObject::PaintingLayer| for the special-cases of floating under
     // inline and multicolumn.
     // Post LayoutNG the |LayoutObject::IsFloatingWithNonContainingBlockParent|
@@ -68,8 +65,7 @@
 
 void PaintInvalidator::UpdateDirectlyCompositedContainer(
     const LayoutObject& object,
-    PaintInvalidatorContext& context,
-    bool is_ng_painting) {
+    PaintInvalidatorContext& context) {
   if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
     return;
 
@@ -88,9 +84,8 @@
     context.directly_composited_container_for_stacked_contents =
         context.directly_composited_container =
             &object.DirectlyCompositableContainer();
-  } else if (!is_ng_painting &&
-             (object.IsColumnSpanAll() ||
-              object.IsFloatingWithNonContainingBlockParent())) {
+  } else if (object.IsColumnSpanAll() ||
+             object.IsFloatingWithNonContainingBlockParent()) {
     // In these cases, the object may belong to an ancestor of the current
     // paint invalidation container, in paint order.
     // Post LayoutNG the |LayoutObject::IsFloatingWithNonContainingBlockParent|
@@ -141,11 +136,6 @@
       context.subtree_flags = 0;
     }
   }
-
-  DCHECK_EQ(context.directly_composited_container,
-            object.DirectlyCompositableContainer())
-      << object;
-  DCHECK_EQ(context.painting_layer, object.PaintingLayer()) << object;
 }
 
 void PaintInvalidator::UpdateFromTreeBuilderContext(
@@ -311,9 +301,26 @@
 
   object.GetMutableForPainting().EnsureIsReadyForPaintInvalidation();
 
-  UpdatePaintingLayer(object, context, /* is_ng_painting */ !!pre_paint_info);
-  UpdateDirectlyCompositedContainer(object, context,
-                                    /* is_ng_painting */ !!pre_paint_info);
+  UpdatePaintingLayer(object, context);
+  UpdateDirectlyCompositedContainer(object, context);
+
+#if DCHECK_IS_ON()
+  // Assert that the container state in the invalidation context is consistent
+  // with what the LayoutObject tree says. We cannot do this if we're fragment-
+  // traversing an "orphaned" object (an object that has a fragment inside a
+  // fragmentainer, even though not all its ancestor objects have it; this may
+  // happen to OOFs, and also to floats, if they are inside a non-atomic
+  // inline). In such cases we'll just have to live with the inconsitency, which
+  // means that we'll lose any paint effects from such "missing" ancestors.
+  if (!pre_paint_info || !pre_paint_info->is_inside_orphaned_object) {
+    if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+      DCHECK_EQ(context.directly_composited_container,
+                object.DirectlyCompositableContainer())
+          << object;
+    }
+    DCHECK_EQ(context.painting_layer, object.PaintingLayer()) << object;
+  }
+#endif  // DCHECK_IS_ON()
 
   if (!object.ShouldCheckForPaintInvalidation() && !context.NeedsSubtreeWalk())
     return false;
@@ -339,7 +346,7 @@
   }
 
   if (pre_paint_info) {
-    FragmentData& fragment_data = pre_paint_info->fragment_data;
+    FragmentData& fragment_data = *pre_paint_info->fragment_data;
     context.fragment_data = &fragment_data;
 
     if (tree_builder_context) {
diff --git a/third_party/blink/renderer/core/paint/paint_invalidator.h b/third_party/blink/renderer/core/paint/paint_invalidator.h
index 58ceb37..7c6d974 100644
--- a/third_party/blink/renderer/core/paint/paint_invalidator.h
+++ b/third_party/blink/renderer/core/paint/paint_invalidator.h
@@ -106,11 +106,10 @@
   friend struct PaintInvalidatorContext;
 
   ALWAYS_INLINE void UpdatePaintingLayer(const LayoutObject&,
-                                         PaintInvalidatorContext&,
-                                         bool is_ng_painting);
-  ALWAYS_INLINE void UpdateDirectlyCompositedContainer(const LayoutObject&,
-                                                       PaintInvalidatorContext&,
-                                                       bool is_ng_painting);
+                                         PaintInvalidatorContext&);
+  ALWAYS_INLINE void UpdateDirectlyCompositedContainer(
+      const LayoutObject&,
+      PaintInvalidatorContext&);
   ALWAYS_INLINE void UpdateFromTreeBuilderContext(
       const PaintPropertyTreeBuilderFragmentContext&,
       PaintInvalidatorContext&);
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc
index f748b7c..5523be3 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -1817,8 +1817,7 @@
       } else if (should_match_fragments) {
         for (root_fragment_data = &first_root_fragment_data; root_fragment_data;
              root_fragment_data = root_fragment_data->NextFragment()) {
-          if (root_fragment_data->LogicalTopInFlowThread() ==
-              fragment_data->LogicalTopInFlowThread())
+          if (root_fragment_data->FragmentID() == fragment_data->FragmentID())
             break;
         }
       } else {
diff --git a/third_party/blink/renderer/core/paint/paint_layer_painter.cc b/third_party/blink/renderer/core/paint/paint_layer_painter.cc
index 1b2303d..55179cf 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_painter.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_painter.cc
@@ -731,18 +731,19 @@
       context.GetPaintController(), chunk_properties, paint_layer_,
       DisplayItem::PaintPhaseToDrawingType(phase));
 
-  PaintInfo paint_info(
-      context, cull_rect, phase, painting_info.GetGlobalPaintFlags(),
-      paint_flags, &painting_info.root_layer->GetLayoutObject(),
-      fragment.fragment_data ? fragment.fragment_data->LogicalTopInFlowThread()
-                             : LayoutUnit());
+  PaintInfo paint_info(context, cull_rect, phase,
+                       painting_info.GetGlobalPaintFlags(), paint_flags,
+                       &painting_info.root_layer->GetLayoutObject());
   if (paint_layer_.GetLayoutObject().ChildPaintBlockedByDisplayLock())
     paint_info.SetDescendantPaintingBlocked(true);
 
-  if (fragment.physical_fragment)
+  if (fragment.physical_fragment) {
     NGBoxFragmentPainter(*fragment.physical_fragment).Paint(paint_info);
-  else
+  } else {
+    if (fragment.fragment_data)
+      paint_info.SetFragmentID(fragment.fragment_data->FragmentID());
     paint_layer_.GetLayoutObject().Paint(paint_info);
+  }
 }
 
 static CullRect LegacyCullRect(const PaintLayerFragment& fragment,
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
index 3d0cc4920..f10c509 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -28,7 +28,7 @@
 #include "third_party/blink/renderer/core/layout/layout_view.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
 #include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h"
 #include "third_party/blink/renderer/core/layout/svg/layout_svg_root.h"
@@ -255,6 +255,38 @@
 
   bool IsInNGFragmentTraversal() const { return pre_paint_info_; }
 
+  void SwitchToOOFContext(
+      PaintPropertyTreeBuilderFragmentContext::ContainingBlockContext&
+          oof_context) const {
+    context_.current = oof_context;
+
+    // If we're not block-fragmented, or if we're traversing the fragment tree
+    // to an orphaned object, simply setting a new context is all we have to do.
+    if (!oof_context.is_in_block_fragmentation ||
+        (pre_paint_info_ && pre_paint_info_->is_inside_orphaned_object))
+      return;
+
+    // Inside NG block fragmentation we have to perform an offset adjustment.
+    // An OOF fragment that is contained by something inside a fragmentainer
+    // will be a direct child of the fragmentainer, rather than a child of its
+    // actual containing block. We therefore need to adjust the offset to make
+    // us relative to the fragmentainer before applying the offset of the OOF.
+    PhysicalOffset delta =
+        oof_context.paint_offset - context_.fragmentainer_paint_offset;
+    // So, we did store |fragmentainer_paint_offset| when entering the
+    // fragmentainer, but the offset may have been reset by
+    // UpdateForPaintOffsetTranslation() since we entered it, which we'll need
+    // to compensate for now.
+    delta += context_.adjustment_for_oof_in_fragmentainer;
+    context_.current.paint_offset -= delta;
+  }
+
+  void ResetPaintOffset(PhysicalOffset new_offset = PhysicalOffset()) {
+    context_.adjustment_for_oof_in_fragmentainer +=
+        context_.current.paint_offset - new_offset;
+    context_.current.paint_offset = new_offset;
+  }
+
   void OnUpdate(PaintPropertyChangeType change) {
     property_changed_ = std::max(property_changed_, change);
   }
@@ -504,7 +536,7 @@
   // compositing code.
   if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
       NeedsIsolationNodes(object_)) {
-    context_.current.paint_offset = PhysicalOffset();
+    ResetPaintOffset();
     context_.current.directly_composited_container_paint_offset_subpixel_delta =
         PhysicalOffset();
     return;
@@ -519,9 +551,7 @@
   PhysicalOffset subpixel_accumulation;
   if (RequiresFragmentStitching()) {
     const LayoutBox& box = To<LayoutBox>(object_);
-    const NGFragmentChildIterator& iterator = pre_paint_info_->iterator;
-    const NGPhysicalBoxFragment& fragment = *iterator->BoxFragment();
-    const NGBlockBreakToken* incoming_break_token = iterator->BlockBreakToken();
+    const NGPhysicalBoxFragment& fragment = pre_paint_info_->box_fragment;
 
     // Calculate this fragment's rectangle relatively to the enclosing stitched
     // layout object, with help from the break token.
@@ -533,7 +563,8 @@
     WritingModeConverter converter(box.StyleRef().GetWritingDirection(),
                                    PhysicalSize(box.Size()));
     LogicalOffset logical_offset;
-    if (incoming_break_token)
+    if (const NGBlockBreakToken* incoming_break_token =
+            FindPreviousBreakToken(fragment))
       logical_offset.block_offset = incoming_break_token->ConsumedBlockSize();
     LogicalRect logical_rect(logical_offset,
                              converter.ToLogical(fragment.Size()));
@@ -545,7 +576,7 @@
     // offset in order to get to the right offset for each fragment.
     new_paint_offset = converter.ToPhysical(logical_rect).offset;
 
-    if (&pre_paint_info_->fragment_data == &object_.FirstFragment()) {
+    if (pre_paint_info_->fragment_data == &object_.FirstFragment()) {
       // Make the translation relatively to the top/left corner of the box. In
       // vertical-rl writing mode, the first fragment is not the leftmost one.
       PhysicalOffset topleft = context_.current.paint_offset - new_paint_offset;
@@ -576,7 +607,7 @@
     // If the object has a non-translation transform, discard the fractional
     // paint offset which can't be transformed by the transform.
     if (!CanPropagateSubpixelAccumulation()) {
-      context_.current.paint_offset = new_paint_offset;
+      ResetPaintOffset(new_paint_offset);
       context_.current
           .directly_composited_container_paint_offset_subpixel_delta =
           PhysicalOffset();
@@ -584,7 +615,7 @@
     }
   }
 
-  context_.current.paint_offset = new_paint_offset + subpixel_accumulation;
+  ResetPaintOffset(new_paint_offset + subpixel_accumulation);
 
   bool can_be_directly_composited =
       RuntimeEnabledFeatures::CompositeAfterPaintEnabled()
@@ -973,10 +1004,11 @@
         // Each individual fragment should have its own transform origin, based
         // on the fragment size. We'll do that, unless the fragments aren't to
         // be stitched together.
-        PhysicalSize size(
-            !pre_paint_info_ || RequiresFragmentStitching()
-                ? PhysicalSize(box.Size())
-                : pre_paint_info_->iterator->BoxFragment()->Size());
+        PhysicalSize size;
+        if (!pre_paint_info_ || RequiresFragmentStitching())
+          size = PhysicalSize(box.Size());
+        else
+          size = pre_paint_info_->box_fragment.Size();
         TransformationMatrix matrix;
         style.ApplyTransform(
             matrix, size.ToLayoutSize(), ComputedStyle::kExcludeTransformOrigin,
@@ -1100,9 +1132,10 @@
          (object.HasLayer() || object.IsSVGChild());
 }
 
-static bool NeedsClipPathClip(const LayoutObject& object) {
+static bool NeedsClipPathClip(const LayoutObject& object,
+                              const FragmentData& fragment_data) {
   // We should have already updated the clip path cache when this is called.
-  if (object.FirstFragment().ClipPathPath()) {
+  if (fragment_data.ClipPathPath()) {
     DCHECK(MayNeedClipPathClip(object));
     return true;
   }
@@ -1639,7 +1672,7 @@
 
 void FragmentPaintPropertyTreeBuilder::UpdateClipPathClip() {
   if (NeedsPaintPropertyUpdate()) {
-    if (!NeedsClipPathClip(object_)) {
+    if (!NeedsClipPathClip(object_, fragment_data_)) {
       OnClearClip(properties_->ClearClipPathClip());
     } else {
       ClipPaintPropertyNode::State state(
@@ -1868,9 +1901,9 @@
       } else if (object_.IsBox()) {
         PhysicalRect clip_rect;
         if (pre_paint_info_) {
-          const NGFragmentChildIterator& iterator = pre_paint_info_->iterator;
-          clip_rect = iterator->BoxFragment()->OverflowClipRect(
-              context_.current.paint_offset, iterator->BlockBreakToken());
+          clip_rect = pre_paint_info_->box_fragment.OverflowClipRect(
+              context_.current.paint_offset,
+              FindPreviousBreakToken(pre_paint_info_->box_fragment));
         } else {
           clip_rect = To<LayoutBox>(object_).OverflowClipRect(
               context_.current.paint_offset);
@@ -2452,15 +2485,6 @@
 }
 
 void FragmentPaintPropertyTreeBuilder::UpdatePaintOffset() {
-  if (IsInNGFragmentTraversal()) {
-    // Text and non-atomic inlines are special, in that they share one
-    // FragmentData per fragmentainer, so their paint offset is kept at their
-    // container. For all other objects, include the offset now.
-    if (object_.IsBox())
-      context_.current.paint_offset += pre_paint_info_->iterator->Link().offset;
-    return;
-  }
-
   // Paint offsets for fragmented content are computed from scratch.
   const auto* enclosing_pagination_layer =
       full_context_.painting_layer->EnclosingPaginationLayer();
@@ -2515,14 +2539,17 @@
     return;
   }
 
-  if (object_.IsFloating() && !object_.IsInLayoutNGInlineFormattingContext())
-    context_.current.paint_offset = context_.paint_offset_for_float;
+  if (!pre_paint_info_) {
+    if (object_.IsFloating() && !object_.IsInLayoutNGInlineFormattingContext())
+      context_.current.paint_offset = context_.paint_offset_for_float;
 
-  // Multicolumn spanners are painted starting at the multicolumn container (but
-  // still inherit properties in layout-tree order) so reset the paint offset.
-  if (object_.IsColumnSpanAll()) {
-    context_.current.paint_offset =
-        object_.Container()->FirstFragment().PaintOffset();
+    // Multicolumn spanners are painted starting at the multicolumn container
+    // (but still inherit properties in layout-tree order) so reset the paint
+    // offset.
+    if (object_.IsColumnSpanAll()) {
+      context_.current.paint_offset =
+          object_.Container()->FirstFragment().PaintOffset();
+    }
   }
 
   if (object_.IsBoxModelObject()) {
@@ -2535,8 +2562,12 @@
             box_model_object.OffsetForInFlowPosition();
         break;
       case EPosition::kAbsolute: {
-        DCHECK_EQ(full_context_.container_for_absolute_position,
-                  box_model_object.Container());
+#if DCHECK_IS_ON()
+        if (!pre_paint_info_ || !pre_paint_info_->is_inside_orphaned_object) {
+          DCHECK_EQ(full_context_.container_for_absolute_position,
+                    box_model_object.Container());
+        }
+#endif
         if (RuntimeEnabledFeatures::TransformInteropEnabled()) {
           // FIXME(dbaron): When the TransformInteropEnabled flag is removed
           // because it's always enabled, we should move these variables from
@@ -2547,7 +2578,7 @@
           context_.absolute_position.rendering_context_id =
               context_.current.rendering_context_id;
         }
-        context_.current = context_.absolute_position;
+        SwitchToOOFContext(context_.absolute_position);
 
         // Absolutely positioned content in an inline should be positioned
         // relative to the inline.
@@ -2564,8 +2595,12 @@
       case EPosition::kSticky:
         break;
       case EPosition::kFixed: {
-        DCHECK_EQ(full_context_.container_for_fixed_position,
-                  box_model_object.Container());
+#if DCHECK_IS_ON()
+        if (!pre_paint_info_ || !pre_paint_info_->is_inside_orphaned_object) {
+          DCHECK_EQ(full_context_.container_for_fixed_position,
+                    box_model_object.Container());
+        }
+#endif
         if (RuntimeEnabledFeatures::TransformInteropEnabled()) {
           // FIXME(dbaron): When the TransformInteropEnabled flag is removed
           // because it's always enabled, we should move these variables from
@@ -2576,7 +2611,7 @@
           context_.fixed_position.rendering_context_id =
               context_.current.rendering_context_id;
         }
-        context_.current = context_.fixed_position;
+        SwitchToOOFContext(context_.fixed_position);
         // Fixed-position elements that are fixed to the viewport have a
         // transform above the scroll of the LayoutView. Child content is
         // relative to that transform, and hence the fixed-position element.
@@ -2598,21 +2633,32 @@
     }
   }
 
-  if (object_.IsBox()) {
-    // TODO(pdr): Several calls in this function walk back up the tree to
-    // calculate containers (e.g., physicalLocation, offsetForInFlowPosition*).
-    // The containing block and other containers can be stored on
-    // PaintPropertyTreeBuilderFragmentContext instead of recomputing them.
-    context_.current.paint_offset += To<LayoutBox>(object_).PhysicalLocation();
+  if (const auto* box = DynamicTo<LayoutBox>(&object_)) {
+    if (pre_paint_info_) {
+      context_.current.paint_offset += pre_paint_info_->paint_offset;
 
-    // This is a weird quirk that table cells paint as children of table rows,
-    // but their location have the row's location baked-in.
-    // Similar adjustment is done in LayoutTableCell::offsetFromContainer().
-    if (object_.IsTableCellLegacy()) {
-      LayoutObject* parent_row = object_.Parent();
-      DCHECK(parent_row && parent_row->IsTableRow());
-      context_.current.paint_offset -=
-          To<LayoutBox>(parent_row)->PhysicalLocation();
+      // Determine whether we're inside block fragmentation or not. OOF
+      // descendants need special treatment inside block fragmentation.
+      context_.current.is_in_block_fragmentation =
+          pre_paint_info_->fragmentainer_idx != WTF::kNotFound &&
+          box->GetNGPaginationBreakability() != LayoutBox::kForbidBreaks;
+    } else {
+      // TODO(pdr): Several calls in this function walk back up the tree to
+      // calculate containers (e.g., physicalLocation,
+      // offsetForInFlowPosition*).  The containing block and other containers
+      // can be stored on PaintPropertyTreeBuilderFragmentContext instead of
+      // recomputing them.
+      context_.current.paint_offset += box->PhysicalLocation();
+
+      // This is a weird quirk that table cells paint as children of table rows,
+      // but their location have the row's location baked-in.
+      // Similar adjustment is done in LayoutTableCell::offsetFromContainer().
+      if (object_.IsTableCellLegacy()) {
+        LayoutObject* parent_row = object_.Parent();
+        DCHECK(parent_row && parent_row->IsTableRow());
+        context_.current.paint_offset -=
+            To<LayoutBox>(parent_row)->PhysicalLocation();
+      }
     }
   }
 
@@ -2942,7 +2988,7 @@
     context_.fragments.push_back(PaintPropertyTreeBuilderFragmentContext());
   else
     context_.fragments.resize(1);
-  InitFragmentPaintProperties(pre_paint_info_->fragment_data,
+  InitFragmentPaintProperties(*pre_paint_info_->fragment_data,
                               needs_paint_properties, context_.fragments[0]);
 }
 
@@ -3810,7 +3856,7 @@
     DCHECK_EQ(context_.fragments.size(), 1u);
     FragmentPaintPropertyTreeBuilder builder(object_, pre_paint_info_, context_,
                                              context_.fragments[0],
-                                             pre_paint_info_->fragment_data);
+                                             *pre_paint_info_->fragment_data);
     builder.UpdateForSelf();
     property_changed = std::max(property_changed, builder.PropertyChanged());
   } else {
@@ -3861,7 +3907,7 @@
   FragmentData* fragment_data;
   if (pre_paint_info_) {
     DCHECK_EQ(context_.fragments.size(), 1u);
-    fragment_data = &pre_paint_info_->fragment_data;
+    fragment_data = pre_paint_info_->fragment_data;
     DCHECK(fragment_data);
   } else {
     fragment_data = &object_.GetMutableForPainting().FirstFragment();
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder.h b/third_party/blink/renderer/core/paint/paint_property_tree_builder.h
index cd2800f..00a8f62 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder.h
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder.h
@@ -21,7 +21,7 @@
 class LayoutObject;
 class LayoutNGTableSectionInterface;
 class LocalFrameView;
-class NGFragmentChildIterator;
+class NGPhysicalBoxFragment;
 class PaintLayer;
 class VisualViewport;
 
@@ -96,6 +96,8 @@
     // object has changed.
     bool layout_shift_root_changed = false;
 
+    bool is_in_block_fragmentation = false;
+
     // Rendering context for 3D sorting. See
     // TransformPaintPropertyNode::renderingContextId.
     unsigned rendering_context_id = 0;
@@ -123,8 +125,6 @@
   // containing block of corresponding positioned descendants.  Overflow clips
   // are also inherited by containing block tree instead of DOM tree, thus they
   // are included in the additional context too.
-  //
-  // Note that these contexts are not used in LayoutNGFragmentTraversal.
   ContainingBlockContext absolute_position;
 
   ContainingBlockContext fixed_position;
@@ -156,6 +156,13 @@
 
   PhysicalOffset old_paint_offset;
 
+  // Paint offset at the current innermost fragmentainer.
+  PhysicalOffset fragmentainer_paint_offset;
+
+  // Amount of adjustment done by UpdateForPaintOffsetTranslation() since we
+  // entered the innermost fragmentainer.
+  PhysicalOffset adjustment_for_oof_in_fragmentainer;
+
   // An additional offset that applies to the current fragment, but is detected
   // *before* the ContainingBlockContext is updated for it. Once the
   // ContainingBlockContext is set, this value should be added to
@@ -177,7 +184,6 @@
 
   Vector<PaintPropertyTreeBuilderFragmentContext, 1> fragments;
 
-  // TODO(mstensho): Stop using these in LayoutNGFragmentTraversal.
   const LayoutObject* container_for_absolute_position = nullptr;
   const LayoutObject* container_for_fixed_position = nullptr;
 
@@ -262,12 +268,41 @@
   STACK_ALLOCATED();
 
  public:
-  NGPrePaintInfo(const NGFragmentChildIterator& iterator,
-                 FragmentData& fragment_data)
-      : iterator(iterator), fragment_data(fragment_data) {}
+  NGPrePaintInfo(const NGPhysicalBoxFragment& box_fragment,
+                 PhysicalOffset paint_offset,
+                 wtf_size_t fragmentainer_idx,
+                 bool is_first_for_node,
+                 bool is_last_for_node,
+                 bool is_inside_orphaned_object,
+                 bool is_inside_fragment_child)
+      : box_fragment(box_fragment),
+        paint_offset(paint_offset),
+        fragmentainer_idx(fragmentainer_idx),
+        is_first_for_node(is_first_for_node),
+        is_last_for_node(is_last_for_node),
+        is_inside_orphaned_object(is_inside_orphaned_object),
+        is_inside_fragment_child(is_inside_fragment_child) {}
 
-  const NGFragmentChildIterator& iterator;
-  FragmentData& fragment_data;
+  // The fragment for the LayoutObject currently being processed, or, in the
+  // case of text and non-atomic inlines: the fragment of the containing block.
+  const NGPhysicalBoxFragment& box_fragment;
+
+  FragmentData* fragment_data = nullptr;
+  PhysicalOffset paint_offset;
+  wtf_size_t fragmentainer_idx;
+  bool is_first_for_node;
+  bool is_last_for_node;
+
+  // True if we're fragment-traversing an object (OOF or float) directly,
+  // instead of walking the layout object tree. In this case, the property /
+  // invalidation context chains will be missing ancestors between the
+  // fragmentainer and the OOF / float.
+  bool is_inside_orphaned_object;
+
+  // True if |box_fragment| is the containing block of the LayoutObject
+  // currently being processed. Otherwise, |box_fragment| is a fragment for the
+  // LayoutObject itself.
+  bool is_inside_fragment_child;
 };
 
 // Creates paint property tree nodes for non-local effects in the layout tree.
diff --git a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
index cd331950..4c573771 100644
--- a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
+++ b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
@@ -16,13 +16,11 @@
 #include "third_party/blink/renderer/core/frame/visual_viewport.h"
 #include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
 #include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
-#include "third_party/blink/renderer/core/layout/layout_fieldset.h"
-#include "third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h"
+#include "third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h"
 #include "third_party/blink/renderer/core/layout/layout_shift_tracker.h"
 #include "third_party/blink/renderer/core/layout/layout_view.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
 #include "third_party/blink/renderer/core/page/chrome_client.h"
@@ -37,114 +35,6 @@
 
 namespace blink {
 
-namespace {
-
-// Locate or/and set up the current FragmentData object. This may involve
-// creating it, or resetting an existing one. If |allow_reset| is set, we're
-// allowed to clear old FragmentData objects.
-NGPrePaintInfo SetupFragmentData(const NGFragmentChildIterator& iterator,
-                                 bool allow_reset) {
-  // TODO(crbug.com/1043787): What's here is mostly gross, and we need to come
-  // up with something better. The way FragmentData works (and is stored)
-  // vs. the way NGPhysicalFragment works is less than ideal.
-  //
-  // There's essentially a 1:1 correspondence between a block-level
-  // NGPhysicalBoxFragment and FragmentData, but there's no direct link between
-  // them, so we have to do some work. In the future we might want to make
-  // FragmentData part of NGPhysicalBoxFragment objects, to simplify this, and
-  // to get rid of O(n^2) performance complexity (where n is the number of
-  // fragments generated by a node). Note that this performance complexity also
-  // exists in the legacy engine.
-  //
-  // For inline-level nodes, it gets a bit more complicated. There's one
-  // FragmentData object per fragmentainer said node occurs in. The offset and
-  // invalidation rectangle in each FragmentData will be a union of all the
-  // fragments generated by the node (one per line box, typically) in that
-  // fragmentainer. This also matches how we do it in legacy layout. It's
-  // considered too expensive to have one FragmentData object per line for each
-  // text node or non-atomic inline.
-  DCHECK(iterator->GetLayoutObject());
-  const LayoutObject& object = *iterator->GetLayoutObject();
-  FragmentData* fragment_data = &object.GetMutableForPainting().FirstFragment();
-  const auto* incoming_break_token = iterator->BlockBreakToken();
-  const NGPhysicalBoxFragment* box_fragment = iterator->BoxFragment();
-
-  // The need for paint properties is the same across all fragments, so if the
-  // first FragmentData needs it, so do all the others.
-  bool needs_paint_properties = fragment_data->PaintProperties();
-
-  if (const NGFragmentItem* fragment_item = iterator->FragmentItem()) {
-    // We're in an inline formatting context. The consumed block-size stored in
-    // the incoming break token will be stored in FragmentData objects to
-    // identify each portion for a given fragmentainer.
-    LayoutUnit consumed_block_size;
-    if (incoming_break_token)
-      consumed_block_size = incoming_break_token->ConsumedBlockSize();
-    if (fragment_item->IsFirstForNode()) {
-      // This is the first fragment generated for the node (i.e. we're on the
-      // first line and first fragmentainer (column) that this node occurs
-      // in). Now is our chance to reset everything (the number or size of
-      // fragments may have changed since last time). All the other fragments
-      // will be visited in due course.
-      if (allow_reset && !object.IsBox()) {
-        // For text and non-atomic inlines, we now remove additional
-        // FragmentData objects, and reset the visual rect. The visual rect will
-        // be set and expanded, as we visit each individual fragment.
-        fragment_data->ClearNextFragment();
-      }
-      fragment_data->SetLogicalTopInFlowThread(consumed_block_size);
-    } else {
-      // This is not the first fragment. Now see if we can find a FragmentData
-      // with the right consumed block-size (or flow thread logical top). If
-      // not, we'll have to create one now.
-      while (consumed_block_size > fragment_data->LogicalTopInFlowThread()) {
-        FragmentData* next_fragment_data = fragment_data->NextFragment();
-        if (!next_fragment_data) {
-          fragment_data = &fragment_data->EnsureNextFragment();
-          fragment_data->SetLogicalTopInFlowThread(consumed_block_size);
-          break;
-        }
-        fragment_data = next_fragment_data;
-      }
-      DCHECK_EQ(fragment_data->LogicalTopInFlowThread(), consumed_block_size);
-    }
-  } else {
-    // The fragment is block-level.
-    if (IsResumingLayout(incoming_break_token)) {
-      // This isn't the first fragment for the node. We now need to walk past
-      // all preceding fragments to figure out which FragmentData to return (or
-      // create, if it doesn't already exist).
-      const auto& layout_box = To<LayoutBox>(object);
-      for (wtf_size_t idx = 0;; idx++) {
-        DCHECK_LT(idx, layout_box.PhysicalFragmentCount());
-        if (layout_box.GetPhysicalFragment(idx) == box_fragment)
-          break;
-        FragmentData* next = fragment_data->NextFragment();
-        if (!next) {
-          DCHECK_EQ(layout_box.GetPhysicalFragment(idx + 1), box_fragment);
-          fragment_data = &fragment_data->EnsureNextFragment();
-          break;
-        }
-        fragment_data = next;
-      }
-      fragment_data->SetLogicalTopInFlowThread(
-          incoming_break_token->ConsumedBlockSize());
-    }
-    if (!box_fragment->BreakToken()) {
-      // We have reached the end. There may be more data entries that were
-      // needed in the previous layout, but not any more. Clear them.
-      fragment_data->ClearNextFragment();
-    }
-  }
-
-  if (needs_paint_properties)
-    fragment_data->EnsurePaintProperties();
-
-  return NGPrePaintInfo(iterator, *fragment_data);
-}
-
-}  // anonymous namespace
-
 static void SetNeedsCompositingLayerPropertyUpdate(const LayoutObject& object) {
   if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
     return;
@@ -254,6 +144,12 @@
   PrePaintTreeWalkContext context(parent_context,
                                   needs_tree_builder_context_update);
 
+  // Block fragmentation doesn't cross frame boundaries.
+  context.current_fragmentainer = {};
+  context.absolute_positioned_container = {};
+  context.fixed_positioned_container = {};
+  context.oof_container_candidate_fragment = nullptr;
+
   // ancestor_scroll_container_paint_layer does not cross frame boundaries.
   context.ancestor_scroll_container_paint_layer = nullptr;
   if (context.tree_builder_context) {
@@ -277,7 +173,7 @@
     is_wheel_event_regions_enabled_ =
         base::FeatureList::IsEnabled(::features::kWheelEventRegions);
 
-    Walk(*view, context, /* iterator */ nullptr);
+    Walk(*view, context, /* pre_paint_info */ nullptr);
 #if DCHECK_IS_ON()
     view->AssertSubtreeClearedPaintInvalidationFlags();
 #endif
@@ -425,8 +321,14 @@
   }
 
   return frame_view.GetLayoutView() &&
-         (ObjectRequiresTreeBuilderContext(*frame_view.GetLayoutView()) ||
-          ContextRequiresChildTreeBuilderContext(context));
+         NeedsTreeBuilderContextUpdate(*frame_view.GetLayoutView(), context);
+}
+
+bool PrePaintTreeWalk::NeedsTreeBuilderContextUpdate(
+    const LayoutObject& object,
+    const PrePaintTreeWalkContext& parent_context) {
+  return ContextRequiresChildTreeBuilderContext(parent_context) ||
+         ObjectRequiresTreeBuilderContext(object);
 }
 
 bool PrePaintTreeWalk::ObjectRequiresPrePaint(const LayoutObject& object) {
@@ -545,18 +447,108 @@
   }
 }
 
+NGPrePaintInfo PrePaintTreeWalk::CreatePrePaintInfo(
+    const NGLink& child,
+    const PrePaintTreeWalkContext& context) {
+  const auto& fragment = *To<NGPhysicalBoxFragment>(child.fragment);
+  return NGPrePaintInfo(fragment, child.offset,
+                        context.current_fragmentainer.fragmentainer_idx,
+                        fragment.IsFirstForNode(), !fragment.BreakToken(),
+                        context.is_inside_orphaned_object,
+                        /* is_inside_fragment_child */ false);
+}
+
+FragmentData* PrePaintTreeWalk::GetOrCreateFragmentData(
+    const LayoutObject& object,
+    const PrePaintTreeWalkContext& context,
+    const NGPrePaintInfo& pre_paint_info) {
+  // If |allow_update| is set, we're allowed to add, remove and modify
+  // FragmentData objects. Otherwise they will be left alone.
+  bool allow_update = context.NeedsTreeBuilderContext();
+
+  FragmentData* fragment_data = &object.GetMutableForPainting().FirstFragment();
+
+  // The need for paint properties is the same across all fragments, so if the
+  // first FragmentData needs it, so do all the others.
+  bool needs_paint_properties = fragment_data->PaintProperties();
+
+  wtf_size_t fragment_id = pre_paint_info.fragmentainer_idx;
+  // TODO(mstensho): For now we need to treat unfragmented as ID 0. It doesn't
+  // really matter for LayoutNG, but legacy
+  // PaintPropertyTreeBuilder::ContextForFragment() may take a walk up the tree
+  // and end up querying this (LayoutNG) object, and
+  // FragmentData::LogicalTopInFlowThread() will DCHECK that the value is 0
+  // unless it has been explicitly set by legacy code (which won't happen, since
+  // it's an NG object).
+  if (fragment_id == WTF::kNotFound)
+    fragment_id = 0;
+
+  if (pre_paint_info.is_first_for_node) {
+    if (allow_update)
+      fragment_data->ClearNextFragment();
+    else
+      DCHECK_EQ(fragment_data->FragmentID(), fragment_id);
+  } else {
+    FragmentData* last_fragment = nullptr;
+    do {
+      if (fragment_data->FragmentID() >= fragment_id)
+        break;
+      last_fragment = fragment_data;
+      fragment_data = fragment_data->NextFragment();
+    } while (fragment_data);
+    if (fragment_data) {
+      if (pre_paint_info.is_last_for_node) {
+        // We have reached the end. There may be more data entries that were
+        // needed in the previous layout, but not any more. Clear them.
+        if (allow_update)
+          fragment_data->ClearNextFragment();
+        else
+          DCHECK(!fragment_data->NextFragment());
+      } else if (fragment_data->FragmentID() != fragment_id) {
+        // There are entries for fragmentainers after this one, but none for
+        // this one. Remove the fragment tail.
+        DCHECK(allow_update);
+        DCHECK_GT(fragment_data->FragmentID(), fragment_id);
+        fragment_data->ClearNextFragment();
+      }
+    } else {
+      DCHECK(allow_update);
+      fragment_data = &last_fragment->EnsureNextFragment();
+    }
+  }
+
+  if (allow_update) {
+    fragment_data->SetFragmentID(fragment_id);
+
+    if (needs_paint_properties)
+      fragment_data->EnsurePaintProperties();
+  } else {
+    DCHECK_EQ(fragment_data->FragmentID(), fragment_id);
+    DCHECK(!needs_paint_properties || fragment_data->PaintProperties());
+  }
+
+  return fragment_data;
+}
+
 void PrePaintTreeWalk::WalkInternal(const LayoutObject& object,
                                     PrePaintTreeWalkContext& context,
-                                    const NGFragmentChildIterator* iterator) {
+                                    NGPrePaintInfo* pre_paint_info) {
   PaintInvalidatorContext& paint_invalidator_context =
       context.paint_invalidator_context;
 
-  absl::optional<NGPrePaintInfo> pre_paint_info_storage;
-  NGPrePaintInfo* pre_paint_info = nullptr;
-  if (iterator) {
-    bool allow_reset = context.NeedsTreeBuilderContext();
-    pre_paint_info_storage.emplace(SetupFragmentData(*iterator, allow_reset));
-    pre_paint_info = &pre_paint_info_storage.value();
+  if (pre_paint_info) {
+    DCHECK(!pre_paint_info->fragment_data);
+    // Find, update or create a FragmentData object to match the current block
+    // fragment.
+    //
+    // TODO(mstensho): If this is collapsed text or a culled inline, we might
+    // not have any work to do (we could just return early here), as there'll be
+    // no need for paint property updates or invalidation. However, this is a
+    // bit tricky to determine, because of things like LinkHighlight, which
+    // might set paint properties on a culled inline.
+    pre_paint_info->fragment_data =
+        GetOrCreateFragmentData(object, context, *pre_paint_info);
+    DCHECK(pre_paint_info->fragment_data);
   }
 
   // This must happen before updatePropertiesForSelf, because the latter reads
@@ -674,6 +666,70 @@
   }
 }
 
+bool PrePaintTreeWalk::CollectMissableChildren(
+    PrePaintTreeWalkContext& context,
+    const NGPhysicalBoxFragment& parent) {
+  bool has_missable_children = false;
+  for (const NGLink& child : parent.Children()) {
+    if ((child->IsOutOfFlowPositioned() &&
+         (context.current_fragmentainer.fragment ||
+          child->IsFixedPositioned())) ||
+        (child->IsFloating() && parent.IsInlineFormattingContext() &&
+         context.current_fragmentainer.fragment)) {
+      // We'll add resumed floats (or floats that couldn't fit a fragment in the
+      // fragmentainer where it was discovered) that have escaped their inline
+      // formatting context.
+      //
+      // We'll also add all out-of-flow positioned fragments inside a
+      // fragmentation context. If a fragment is fixed-positioned, we even need
+      // to add those that aren't inside a fragmentation context, because they
+      // may have an ancestor LayoutObject inside one, and one of those
+      // ancestors may be out-of-flow positioned, which may be missed, in which
+      // case we'll miss this fixed-positioned one as well (since we don't enter
+      // descendant OOFs when walking missed children) (example: fixedpos inside
+      // missed abspos in relpos in multicol).
+      pending_missables_.insert(child.fragment);
+      has_missable_children = true;
+    }
+  }
+  return has_missable_children;
+}
+
+void PrePaintTreeWalk::WalkMissedChildren(const NGPhysicalBoxFragment& fragment,
+                                          PrePaintTreeWalkContext& context) {
+  if (pending_missables_.IsEmpty())
+    return;
+
+  for (const NGLink& child : fragment.Children()) {
+    if (!child->IsOutOfFlowPositioned() && !child->IsFloating())
+      continue;
+    if (!pending_missables_.Contains(child.fragment))
+      continue;
+    const LayoutObject& descendant_object = *child->GetLayoutObject();
+    PrePaintTreeWalkContext descendant_context(
+        context, NeedsTreeBuilderContextUpdate(descendant_object, context));
+    if (child->IsOutOfFlowPositioned() &&
+        descendant_context.tree_builder_context) {
+      PaintPropertyTreeBuilderFragmentContext& fragment_context =
+          descendant_context.tree_builder_context->fragments[0];
+      // Reset the relevant OOF context to this fragmentainer, since this is its
+      // containing block, as far as the NG fragment structure is concerned.
+      // Note that when walking a missed child OOF fragment, we'll also
+      // forcefully miss any OOF descendant nodes, which is why we only set the
+      // context for the OOF type we're dealing with here.
+      if (child->IsFixedPositioned())
+        fragment_context.fixed_position = fragment_context.current;
+      else
+        fragment_context.absolute_position = fragment_context.current;
+    }
+    descendant_context.is_inside_orphaned_object = true;
+
+    NGPrePaintInfo pre_paint_info =
+        CreatePrePaintInfo(child, descendant_context);
+    Walk(descendant_object, descendant_context, &pre_paint_info);
+  }
+}
+
 LocalFrameView* FindWebViewPluginContentFrameView(
     const LayoutEmbeddedContent& embedded_content) {
   for (Frame* frame = embedded_content.GetFrame()->Tree().FirstChild(); frame;
@@ -685,92 +741,133 @@
   return nullptr;
 }
 
-void PrePaintTreeWalk::WalkNGChildren(const LayoutObject* parent,
-                                      PrePaintTreeWalkContext& parent_context,
-                                      NGFragmentChildIterator* iterator) {
+void PrePaintTreeWalk::WalkFragmentationContextRootChildren(
+    const LayoutObject& object,
+    const NGPhysicalBoxFragment& fragment,
+    PrePaintTreeWalkContext& context) {
+  // The actual children are inside the flow thread child of |object|.
+  const auto* flow_thread =
+      To<LayoutBlockFlow>(&object)->MultiColumnFlowThread();
+  const LayoutObject& actual_parent = flow_thread ? *flow_thread : object;
+
   FragmentData* fragmentainer_fragment_data = nullptr;
 #if DCHECK_IS_ON()
   const LayoutObject* fragmentainer_owner_box = nullptr;
 #endif
-  for (; !iterator->IsAtEnd(); iterator->Advance()) {
-    const LayoutObject* object = (*iterator)->GetLayoutObject();
-    if (const auto* fragment_item = (*iterator)->FragmentItem()) {
-      // Line boxes are not interesting. They have no paint effects. Descend
-      // directly into children.
-      if (fragment_item->Type() == NGFragmentItem::kLine) {
-        WalkChildren(/* parent */ nullptr, parent_context, iterator);
-        continue;
-      }
-    } else if (!object) {
-      const NGPhysicalBoxFragment* box_fragment = (*iterator)->BoxFragment();
-      if (UNLIKELY(box_fragment->IsLayoutObjectDestroyedOrMoved()))
+
+  DCHECK(fragment.IsFragmentationContextRoot());
+
+  const auto outer_fragmentainer = context.current_fragmentainer;
+  absl::optional<wtf_size_t> inner_fragmentainer_idx;
+
+  for (NGLink child : fragment.Children()) {
+    const auto* box_fragment = To<NGPhysicalBoxFragment>(child.fragment);
+    if (UNLIKELY(box_fragment->IsLayoutObjectDestroyedOrMoved()))
+      continue;
+
+    if (box_fragment->GetLayoutObject()) {
+      // OOFs contained by a multicol container will be visited during object
+      // tree traversal.
+      if (box_fragment->IsOutOfFlowPositioned())
         continue;
 
-      // Check |box_fragment| and the |LayoutBox| that produced it are in sync.
-      // |OwnerLayoutBox()| has a few DCHECKs for this purpose.
-      DCHECK(box_fragment->OwnerLayoutBox());
+      // We'll walk all other non-fragmentainer children directly now, entering
+      // them from the fragment tree, rather than from the LayoutObject tree.
+      // One consequence of this is that paint effects on any ancestors between
+      // a column spanner and its multicol container will not be applied on the
+      // spanner. This is fixable, but it would require non-trivial amounts of
+      // special-code for such a special case. If anyone complains, we can
+      // revisit this decision.
+      if (box_fragment->IsColumnSpanAll())
+        context.current_fragmentainer = outer_fragmentainer;
 
-      // A fragmentainer doesn't paint anything itself. Just include its offset
-      // and descend into children.
-      DCHECK((*iterator)->BoxFragment()->IsFragmentainerBox());
-      if (UNLIKELY(!parent_context.tree_builder_context)) {
-        WalkChildren(/* parent */ nullptr, parent_context, iterator);
-        continue;
-      }
-
-      PaintPropertyTreeBuilderContext& tree_builder_context =
-          *parent_context.tree_builder_context;
-      PaintPropertyTreeBuilderFragmentContext& context =
-          tree_builder_context.fragments[0];
-      PaintPropertyTreeBuilderFragmentContext::ContainingBlockContext*
-          containing_block_context = &context.current;
-      const PhysicalOffset offset = (*iterator)->Link().offset;
-      containing_block_context->paint_offset += offset;
-      const PhysicalOffset paint_offset =
-          containing_block_context->paint_offset;
-
-      // Create corresponding |FragmentData|. Hit-testing needs
-      // |FragmentData.PaintOffset|.
-      if (fragmentainer_fragment_data) {
-        DCHECK(!box_fragment->IsFirstForNode());
-#if DCHECK_IS_ON()
-        DCHECK_EQ(fragmentainer_owner_box, box_fragment->OwnerLayoutBox());
-#endif
-        fragmentainer_fragment_data =
-            &fragmentainer_fragment_data->EnsureNextFragment();
-      } else {
-        const LayoutBox* owner_box = box_fragment->OwnerLayoutBox();
-#if DCHECK_IS_ON()
-        DCHECK(!fragmentainer_owner_box);
-        fragmentainer_owner_box = owner_box;
-#endif
-        fragmentainer_fragment_data =
-            &owner_box->GetMutableForPainting().FirstFragment();
-        if (box_fragment->IsFirstForNode()) {
-          fragmentainer_fragment_data->ClearNextFragment();
-        } else {
-          // |box_fragment| is nested in another fragmentainer, and that it is
-          // the first one in this loop, but not the first one for the
-          // |LayoutObject|. Append a new |FragmentData| to the last one.
-          fragmentainer_fragment_data =
-              &fragmentainer_fragment_data->LastFragment().EnsureNextFragment();
-        }
-      }
-      fragmentainer_fragment_data->SetPaintOffset(paint_offset);
-
-      WalkChildren(/* parent */ nullptr, parent_context, iterator);
-      containing_block_context->paint_offset -= offset;
+      NGPrePaintInfo pre_paint_info = CreatePrePaintInfo(child, context);
+      Walk(*box_fragment->GetLayoutObject(), context, &pre_paint_info);
       continue;
     }
-    Walk(*object, parent_context, iterator);
+
+    // Check |box_fragment| and the |LayoutBox| that produced it are in sync.
+    // |OwnerLayoutBox()| has a few DCHECKs for this purpose.
+    DCHECK(box_fragment->OwnerLayoutBox());
+
+    // A fragmentainer doesn't paint anything itself. Just include its offset
+    // and descend into children.
+    DCHECK(box_fragment->IsFragmentainerBox());
+
+    // Always keep track of the current innermost fragmentainer we're handling,
+    // as they may serve as containing blocks for OOF descendants.
+    context.current_fragmentainer.fragment = box_fragment;
+
+    // Set up |inner_fragmentainer_idx| lazily, as it's O(n) (n == number of
+    // multicol container fragments).
+    if (!inner_fragmentainer_idx)
+      inner_fragmentainer_idx = PreviousInnerFragmentainerIndex(fragment);
+    context.current_fragmentainer.fragmentainer_idx = *inner_fragmentainer_idx;
+
+    if (UNLIKELY(!context.tree_builder_context)) {
+      WalkChildren(actual_parent, box_fragment, context);
+      continue;
+    }
+
+    PaintPropertyTreeBuilderContext& tree_builder_context =
+        *context.tree_builder_context;
+    PaintPropertyTreeBuilderFragmentContext& fragment_context =
+        tree_builder_context.fragments[0];
+    PaintPropertyTreeBuilderFragmentContext::ContainingBlockContext*
+        containing_block_context = &fragment_context.current;
+    containing_block_context->paint_offset += child.offset;
+
+    const PhysicalOffset paint_offset = containing_block_context->paint_offset;
+    // Keep track of the paint offset at the fragmentainer, and also reset the
+    // offset adjustment tracker. This is needed when entering OOF
+    // descendants. OOFs have the nearest fragmentainer as their containing
+    // block, so when entering them during LayoutObject tree traversal, we have
+    // to compensate for this.
+    fragment_context.fragmentainer_paint_offset = paint_offset;
+    fragment_context.adjustment_for_oof_in_fragmentainer = PhysicalOffset();
+
+    // Create corresponding |FragmentData|. Hit-testing needs
+    // |FragmentData.PaintOffset|.
+    if (fragmentainer_fragment_data) {
+      DCHECK(!box_fragment->IsFirstForNode());
+#if DCHECK_IS_ON()
+      DCHECK_EQ(fragmentainer_owner_box, box_fragment->OwnerLayoutBox());
+#endif
+      fragmentainer_fragment_data =
+          &fragmentainer_fragment_data->EnsureNextFragment();
+    } else {
+      const LayoutBox* owner_box = box_fragment->OwnerLayoutBox();
+#if DCHECK_IS_ON()
+      DCHECK(!fragmentainer_owner_box);
+      fragmentainer_owner_box = owner_box;
+#endif
+      fragmentainer_fragment_data =
+          &owner_box->GetMutableForPainting().FirstFragment();
+      if (box_fragment->IsFirstForNode()) {
+        fragmentainer_fragment_data->ClearNextFragment();
+      } else {
+        // |box_fragment| is nested in another fragmentainer, and that it is
+        // the first one in this loop, but not the first one for the
+        // |LayoutObject|. Append a new |FragmentData| to the last one.
+        fragmentainer_fragment_data =
+            &fragmentainer_fragment_data->LastFragment().EnsureNextFragment();
+      }
+    }
+    fragmentainer_fragment_data->SetPaintOffset(paint_offset);
+
+    WalkChildren(actual_parent, box_fragment, context);
+
+    containing_block_context->paint_offset -= child.offset;
+    (*inner_fragmentainer_idx)++;
   }
 
-  const LayoutBlockFlow* parent_block = DynamicTo<LayoutBlockFlow>(parent);
-  if (!parent_block || !parent_block->MultiColumnFlowThread())
+  if (!flow_thread)
     return;
   // Multicol containers only contain special legacy children invisible to
   // LayoutNG, so we need to clean them manually.
-  for (const LayoutObject* child = parent->SlowFirstChild(); child;
+  if (fragment.BreakToken())
+    return;  // Wait until we've reached the end.
+  for (const LayoutObject* child = object.SlowFirstChild(); child;
        child = child->NextSibling()) {
     DCHECK(child->IsLayoutFlowThread() || child->IsLayoutMultiColumnSet() ||
            child->IsLayoutMultiColumnSpannerPlaceholder());
@@ -778,139 +875,287 @@
   }
 }
 
-void PrePaintTreeWalk::WalkLegacyChildren(const LayoutObject& object,
-                                          PrePaintTreeWalkContext& context) {
-  if (const auto* layout_box = DynamicTo<LayoutBox>(&object)) {
-    if (layout_box->CanTraversePhysicalFragments()) {
-      // Enter NG child fragment traversal. We'll stay in this mode for all
-      // descendants that support fragment traversal. We'll re-enter
-      // LayoutObject traversal for descendants that don't support it. This only
-      // works correctly if we're not block-fragmented, though, so DCHECK for
-      // that.
-      DCHECK_EQ(layout_box->PhysicalFragmentCount(), 1u);
-      const NGPhysicalBoxFragment& fragment =
-          To<NGPhysicalBoxFragment>(*layout_box->GetPhysicalFragment(0));
-      DCHECK(!fragment.BreakToken());
-      NGFragmentChildIterator child_iterator(fragment);
-      WalkNGChildren(&object, context, &child_iterator);
-      return;
-    }
-  }
-
-  for (const LayoutObject* child = object.SlowFirstChild(); child;
+void PrePaintTreeWalk::WalkLayoutObjectChildren(
+    const LayoutObject& parent_object,
+    const NGPhysicalBoxFragment* parent_fragment,
+    PrePaintTreeWalkContext& context) {
+  for (const LayoutObject* child = parent_object.SlowFirstChild(); child;
        child = child->NextSibling()) {
-    if (child->IsLayoutMultiColumnSpannerPlaceholder()) {
-      child->GetMutableForPainting().ClearPaintFlags();
+    if (!parent_fragment) {
+      // If we haven't found a fragment tree to accompany us in our walk,
+      // perform a pure LayoutObject tree walk. This is needed for legacy block
+      // fragmentation, and it also works fine if there's no block fragmentation
+      // involved at all (in such cases we can either to do this, or perform the
+      // NGPhysicalBoxFragment-accompanied walk that we do further down).
+
+      if (child->IsLayoutMultiColumnSpannerPlaceholder()) {
+        child->GetMutableForPainting().ClearPaintFlags();
+        continue;
+      }
+
+      Walk(*child, context, /* pre_paint_info */ nullptr);
       continue;
     }
-    // Skip out-of-flow positioned children lest they be walked twice. If |this|
-    // is an NG object, but it still walks its children the legacy way (this may
-    // happen to table-cells; see LayoutObject::CanTraversePhysicalFragments()),
-    // we're either going to handle it in the code below after the loop - if
-    // |this| is actually the containing block. Otherwise it will be handled by
-    // some ancestor - either in the same code below (if it's a legacy-walking
-    // object) or via regular child fragment traversal. If we walk it here as
-    // well, we'd end up walking it twice. This is both bad for performance, and
-    // also correctness, as fragment items are sensitive to how they're walked
-    // (see SetupFragmentData()).
-    if (UNLIKELY(RuntimeEnabledFeatures::LayoutNGFragmentTraversalEnabled() &&
-                 child->IsOutOfFlowPositioned() && object.IsLayoutNGObject()))
+
+    // If we're in the middle of walking a missed OOF, don't enter nested OOFs
+    // (but miss those as well, and handle them via fragment traversal).
+    if (context.is_inside_orphaned_object && child->IsOutOfFlowPositioned())
       continue;
 
-    Walk(*child, context, /* iterator */ nullptr);
-  }
+    // Perform an NGPhysicalBoxFragment-accompanied walk of the child
+    // LayoutObject tree.
+    //
+    // We'll map each child LayoutObject to a corresponding
+    // NGPhysicalBoxFragment. For text and non-atomic inlines this will be the
+    // fragment of their containing block, while for all other objects, it will
+    // be a fragment generated by the object itself. Even when we have LayoutNG
+    // fragments, we'll try to do the pre-paint walk it in LayoutObject tree
+    // order. This will ensure that paint properties are applied correctly (the
+    // LayoutNG fragment tree follows the containing block structure closely,
+    // but for paint effects, it's actually the LayoutObject / DOM tree
+    // structure that matters, e.g. when there's a relpos with a child with
+    // opacity, which has an absolutely positioned child, the absolutely
+    // positioned child should be affected by opacity, even if the object that
+    // establishes the opacity layer isn't in the containing block
+    // chain). Furthermore, culled inlines have no fragments, but they still
+    // need to be visited, since the invalidation code marks them for pre-paint.
+    const NGPhysicalBoxFragment* box_fragment = nullptr;
+    wtf_size_t fragmentainer_idx =
+        context.current_fragmentainer.fragmentainer_idx;
+    PhysicalOffset paint_offset;
+    const auto* child_box = DynamicTo<LayoutBox>(child);
+    bool is_first_for_node = true;
+    bool is_last_for_node = true;
+    bool is_inside_fragment_child = false;
+    if (parent_fragment->Items() && child->FirstInlineFragmentItemIndex()) {
+      for (const NGFragmentItem& item : parent_fragment->Items()->Items()) {
+        if (item.GetLayoutObject() != child)
+          continue;
 
-  if (!RuntimeEnabledFeatures::LayoutNGFragmentTraversalEnabled())
-    return;
+        is_last_for_node = item.IsLastForNode();
+        if (box_fragment) {
+          if (is_last_for_node)
+            break;
+          continue;
+        }
 
-  const LayoutBlock* block = DynamicTo<LayoutBlock>(&object);
-  if (!block)
-    return;
-  const auto* positioned_objects = block->PositionedObjects();
-  if (!positioned_objects)
-    return;
+        paint_offset = item.OffsetInContainerFragment();
+        is_first_for_node = item.IsFirstForNode();
 
-  // If we have performed NG fragment traversal in any part of the subtree, we
-  // may have missed certain out-of-flow positioned objects. LayoutNG fragments
-  // are always children of their containing block, while the structure of the
-  // LayoutObject tree corresponds more closely to that of the DOM tree.
-  //
-  // Example: if we assume that flexbox isn't natively supported in LayoutNG:
-  //
-  // <div id="flex" style="display:flex; position:relative;">
-  //   <div id="flexitem">
-  //     <div id="abs" style="position:absolute;"></div>
-  //     <div id="regular"></div>
-  //
-  // If we let |object| be #flex, it will be handled by legacy LayoutObject
-  // traversal, while #flexitem, on the other hand, can traverse its NG child
-  // fragments. However, #regular will be the only child fragment of #flexitem,
-  // since the containing block for #abs is #flex. So we'd miss it, unless we
-  // walk it now.
-  for (const LayoutBox* box : *positioned_objects) {
-    // It's important that objects that have already been walked be left alone.
-    // Otherwise, we might calculate the wrong offsets (and overwrite the
-    // correct ones) in case of out-of-flow positioned objects whose containing
-    // block is a relatively positioned non-atomic inline (such objects will
-    // already have been properly walked, since we don't switch engines within
-    // an inline formatting context). Put differently, the code here will only
-    // do the right thing if |object| is truly the containing block of the
-    // positioned objects in its list (which isn't the case if the containing
-    // block is a non-atomic inline).
-    if (!ObjectRequiresPrePaint(*box) &&
-        !ObjectRequiresTreeBuilderContext(*box))
-      continue;
-    DCHECK_EQ(box->Container(), &object);
-    Walk(*box, context, /* iterator */ nullptr);
+        if (item.BoxFragment() && !item.BoxFragment()->IsInlineBox()) {
+          box_fragment = item.BoxFragment();
+          is_last_for_node = !box_fragment->BreakToken();
+          break;
+        } else {
+          // Inlines will pass their containing block fragment (and its incoming
+          // break token).
+          box_fragment = parent_fragment;
+          is_inside_fragment_child = true;
+        }
+
+        if (is_last_for_node)
+          break;
+
+        // Keep looking for the end. We need to know whether this is the last
+        // time we're going to visit this object.
+      }
+      if (!box_fragment)
+        continue;
+    } else if (child->IsInline() && !child_box) {
+      // Deal with inline-level objects not searched for above.
+      //
+      // Needed for fragment-less objects that have children. This is the case
+      // for culled inlines. We're going to have to enter them for every
+      // fragment in the parent.
+      //
+      // The child is inline-level even if the parent fragment doesn't establish
+      // an inline formatting context. This may happen if there's only collapsed
+      // text, or if we had to insert a break in a block before we got to any
+      // inline content. Make sure that we visit such objects once.
+
+      // Inlines will pass their containing block fragment (and its incoming
+      // break token).
+      box_fragment = parent_fragment;
+      is_inside_fragment_child = true;
+
+      is_first_for_node = parent_fragment->IsFirstForNode();
+      is_last_for_node = !parent_fragment->BreakToken();
+    } else if (child_box && child_box->PhysicalFragmentCount()) {
+      // Figure out which fragment the child may be found inside. The fragment
+      // tree follows the structure of containing blocks closely, while here
+      // we're walking the LayoutObject tree (which follows the structure of the
+      // flat DOM tree, more or less). This means that for out-of-flow
+      // positioned objects, the fragment of the parent LayoutObject might not
+      // be the right place to search.
+      const NGPhysicalBoxFragment* search_fragment = parent_fragment;
+      if (child_box->IsOutOfFlowPositioned()) {
+        if (child_box->IsFixedPositioned()) {
+          search_fragment = context.fixed_positioned_container.fragment;
+          fragmentainer_idx =
+              context.fixed_positioned_container.fragmentainer_idx;
+        } else {
+          search_fragment = context.absolute_positioned_container.fragment;
+          fragmentainer_idx =
+              context.absolute_positioned_container.fragmentainer_idx;
+        }
+        if (!search_fragment) {
+          // Only walk unfragmented legacy-contained OOFs once.
+          if (context.is_inside_orphaned_object ||
+              (context.current_fragmentainer.fragment &&
+               !context.current_fragmentainer.fragment->IsFirstForNode()))
+            continue;
+        }
+      }
+
+      if (search_fragment) {
+        // See if we can find a fragment for the child.
+        for (NGLink link : search_fragment->Children()) {
+          if (link->GetLayoutObject() != child)
+            continue;
+          // We found it!
+          box_fragment = To<NGPhysicalBoxFragment>(link.get());
+          paint_offset = link.offset;
+          is_first_for_node = box_fragment->IsFirstForNode();
+          is_last_for_node = !box_fragment->BreakToken();
+          break;
+        }
+        // If we didn't find a fragment for the child, it means that the child
+        // doesn't occur inside the fragmentainer that we're currently handling.
+        if (!box_fragment)
+          continue;
+      }
+    }
+
+    if (box_fragment) {
+      NGPrePaintInfo pre_paint_info(
+          *box_fragment, paint_offset, fragmentainer_idx, is_first_for_node,
+          is_last_for_node, context.is_inside_orphaned_object,
+          is_inside_fragment_child);
+      Walk(*child, context, &pre_paint_info);
+    } else {
+      Walk(*child, context, /* pre_paint_info */ nullptr);
+    }
   }
 }
 
-void PrePaintTreeWalk::WalkChildren(const LayoutObject* object,
+void PrePaintTreeWalk::WalkChildren(const LayoutObject& object,
+                                    const NGPhysicalBoxFragment* fragment,
                                     PrePaintTreeWalkContext& context,
-                                    const NGFragmentChildIterator* iterator) {
-  DCHECK(iterator || object);
+                                    bool is_inside_fragment_child) {
+  const LayoutBox* box = DynamicTo<LayoutBox>(&object);
+  if (box) {
+    if (fragment) {
+      if (!box->IsLayoutFlowThread() && (!box->CanTraversePhysicalFragments() ||
+                                         !box->PhysicalFragmentCount())) {
+        // Leave LayoutNGBoxFragment-accompanied child LayoutObject traversal,
+        // since this object doesn't support that (or has no fragments (happens
+        // for table columns)). We need to switch back to legacy LayoutObject
+        // traversal for its children. We're then also assuming that we're
+        // either not block-fragmenting, or that this is monolithic content. We
+        // may re-enter LayoutNGBoxFragment-accompanied traversal if we get to a
+        // descendant that supports that.
+        DCHECK(
+            !box->FlowThreadContainingBlock() ||
+            (box->GetNGPaginationBreakability() == LayoutBox::kForbidBreaks));
 
-  if (!iterator) {
-    // We're not doing LayoutNG fragment traversal of this object.
-    WalkLegacyChildren(*object, context);
-    return;
+        fragment = nullptr;
+        context.oof_container_candidate_fragment = nullptr;
+      }
+    } else {
+      // There may be fragment-less objects, such as table columns or table
+      // column groups.
+      if (box->CanTraversePhysicalFragments() && box->PhysicalFragmentCount()) {
+        // Enter LayoutNGBoxFragment-accompanied child LayoutObject traversal.
+        // We'll stay in this mode for all descendants that support fragment
+        // traversal. We'll re-enter legacy traversal for descendants that don't
+        // support it. This only works correctly if we're not block-fragmented,
+        // though, so DCHECK for that.
+        //
+        // TODO(mstensho): Before shipping LayoutNGFragmentTraversal: Only enter
+        // this mode at block fragmentation roots (multicol containers), as
+        // LayoutNGBoxFragment-accompanied child LayoutObject traversal is more
+        // expensive than pure LayoutObject traversal: we need to search for
+        // each object among child fragments (NGLink) to find the offset, also
+        // when not fragmented at all. For now, though enter this mode as often
+        // as we can, for increased test coverage (when running with
+        // LayoutNGFragmentTraversal enabled).
+        DCHECK_EQ(box->PhysicalFragmentCount(), 1u);
+        fragment = To<NGPhysicalBoxFragment>(box->GetPhysicalFragment(0));
+        DCHECK(!fragment->BreakToken());
+      }
+    }
+
+    // Inline-contained OOFs are placed in the containing block of the
+    // containing inline in NG, not an anonymous block that's part of a
+    // continuation, if any. We need to know where these might be stored, so
+    // that we eventually search the right ancestor fragment for them.
+    if (fragment && !box->IsAnonymousBlock())
+      context.oof_container_candidate_fragment = fragment;
   }
 
-  // If we are performing LayoutNG fragment traversal, but this object doesn't
-  // support that, we need to switch back to legacy LayoutObject traversal for
-  // its children. We're then also assuming that we're either not
-  // block-fragmenting, or that this is monolithic content. We may re-enter
-  // LayoutNG fragment traversal if we get to a descendant that supports that.
-  if (object && !object->CanTraversePhysicalFragments()) {
-    DCHECK(!object->FlowThreadContainingBlock() ||
-           (object->IsBox() &&
-            To<LayoutBox>(object)->GetNGPaginationBreakability() ==
-                LayoutBox::kForbidBreaks));
-    WalkLegacyChildren(*object, context);
-    return;
+  // Keep track of fragments that act as containers for OOFs, so that we can
+  // search their children when looking for an OOF further down in the tree.
+  if (object.CanContainAbsolutePositionObjects()) {
+    if (context.current_fragmentainer.fragment && box &&
+        box->GetNGPaginationBreakability() == LayoutBox::kForbidBreaks) {
+      // If we're in a fragmentation context, the parent fragment of OOFs is the
+      // fragmentainer, unless the object is monolithic, in which case nothing
+      // inside the object participates in the current block fragmentation
+      // context. This means that this object (and not the nearest
+      // fragmentainer) acts as a containing block for OOF descendants,
+      context.current_fragmentainer = {};
+    }
+    // The OOF containing block structure is special under block fragmentation:
+    // A fragmentable OOF is always a direct child of a fragmentainer.
+    const auto* container_fragment = context.current_fragmentainer.fragment;
+    if (!container_fragment)
+      container_fragment = context.oof_container_candidate_fragment;
+    context.absolute_positioned_container = {
+        container_fragment, context.current_fragmentainer.fragmentainer_idx};
+    if (object.CanContainFixedPositionObjects()) {
+      context.fixed_positioned_container = {
+          container_fragment, context.current_fragmentainer.fragmentainer_idx};
+    }
   }
 
-  // Traverse child NG fragments.
-  NGFragmentChildIterator child_iterator(iterator->Descend());
-  WalkNGChildren(object, context, &child_iterator);
+  if (fragment) {
+    bool has_missable_children = false;
+    // If we are at a block fragment, collect any missable children.
+    DCHECK(!is_inside_fragment_child || !object.IsBox());
+    if (!is_inside_fragment_child)
+      has_missable_children = CollectMissableChildren(context, *fragment);
+
+    // We'll always walk the LayoutObject tree when possible, but if this is a
+    // fragmentation context root (such as a multicol container), we need to
+    // enter each fragmentainer child and then walk all the LayoutObject
+    // children.
+    if (fragment->IsFragmentationContextRoot())
+      WalkFragmentationContextRootChildren(object, *fragment, context);
+    else
+      WalkLayoutObjectChildren(object, fragment, context);
+
+    if (has_missable_children)
+      WalkMissedChildren(*fragment, context);
+  } else {
+    WalkLayoutObjectChildren(object, fragment, context);
+  }
 }
 
 void PrePaintTreeWalk::Walk(const LayoutObject& object,
                             const PrePaintTreeWalkContext& parent_context,
-                            const NGFragmentChildIterator* iterator) {
+                            NGPrePaintInfo* pre_paint_info) {
   const NGPhysicalBoxFragment* physical_fragment = nullptr;
-  bool is_last_fragment = true;
-  if (iterator) {
-    physical_fragment = (*iterator)->BoxFragment();
-    if (const auto* fragment_item = (*iterator)->FragmentItem())
-      is_last_fragment = fragment_item->IsLastForNode();
-    else if (physical_fragment)
-      is_last_fragment = !physical_fragment->BreakToken();
+  bool is_inside_fragment_child = false;
+  if (pre_paint_info) {
+    physical_fragment = &pre_paint_info->box_fragment;
+    if (physical_fragment && (physical_fragment->IsOutOfFlowPositioned() ||
+                              physical_fragment->IsFloating()))
+      pending_missables_.erase(physical_fragment);
+    is_inside_fragment_child = pre_paint_info->is_inside_fragment_child;
   }
 
   bool needs_tree_builder_context_update =
-      ContextRequiresChildTreeBuilderContext(parent_context) ||
-      ObjectRequiresTreeBuilderContext(object);
+      NeedsTreeBuilderContextUpdate(object, parent_context);
 
 #if DCHECK_IS_ON()
   CheckTreeBuilderContextState(object, parent_context);
@@ -932,7 +1177,7 @@
       context.tree_builder_context->clip_changed = false;
   }
 
-  WalkInternal(object, context, iterator);
+  WalkInternal(object, context, pre_paint_info);
 
   bool child_walk_blocked = object.ChildPrePaintBlockedByDisplayLock();
   // If we need a subtree walk due to context flags, we need to store that
@@ -952,7 +1197,7 @@
   }
 
   if (!child_walk_blocked) {
-    WalkChildren(&object, context, iterator);
+    WalkChildren(object, physical_fragment, context, is_inside_fragment_child);
 
     if (const auto* layout_embedded_content =
             DynamicTo<LayoutEmbeddedContent>(object)) {
@@ -981,7 +1226,7 @@
       }
     }
   }
-  if (is_last_fragment)
+  if (!pre_paint_info || pre_paint_info->is_last_for_node)
     object.GetMutableForPainting().ClearPaintFlags();
 }
 
diff --git a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.h b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.h
index 5ea8502..a311b0e4 100644
--- a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.h
+++ b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.h
@@ -10,12 +10,15 @@
 #include "third_party/blink/renderer/core/paint/paint_invalidator.h"
 #include "third_party/blink/renderer/core/paint/paint_property_tree_builder.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/hash_set.h"
 
 namespace blink {
 
 class LayoutObject;
 class LocalFrameView;
-class NGFragmentChildIterator;
+struct NGLink;
+class NGPhysicalBoxFragment;
+class NGPhysicalFragment;
 
 // This class walks the whole layout tree, beginning from the root
 // LocalFrameView, across frame boundaries. Helper classes are called for each
@@ -31,6 +34,11 @@
   static bool ObjectRequiresPrePaint(const LayoutObject&);
   static bool ObjectRequiresTreeBuilderContext(const LayoutObject&);
 
+  struct ContainingFragment {
+    const NGPhysicalBoxFragment* fragment = nullptr;
+    wtf_size_t fragmentainer_idx = WTF::kNotFound;
+  };
+
   // This provides a default base copy constructor for PrePaintTreeWalkContext.
   // It contains all fields except for tree_builder_context which needs special
   // treatment in the copy constructor.
@@ -68,9 +76,29 @@
     // enabled.
     bool clip_changed = false;
 
+    // True if we're fragment-traversing an object whose fragment wasn't found
+    // and walked when walking the layout object tree. This may happen for
+    // out-of-flow positioned and floated fragments inside block fragmentation,
+    // when an ancestor object doesn't have a fragment representation in a
+    // fragmentainer even if the OOF / float is there.
+    bool is_inside_orphaned_object = false;
+
     const LayoutBoxModelObject* paint_invalidation_container = nullptr;
     const LayoutBoxModelObject*
         paint_invalidation_container_for_stacked_contents = nullptr;
+
+    ContainingFragment current_fragmentainer;
+    ContainingFragment absolute_positioned_container;
+    ContainingFragment fixed_positioned_container;
+
+    // When walking down the tree and discovering containers for OOFs, not every
+    // such container has the fragment actually containing OOF descendants; they
+    // may instead be inside a fragment generated by a parent (this happens for
+    // inline continuations, for instance). So keep track of the innermost valid
+    // container fragment for OOFs, and set
+    // absolute_positioned_container_fragment and
+    // fixed_positioned_container_fragment to this one as appropriate.
+    const NGPhysicalBoxFragment* oof_container_candidate_fragment = nullptr;
   };
 
   struct PrePaintTreeWalkContext : public PrePaintTreeWalkContextBase {
@@ -113,6 +141,19 @@
                                     const PrePaintTreeWalkContext&);
 #endif
 
+  // Upon entering a child LayoutObject, create an NGPrePaintInfo, and populate
+  // everything except its FragmentData. We need to get a bit further inside the
+  // child (WalkInternal()) before we can set up FragmentData (if we get there
+  // at all).
+  NGPrePaintInfo CreatePrePaintInfo(const NGLink& child,
+                                    const PrePaintTreeWalkContext& context);
+
+  // Locate and/or set up a FragmentData object for the current object /
+  // physical fragment.
+  FragmentData* GetOrCreateFragmentData(const LayoutObject&,
+                                        const PrePaintTreeWalkContext&,
+                                        const NGPrePaintInfo&);
+
   void Walk(LocalFrameView&, const PrePaintTreeWalkContext& parent_context);
 
   // This is to minimize stack frame usage during recursion. Modern compilers
@@ -122,20 +163,44 @@
   // See https://crbug.com/781301 .
   NOINLINE void WalkInternal(const LayoutObject&,
                              PrePaintTreeWalkContext&,
-                             const NGFragmentChildIterator*);
-  void WalkNGChildren(const LayoutObject* parent,
-                      PrePaintTreeWalkContext& parent_context,
-                      NGFragmentChildIterator*);
-  void WalkLegacyChildren(const LayoutObject&, PrePaintTreeWalkContext&);
-  void WalkChildren(const LayoutObject*,
+                             NGPrePaintInfo*);
+
+  // Add any "missable" children to a list. Missable children are children that
+  // we might not find during LayoutObject traversal. This happens when an
+  // ancestor LayoutObject (of the missable child) has no fragment inside a
+  // given fragmentainer, e.g. when there's an OOF fragment, but its containing
+  // block has no fragment inside that fragmentainer. Later, during the child
+  // walk, when a missable child is actually walked, it's removed from the
+  // list.
+  //
+  // Returns true if there are any missable children inside the fragment, false
+  // otherwise.
+  bool CollectMissableChildren(PrePaintTreeWalkContext&,
+                               const NGPhysicalBoxFragment&);
+
+  // Walk any missed children (i.e. those collected by CollectMissableChildren()
+  // and not walked by Walk()) after child object traversal.
+  void WalkMissedChildren(const NGPhysicalBoxFragment&,
+                          PrePaintTreeWalkContext&);
+
+  void WalkFragmentationContextRootChildren(const LayoutObject&,
+                                            const NGPhysicalBoxFragment&,
+                                            PrePaintTreeWalkContext&);
+  void WalkLayoutObjectChildren(const LayoutObject&,
+                                const NGPhysicalBoxFragment*,
+                                PrePaintTreeWalkContext&);
+  void WalkChildren(const LayoutObject&,
+                    const NGPhysicalBoxFragment*,
                     PrePaintTreeWalkContext&,
-                    const NGFragmentChildIterator*);
+                    bool is_inside_fragment_child = false);
   void Walk(const LayoutObject&,
             const PrePaintTreeWalkContext& parent_context,
-            const NGFragmentChildIterator*);
+            NGPrePaintInfo*);
 
   bool NeedsTreeBuilderContextUpdate(const LocalFrameView&,
                                      const PrePaintTreeWalkContext&);
+  bool NeedsTreeBuilderContextUpdate(const LayoutObject&,
+                                     const PrePaintTreeWalkContext&);
   void UpdateAuxiliaryObjectProperties(const LayoutObject&,
                                        PrePaintTreeWalkContext&);
   // Updates |LayoutObject::InsideBlockingTouchEventHandler|. Also ensures
@@ -158,6 +223,10 @@
 
   PaintInvalidator paint_invalidator_;
 
+  // List of fragments that may be missed during LayoutObject walking. See
+  // CollectMissableChildren() and WalkMissedChildren().
+  HashSet<const NGPhysicalFragment*> pending_missables_;
+
   // TODO(https://crbug.com/841364): Remove is_wheel_event_regions_enabled
   // argument once kWheelEventRegions feature flag is removed.
   bool is_wheel_event_regions_enabled_ = false;
diff --git a/third_party/blink/renderer/core/paint/table_section_painter.cc b/third_party/blink/renderer/core/paint/table_section_painter.cc
index 15aced96..886e3ccd 100644
--- a/third_party/blink/renderer/core/paint/table_section_painter.cc
+++ b/third_party/blink/renderer/core/paint/table_section_painter.cc
@@ -48,8 +48,7 @@
   for (const auto* fragment = &layout_table_section_.FirstFragment(); fragment;
        fragment = fragment->NextFragment()) {
     PaintInfo fragment_paint_info = paint_info;
-    fragment_paint_info.SetFragmentLogicalTopInFlowThread(
-        fragment->LogicalTopInFlowThread());
+    fragment_paint_info.SetFragmentID(fragment->FragmentID());
     ScopedDisplayItemFragment scoped_display_item_fragment(
         fragment_paint_info.context, fragment_index++);
     PaintSection(fragment_paint_info);
@@ -110,8 +109,7 @@
   for (const auto* fragment = &layout_table_section_.FirstFragment(); fragment;
        fragment = fragment->NextFragment()) {
     PaintInfo fragment_paint_info = paint_info;
-    fragment_paint_info.SetFragmentLogicalTopInFlowThread(
-        fragment->LogicalTopInFlowThread());
+    fragment_paint_info.SetFragmentID(fragment->FragmentID());
     ScopedDisplayItemFragment scoped_display_item_fragment(
         fragment_paint_info.context, fragment_index++);
     PaintCollapsedSectionBorders(fragment_paint_info);
diff --git a/third_party/blink/renderer/modules/webaudio/OWNERS b/third_party/blink/renderer/modules/webaudio/OWNERS
index a837fc9b..5248064 100644
--- a/third_party/blink/renderer/modules/webaudio/OWNERS
+++ b/third_party/blink/renderer/modules/webaudio/OWNERS
@@ -1,2 +1 @@
 hongchan@chromium.org
-rtoy@chromium.org
diff --git a/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc b/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc
index 20e1456..596dac2 100644
--- a/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc
+++ b/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc
@@ -218,4 +218,25 @@
   return std::make_tuple(dawn_stage, std::move(entry_point_keepalive));
 }
 
+WGPUTextureFormat AsDawnType(SkColorType color_type) {
+  switch (color_type) {
+    case SkColorType::kRGBA_8888_SkColorType:
+      return WGPUTextureFormat_RGBA8Unorm;
+    case SkColorType::kBGRA_8888_SkColorType:
+      return WGPUTextureFormat_BGRA8Unorm;
+    case SkColorType::kRGBA_1010102_SkColorType:
+      return WGPUTextureFormat_RGB10A2Unorm;
+    case SkColorType::kRGBA_F16_SkColorType:
+      return WGPUTextureFormat_RGBA16Float;
+    case SkColorType::kRGBA_F32_SkColorType:
+      return WGPUTextureFormat_RGBA32Float;
+    case SkColorType::kR8G8_unorm_SkColorType:
+      return WGPUTextureFormat_RG8Unorm;
+    case SkColorType::kR16G16_float_SkColorType:
+      return WGPUTextureFormat_RG16Float;
+    default:
+      return WGPUTextureFormat_Undefined;
+  }
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgpu/dawn_conversions.h b/third_party/blink/renderer/modules/webgpu/dawn_conversions.h
index 9965b965..b5356a35 100644
--- a/third_party/blink/renderer/modules/webgpu/dawn_conversions.h
+++ b/third_party/blink/renderer/modules/webgpu/dawn_conversions.h
@@ -36,6 +36,8 @@
 WGPUOrigin3D AsDawnType(const V8GPUOrigin3D* webgpu_extent);
 WGPUTextureCopyView AsDawnType(const GPUImageCopyTexture* webgpu_view,
                                GPUDevice* device);
+WGPUTextureFormat AsDawnType(SkColorType color_type);
+
 const char* ValidateTextureDataLayout(const GPUImageDataLayout* webgpu_layout,
                                       WGPUTextureDataLayout* layout);
 using OwnedProgrammableStageDescriptor =
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_bind_group.cc b/third_party/blink/renderer/modules/webgpu/gpu_bind_group.cc
index 78702b2..e3f1e16 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_bind_group.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_bind_group.cc
@@ -46,11 +46,14 @@
       break;
     case V8GPUBindingResource::ContentType::kGPUExternalTexture:
       std::unique_ptr<WGPUExternalTextureBindingEntry>
-          externalTextureBindingEntry;
+          externalTextureBindingEntry =
+              std::make_unique<WGPUExternalTextureBindingEntry>();
       externalTextureBindingEntry->externalTexture =
           AsDawnType(webgpu_binding->resource()->GetAsGPUExternalTexture());
-      dawn_binding.nextInChain =
-          reinterpret_cast<WGPUChainedStruct*>(&externalTextureBindingEntry);
+      externalTextureBindingEntry->chain.sType =
+          WGPUSType_ExternalTextureBindingEntry;
+      dawn_binding.nextInChain = reinterpret_cast<WGPUChainedStruct*>(
+          externalTextureBindingEntry.get());
       externalTextureBindingEntries->push_back(
           std::move(externalTextureBindingEntry));
       break;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.cc b/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.cc
index dc7a4ae8..03aaf14 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.cc
@@ -63,7 +63,10 @@
 
   if (webgpu_binding->hasExternalTexture()) {
     std::unique_ptr<WGPUExternalTextureBindingLayout>
-        externalTextureBindingLayout;
+        externalTextureBindingLayout =
+            std::make_unique<WGPUExternalTextureBindingLayout>();
+    externalTextureBindingLayout->chain.sType =
+        WGPUSType_ExternalTextureBindingLayout;
     dawn_binding.nextInChain = reinterpret_cast<WGPUChainedStruct*>(
         externalTextureBindingLayout.get());
     externalTextureBindingLayouts->push_back(
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_device.cc b/third_party/blink/renderer/modules/webgpu/gpu_device.cc
index cda9c57f5..d865e5d 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_device.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_device.cc
@@ -9,6 +9,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_compute_pipeline_descriptor.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_device_descriptor.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_external_texture_descriptor.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_feature_name.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_render_pipeline_descriptor.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_uncaptured_error_event_init.h"
@@ -24,6 +25,7 @@
 #include "third_party/blink/renderer/modules/webgpu/gpu_command_encoder.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_device_lost_info.h"
+#include "third_party/blink/renderer/modules/webgpu/gpu_external_texture.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_out_of_memory_error.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_query_set.h"
@@ -37,8 +39,8 @@
 #include "third_party/blink/renderer/modules/webgpu/gpu_texture.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_uncaptured_error_event.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_validation_error.h"
+#include "third_party/blink/renderer/platform/bindings/microtask.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler.h"
-#include "third_party/blink/renderer/platform/heap/heap.h"
 
 namespace blink {
 
@@ -272,14 +274,6 @@
 }
 
 GPUTexture* GPUDevice::experimentalImportTexture(
-    HTMLVideoElement* video,
-    unsigned int usage_flags,
-    ExceptionState& exception_state) {
-  return GPUTexture::FromVideo(
-      this, video, static_cast<WGPUTextureUsage>(usage_flags), exception_state);
-}
-
-GPUTexture* GPUDevice::experimentalImportTexture(
     HTMLCanvasElement* canvas,
     unsigned int usage_flags,
     ExceptionState& exception_state) {
@@ -292,6 +286,15 @@
   return GPUSampler::Create(this, descriptor);
 }
 
+GPUExternalTexture* GPUDevice::importExternalTexture(
+    const GPUExternalTextureDescriptor* descriptor,
+    ExceptionState& exception_state) {
+  GPUExternalTexture* externalTexture =
+      GPUExternalTexture::FromVideo(this, descriptor, exception_state);
+  EnsureExternalTextureDestroyed(externalTexture);
+  return externalTexture;
+}
+
 GPUBindGroup* GPUDevice::createBindGroup(
     const GPUBindGroupDescriptor* descriptor,
     ExceptionState& exception_state) {
@@ -475,8 +478,29 @@
   visitor->Trace(limits_);
   visitor->Trace(queue_);
   visitor->Trace(lost_property_);
+  visitor->Trace(external_textures_pending_destroy_);
   ExecutionContextClient::Trace(visitor);
   EventTargetWithInlineData::Trace(visitor);
 }
 
+void GPUDevice::EnsureExternalTextureDestroyed(
+    GPUExternalTexture* externalTexture) {
+  external_textures_pending_destroy_.push_back(externalTexture);
+  if (has_pending_microtask_)
+    return;
+
+  Microtask::EnqueueMicrotask(WTF::Bind(
+      &GPUDevice::DestroyExternalTexturesMicrotask, WrapWeakPersistent(this)));
+  has_pending_microtask_ = true;
+}
+
+void GPUDevice::DestroyExternalTexturesMicrotask() {
+  has_pending_microtask_ = false;
+
+  auto externalTextures = std::move(external_textures_pending_destroy_);
+  for (Member<GPUExternalTexture> externalTexture : externalTextures) {
+    externalTexture->Destroy();
+  }
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_device.h b/third_party/blink/renderer/modules/webgpu/gpu_device.h
index 624ea4c2..4237762 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_device.h
+++ b/third_party/blink/renderer/modules/webgpu/gpu_device.h
@@ -12,12 +12,12 @@
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/modules/webgpu/dawn_callback.h"
 #include "third_party/blink/renderer/modules/webgpu/dawn_object.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
 
 namespace blink {
 
 class ExecutionContext;
 class HTMLCanvasElement;
-class HTMLVideoElement;
 class GPUAdapter;
 class GPUAdapter;
 class GPUBuffer;
@@ -32,6 +32,8 @@
 class GPUComputePipelineDescriptor;
 class GPUDeviceDescriptor;
 class GPUDeviceLostInfo;
+class GPUExternalTexture;
+class GPUExternalTextureDescriptor;
 class GPUPipelineLayout;
 class GPUPipelineLayoutDescriptor;
 class GPUQuerySet;
@@ -77,13 +79,13 @@
   GPUBuffer* createBuffer(const GPUBufferDescriptor* descriptor);
   GPUTexture* createTexture(const GPUTextureDescriptor* descriptor,
                             ExceptionState& exception_state);
-  GPUTexture* experimentalImportTexture(HTMLVideoElement* video,
-                                        unsigned int usage_flags,
-                                        ExceptionState& exception_state);
   GPUTexture* experimentalImportTexture(HTMLCanvasElement* canvas,
                                         unsigned int usage_flags,
                                         ExceptionState& exception_state);
   GPUSampler* createSampler(const GPUSamplerDescriptor* descriptor);
+  GPUExternalTexture* importExternalTexture(
+      const GPUExternalTextureDescriptor* descriptor,
+      ExceptionState& exception_state);
 
   GPUBindGroup* createBindGroup(const GPUBindGroupDescriptor* descriptor,
                                 ExceptionState& exception_state);
@@ -128,10 +130,14 @@
   void InjectError(WGPUErrorType type, const char* message);
   void AddConsoleWarning(const char* message);
 
+  void EnsureExternalTextureDestroyed(GPUExternalTexture* externalTexture);
+
  private:
   using LostProperty =
       ScriptPromiseProperty<Member<GPUDeviceLostInfo>, ToV8UndefinedGenerator>;
 
+  void DestroyExternalTexturesMicrotask();
+
   void OnUncapturedError(WGPUErrorType errorType, const char* message);
   void OnLogging(WGPULoggingType loggingType, const char* message);
   void OnDeviceLostError(const char* message);
@@ -171,6 +177,9 @@
   static constexpr int kMaxAllowedConsoleWarnings = 500;
   int allowed_console_warnings_remaining_ = kMaxAllowedConsoleWarnings;
 
+  bool has_pending_microtask_ = false;
+  HeapVector<Member<GPUExternalTexture>> external_textures_pending_destroy_;
+
   DISALLOW_COPY_AND_ASSIGN(GPUDevice);
 };
 
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_device.idl b/third_party/blink/renderer/modules/webgpu/gpu_device.idl
index bb4616e0..d2e72fb 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_device.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_device.idl
@@ -18,9 +18,9 @@
 
     GPUBuffer createBuffer(GPUBufferDescriptor descriptor);
     [RaisesException] GPUTexture createTexture(GPUTextureDescriptor descriptor);
-    [RuntimeEnabled=WebGPUImportTexture, RaisesException] GPUTexture experimentalImportTexture(HTMLVideoElement video, GPUTextureUsageFlags usage);
     [RuntimeEnabled=WebGPUImportTexture, RaisesException] GPUTexture experimentalImportTexture(HTMLCanvasElement canvas, GPUTextureUsageFlags usage);
     GPUSampler createSampler(optional GPUSamplerDescriptor descriptor = {});
+    [RaisesException] GPUExternalTexture importExternalTexture(GPUExternalTextureDescriptor descriptor);
 
     [RaisesException] GPUBindGroup createBindGroup(GPUBindGroupDescriptor descriptor);
     [RaisesException] GPUBindGroupLayout createBindGroupLayout(GPUBindGroupLayoutDescriptor descriptor);
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_external_texture.cc b/third_party/blink/renderer/modules/webgpu/gpu_external_texture.cc
index 479b449..6841949 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_external_texture.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_external_texture.cc
@@ -4,12 +4,136 @@
 
 #include "third_party/blink/renderer/modules/webgpu/gpu_external_texture.h"
 
+#include "media/base/video_frame.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_external_texture_descriptor.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_view_descriptor.h"
+#include "third_party/blink/renderer/core/html/media/html_video_element.h"
+#include "third_party/blink/renderer/modules/webgpu/dawn_conversions.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
+#include "third_party/blink/renderer/modules/webgpu/gpu_texture.h"
+#include "third_party/blink/renderer/modules/webgpu/gpu_texture_view.h"
+#include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
+#include "third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.h"
+#include "third_party/blink/renderer/platform/graphics/video_frame_image_util.h"
 
 namespace blink {
 
-GPUExternalTexture::GPUExternalTexture(GPUDevice* device,
-                                       WGPUExternalTexture externalTexture)
-    : DawnObject<WGPUExternalTexture>(device, externalTexture) {}
+// static
+GPUExternalTexture* GPUExternalTexture::FromVideo(
+    GPUDevice* device,
+    const GPUExternalTextureDescriptor* webgpu_desc,
+    ExceptionState& exception_state) {
+  HTMLVideoElement* video = webgpu_desc->source();
+
+  if (!video || !video->videoWidth() || !video->videoHeight()) {
+    exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
+                                      "Missing video source");
+    return nullptr;
+  }
+
+  if (video->WouldTaintOrigin()) {
+    exception_state.ThrowSecurityError(
+        "Video element is tainted by cross-origin data and may not be loaded.");
+    return nullptr;
+  }
+
+  media::PaintCanvasVideoRenderer* video_renderer = nullptr;
+  scoped_refptr<media::VideoFrame> media_video_frame;
+  if (auto* wmp = video->GetWebMediaPlayer()) {
+    media_video_frame = wmp->GetCurrentFrame();
+    video_renderer = wmp->GetPaintCanvasVideoRenderer();
+  }
+
+  if (!media_video_frame || !video_renderer) {
+    exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
+                                      "Failed to import texture from video");
+    return nullptr;
+  }
+
+  // If the context is lost, the resource provider would be invalid.
+  auto context_provider_wrapper = SharedGpuContext::ContextProviderWrapper();
+  if (!context_provider_wrapper ||
+      context_provider_wrapper->ContextProvider()->IsContextLost())
+    return nullptr;
+
+  const CanvasResourceParams params(CanvasColorSpace::kSRGB, kN32_SkColorType,
+                                    kPremul_SkAlphaType);
+  const auto intrinsic_size = IntSize(media_video_frame->natural_size());
+
+  // Get a recyclable resource for producing WebGPU-compatible shared images.
+  std::unique_ptr<RecyclableCanvasResource> recyclable_canvas_resource =
+      device->GetDawnControlClient()->GetOrCreateCanvasResource(
+          intrinsic_size, params, /*is_origin_top_left=*/true);
+  if (!recyclable_canvas_resource) {
+    exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
+                                      "Failed to import texture from video");
+    return nullptr;
+  }
+
+  CanvasResourceProvider* resource_provider =
+      recyclable_canvas_resource->resource_provider();
+  DCHECK(resource_provider);
+
+  viz::RasterContextProvider* raster_context_provider = nullptr;
+  if (auto* context_provider = context_provider_wrapper->ContextProvider())
+    raster_context_provider = context_provider->RasterContextProvider();
+
+  // TODO(crbug.com/1174809): This isn't efficient for VideoFrames which are
+  // already available as a shared image. A WebGPUMailboxTexture should be
+  // created directly from the VideoFrame instead.
+  const auto dest_rect = gfx::Rect(media_video_frame->natural_size());
+  if (!DrawVideoFrameIntoResourceProvider(
+          std::move(media_video_frame), resource_provider,
+          raster_context_provider, dest_rect, video_renderer)) {
+    exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
+                                      "Failed to import texture from video");
+    return nullptr;
+  }
+
+  // Extract the format. If this format is invalid, Dawn will emit an error upon
+  // ExternalTexture creation.
+  WGPUTextureFormat format =
+      AsDawnType(resource_provider->ColorParams().GetSkColorType());
+
+  scoped_refptr<WebGPUMailboxTexture> mailbox_texture =
+      WebGPUMailboxTexture::FromCanvasResource(
+          device->GetDawnControlClient(), device->GetHandle(),
+          WGPUTextureUsage::WGPUTextureUsage_Sampled,
+          std::move(recyclable_canvas_resource));
+
+  WGPUTextureViewDescriptor viewDesc = {};
+  WGPUTextureView plane0 = device->GetProcs().textureCreateView(
+      mailbox_texture->GetTexture(), &viewDesc);
+
+  WGPUExternalTextureDescriptor dawn_desc = {};
+  dawn_desc.plane0 = plane0;
+  dawn_desc.format = format;
+
+  GPUExternalTexture* externalTexture =
+      MakeGarbageCollected<GPUExternalTexture>(
+          device,
+          device->GetProcs().deviceCreateExternalTexture(device->GetHandle(),
+                                                         &dawn_desc),
+          mailbox_texture);
+
+  // The texture view will be referenced during external texture creation, so by
+  // calling release here we ensure this texture view will be destructed when
+  // the external texture is destructed.
+  device->GetProcs().textureViewRelease(plane0);
+
+  return externalTexture;
+}
+
+GPUExternalTexture::GPUExternalTexture(
+    GPUDevice* device,
+    WGPUExternalTexture externalTexture,
+    scoped_refptr<WebGPUMailboxTexture> mailbox_texture)
+    : DawnObject<WGPUExternalTexture>(device, externalTexture),
+      mailbox_texture_(mailbox_texture) {}
+
+void GPUExternalTexture::Destroy() {
+  GetProcs().textureDestroy(mailbox_texture_->GetTexture());
+  mailbox_texture_.reset();
+}
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_external_texture.h b/third_party/blink/renderer/modules/webgpu/gpu_external_texture.h
index 448d337..6980dca 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_external_texture.h
+++ b/third_party/blink/renderer/modules/webgpu/gpu_external_texture.h
@@ -6,17 +6,30 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_EXTERNAL_TEXTURE_H_
 
 #include "third_party/blink/renderer/modules/webgpu/dawn_object.h"
+#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
 
 namespace blink {
 
+class ExceptionState;
+class GPUExternalTextureDescriptor;
+class WebGPUMailboxTexture;
+
 class GPUExternalTexture : public DawnObject<WGPUExternalTexture> {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  explicit GPUExternalTexture(GPUDevice* device,
-                              WGPUExternalTexture externalTexture);
+  static GPUExternalTexture* FromVideo(
+      GPUDevice* device,
+      const GPUExternalTextureDescriptor* webgpu_desc,
+      ExceptionState& exception_state);
+  explicit GPUExternalTexture(
+      GPUDevice* device,
+      WGPUExternalTexture externalTexture,
+      scoped_refptr<WebGPUMailboxTexture> mailbox_texture);
+  void Destroy();
 
  private:
+  scoped_refptr<WebGPUMailboxTexture> mailbox_texture_;
   DISALLOW_COPY_AND_ASSIGN(GPUExternalTexture);
 };
 
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_texture.cc b/third_party/blink/renderer/modules/webgpu/gpu_texture.cc
index e94e305..37e0e03b 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_texture.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_texture.cc
@@ -5,12 +5,10 @@
 #include "third_party/blink/renderer/modules/webgpu/gpu_texture.h"
 
 #include "gpu/command_buffer/client/webgpu_interface.h"
-#include "media/base/video_frame.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_descriptor.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_view_descriptor.h"
 #include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h"
 #include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h"
-#include "third_party/blink/renderer/core/html/media/html_video_element.h"
 #include "third_party/blink/renderer/modules/webgpu/dawn_conversions.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_texture_usage.h"
@@ -20,7 +18,6 @@
 #include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/webgpu_resource_provider_cache.h"
-#include "third_party/blink/renderer/platform/graphics/video_frame_image_util.h"
 
 namespace blink {
 
@@ -79,27 +76,6 @@
   return dawn_desc;
 }
 
-WGPUTextureFormat SkColorTypeToWGPUTextureFormat(SkColorType color_type) {
-  switch (color_type) {
-    case SkColorType::kRGBA_8888_SkColorType:
-      return WGPUTextureFormat_RGBA8Unorm;
-    case SkColorType::kBGRA_8888_SkColorType:
-      return WGPUTextureFormat_BGRA8Unorm;
-    case SkColorType::kRGBA_1010102_SkColorType:
-      return WGPUTextureFormat_RGB10A2Unorm;
-    case SkColorType::kRGBA_F16_SkColorType:
-      return WGPUTextureFormat_RGBA16Float;
-    case SkColorType::kRGBA_F32_SkColorType:
-      return WGPUTextureFormat_RGBA32Float;
-    case SkColorType::kR8G8_unorm_SkColorType:
-      return WGPUTextureFormat_RG8Unorm;
-    case SkColorType::kR16G16_float_SkColorType:
-      return WGPUTextureFormat_RG16Float;
-    default:
-      return WGPUTextureFormat_Undefined;
-  }
-}
-
 void popErrorDiscardCallback(WGPUErrorType, const char*, void*) {
   // This callback is used to silently consume expected error messages
 }
@@ -148,99 +124,6 @@
 }
 
 // static
-GPUTexture* GPUTexture::FromVideo(GPUDevice* device,
-                                  HTMLVideoElement* video,
-                                  WGPUTextureUsage usage,
-                                  ExceptionState& exception_state) {
-  if (!video || !video->videoWidth() || !video->videoHeight()) {
-    exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
-                                      "Missing video source");
-    return nullptr;
-  }
-
-  if (video->WouldTaintOrigin()) {
-    exception_state.ThrowSecurityError(
-        "Video element is tainted by cross-origin data and may not be loaded.");
-    return nullptr;
-  }
-
-  media::PaintCanvasVideoRenderer* video_renderer = nullptr;
-  scoped_refptr<media::VideoFrame> media_video_frame;
-  if (auto* wmp = video->GetWebMediaPlayer()) {
-    media_video_frame = wmp->GetCurrentFrame();
-    video_renderer = wmp->GetPaintCanvasVideoRenderer();
-  }
-
-  if (!media_video_frame || !video_renderer) {
-    exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
-                                      "Failed to import texture from video");
-    return nullptr;
-  }
-
-  // If the context is lost, the resource provider would be invalid.
-  auto context_provider_wrapper = SharedGpuContext::ContextProviderWrapper();
-  if (!context_provider_wrapper ||
-      context_provider_wrapper->ContextProvider()->IsContextLost())
-    return nullptr;
-
-  const CanvasResourceParams params(CanvasColorSpace::kSRGB, kN32_SkColorType,
-                                    kPremul_SkAlphaType);
-  const auto intrinsic_size = IntSize(media_video_frame->natural_size());
-
-  // Get a recyclable resource for producing WebGPU-compatible shared images.
-  std::unique_ptr<RecyclableCanvasResource> recyclable_canvas_resource =
-      device->GetDawnControlClient()->GetOrCreateCanvasResource(
-          intrinsic_size, params, /*is_origin_top_left=*/true);
-  if (!recyclable_canvas_resource) {
-    exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
-                                      "Failed to import texture from video");
-    return nullptr;
-  }
-
-  CanvasResourceProvider* resource_provider =
-      recyclable_canvas_resource->resource_provider();
-  DCHECK(resource_provider);
-
-  viz::RasterContextProvider* raster_context_provider = nullptr;
-  if (auto* context_provider = context_provider_wrapper->ContextProvider())
-    raster_context_provider = context_provider->RasterContextProvider();
-
-  // TODO(crbug.com/1174809): This isn't efficient for VideoFrames which are
-  // already available as a shared image. A WebGPUMailboxTexture should be
-  // created directly from the VideoFrame instead.
-  const auto dest_rect = gfx::Rect(media_video_frame->natural_size());
-  if (!DrawVideoFrameIntoResourceProvider(
-          std::move(media_video_frame), resource_provider,
-          raster_context_provider, dest_rect, video_renderer)) {
-    exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
-                                      "Failed to import texture from video");
-    return nullptr;
-  }
-
-  // Extract the format. This is only used to validate experimentalImportTexture
-  // right now. We may want to reflect it from this function or validate it
-  // against some input parameters.
-  WGPUTextureFormat format = SkColorTypeToWGPUTextureFormat(
-      resource_provider->ColorParams().GetSkColorType());
-  if (format == WGPUTextureFormat_Undefined) {
-    exception_state.ThrowDOMException(
-        DOMExceptionCode::kOperationError,
-        "Failed to import texture from video. Unsupported format.");
-    return nullptr;
-  }
-
-  scoped_refptr<WebGPUMailboxTexture> mailbox_texture =
-      WebGPUMailboxTexture::FromCanvasResource(
-          device->GetDawnControlClient(), device->GetHandle(), usage,
-          std::move(recyclable_canvas_resource));
-
-  DCHECK(mailbox_texture->GetTexture() != nullptr);
-
-  return MakeGarbageCollected<GPUTexture>(device, format, usage,
-                                          std::move(mailbox_texture));
-}
-
-// static
 GPUTexture* GPUTexture::FromCanvas(GPUDevice* device,
                                    HTMLCanvasElement* canvas,
                                    WGPUTextureUsage usage,
@@ -297,8 +180,8 @@
   // Extract the format. This is only used to validate experimentalImportTexture
   // right now. We may want to reflect it from this function or validate it
   // against some input parameters.
-  WGPUTextureFormat format = SkColorTypeToWGPUTextureFormat(
-      resource_provider->ColorParams().GetSkColorType());
+  WGPUTextureFormat format =
+      AsDawnType(resource_provider->ColorParams().GetSkColorType());
   if (format == WGPUTextureFormat_Undefined) {
     exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
                                       "Unsupported format for import texture");
@@ -355,6 +238,10 @@
       mailbox_texture_(std::move(mailbox_texture)) {
   // Mailbox textures are all 2d texture.
   dimension_ = WGPUTextureDimension_2D;
+
+  // The mailbox texture releases the texture on destruction, so reference it
+  // here.
+  GetProcs().textureReference(GetHandle());
 }
 
 GPUTextureView* GPUTexture::createView(
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_texture.h b/third_party/blink/renderer/modules/webgpu/gpu_texture.h
index 46499bbb..b2507d6 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_texture.h
+++ b/third_party/blink/renderer/modules/webgpu/gpu_texture.h
@@ -12,7 +12,6 @@
 
 class ExceptionState;
 class HTMLCanvasElement;
-class HTMLVideoElement;
 class GPUTextureDescriptor;
 class GPUTextureView;
 class GPUTextureViewDescriptor;
@@ -27,10 +26,6 @@
                             const GPUTextureDescriptor* webgpu_desc,
                             ExceptionState& exception_state);
   static GPUTexture* CreateError(GPUDevice* device);
-  static GPUTexture* FromVideo(GPUDevice* device,
-                               HTMLVideoElement* video,
-                               WGPUTextureUsage usage,
-                               ExceptionState& exception_state);
   static GPUTexture* FromCanvas(GPUDevice* device,
                                 HTMLCanvasElement* canvas,
                                 WGPUTextureUsage usage,
diff --git a/third_party/blink/renderer/modules/webid/web_id.cc b/third_party/blink/renderer/modules/webid/web_id.cc
index 2ef8db4c..be1f270 100644
--- a/third_party/blink/renderer/modules/webid/web_id.cc
+++ b/third_party/blink/renderer/modules/webid/web_id.cc
@@ -134,16 +134,6 @@
 ScriptPromise WebId::get(ScriptState* script_state,
                          const WebIdRequestOptions* options,
                          ExceptionState& exception_state) {
-  if (!options->hasProvider()) {
-    exception_state.ThrowTypeError("Invalid parameters: provider required.");
-    return ScriptPromise();
-  }
-
-  if (!options->hasRequest()) {
-    exception_state.ThrowTypeError("Invalid parameters: request required.");
-    return ScriptPromise();
-  }
-
   DCHECK(options->hasMode());
 
   // TODO(kenrb): Add some renderer-side validation here, such as validating
@@ -161,8 +151,11 @@
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
   ScriptPromise promise = resolver->Promise();
 
+  String client_id = options->hasClientId() ? options->clientId() : "";
+  String nonce = options->hasNonce() ? options->nonce() : "";
+
   auth_request_->RequestIdToken(
-      provider, options->request(), ToRequestMode(options->mode()),
+      provider, client_id, nonce, ToRequestMode(options->mode()),
       WTF::Bind(&OnRequestIdToken, WrapPersistent(resolver)));
 
   return promise;
diff --git a/third_party/blink/renderer/modules/webid/web_id_request_options.idl b/third_party/blink/renderer/modules/webid/web_id_request_options.idl
index 8d3dc870..591aecf 100644
--- a/third_party/blink/renderer/modules/webid/web_id_request_options.idl
+++ b/third_party/blink/renderer/modules/webid/web_id_request_options.idl
@@ -11,8 +11,8 @@
 
 dictionary WebIdRequestOptions {
   // URL for the Identity Provider.
-  USVString provider;
-  // Serialized request parameters.
-  USVString request;
+  required USVString provider;
+  USVString client_id;
+  USVString nonce;
   Mode mode = "permission";
 };
diff --git a/third_party/blink/renderer/platform/OWNERS b/third_party/blink/renderer/platform/OWNERS
index 37e78833..c7b8717 100644
--- a/third_party/blink/renderer/platform/OWNERS
+++ b/third_party/blink/renderer/platform/OWNERS
@@ -15,7 +15,6 @@
 mkwst@chromium.org
 noel@chromium.org
 pdr@chromium.org
-rtoy@chromium.org
 schenney@chromium.org
 senorblanco@chromium.org
 skyostil@chromium.org
diff --git a/third_party/blink/renderer/platform/audio/OWNERS b/third_party/blink/renderer/platform/audio/OWNERS
index a837fc9b..5248064 100644
--- a/third_party/blink/renderer/platform/audio/OWNERS
+++ b/third_party/blink/renderer/platform/audio/OWNERS
@@ -1,2 +1 @@
 hongchan@chromium.org
-rtoy@chromium.org
diff --git a/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_string.h b/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_string.h
index 67114790f..128672cb 100644
--- a/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_string.h
+++ b/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_string.h
@@ -15,15 +15,14 @@
 // Small shim around TraceWrapperReference<v8::String> with a few
 // utility methods. Internally, v8::String is represented as string
 // rope.
-class GC_PLUGIN_IGNORE("crbug.com/841830")
-    PLATFORM_EXPORT TraceWrapperV8String final : public NameClient {
+class PLATFORM_EXPORT TraceWrapperV8String final {
   DISALLOW_NEW();
 
  public:
   TraceWrapperV8String() = default;
   TraceWrapperV8String(const TraceWrapperV8String&) = delete;
   TraceWrapperV8String& operator=(const TraceWrapperV8String&) = delete;
-  ~TraceWrapperV8String() final = default;
+  ~TraceWrapperV8String() = default;
 
   bool IsEmpty() const { return string_.IsEmpty(); }
   void Clear() { string_.Clear(); }
@@ -35,11 +34,7 @@
   void Concat(v8::Isolate*, const String&);
   String Flatten(v8::Isolate*) const;
 
-  virtual void Trace(Visitor* visitor) const { visitor->Trace(string_); }
-
-  const char* NameInHeapSnapshot() const override {
-    return "TraceWrapperV8String";
-  }
+  void Trace(Visitor* visitor) const { visitor->Trace(string_); }
 
  private:
   TraceWrapperV8Reference<v8::String> string_;
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler_test.cc b/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler_test.cc
index c316f80..15ff68fa 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler_test.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/webgpu_image_bitmap_handler_test.cc
@@ -65,6 +65,7 @@
     // real WebGPU device.
     procs_.deviceReference = [](WGPUDevice) {};
     procs_.deviceRelease = [](WGPUDevice) {};
+    procs_.textureRelease = [](WGPUTexture) {};
   }
 
   MOCK_METHOD(gpu::webgpu::ReservedTexture,
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.cc b/third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.cc
index 4651c0b..24ac27d 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/webgpu_mailbox_texture.cc
@@ -92,7 +92,7 @@
     webgpu->GenUnverifiedSyncTokenCHROMIUM(finished_access_token.GetData());
     std::move(destroy_callback_).Run(finished_access_token);
   }
-
+  dawn_control_client_->GetProcs().textureRelease(texture_);
   dawn_control_client_->GetProcs().deviceRelease(device_);
 }
 
diff --git a/third_party/blink/renderer/platform/graphics/paint/cull_rect.cc b/third_party/blink/renderer/platform/graphics/paint/cull_rect.cc
index d69c077a..f8e1c8b9 100644
--- a/third_party/blink/renderer/platform/graphics/paint/cull_rect.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/cull_rect.cc
@@ -126,6 +126,10 @@
     const PropertyTreeState& destination) {
   FloatClipRect clip_rect =
       GeometryMapper::LocalToAncestorClipRect(destination, source);
+  if (clip_rect.Rect().IsEmpty()) {
+    rect_ = IntRect();
+    return false;
+  }
   if (!clip_rect.IsInfinite()) {
     rect_.Intersect(EnclosingIntRect(clip_rect.Rect()));
     if (rect_.IsEmpty())
diff --git a/third_party/blink/renderer/platform/graphics/paint/cull_rect_test.cc b/third_party/blink/renderer/platform/graphics/paint/cull_rect_test.cc
index 2e13e75f..964f3b78 100644
--- a/third_party/blink/renderer/platform/graphics/paint/cull_rect_test.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/cull_rect_test.cc
@@ -799,6 +799,17 @@
   EXPECT_EQ(IntRect(0, 0, 100, 2000), cull_rect.Rect());
 }
 
+TEST_F(CullRectTest, ClipWithNonIntegralOffsetAndZeroSize) {
+  ScopedCullRectUpdateForTest cull_rect_update(true);
+
+  auto clip = CreateClip(c0(), t0(), FloatRoundedRect(0.4, 0.6, 0, 0));
+  PropertyTreeState source = PropertyTreeState::Root();
+  PropertyTreeState destination(t0(), *clip, e0());
+  CullRect cull_rect(IntRect(0, 0, 800, 600));
+  cull_rect.ApplyPaintProperties(source, source, destination, absl::nullopt);
+  EXPECT_TRUE(cull_rect.Rect().IsEmpty());
+}
+
 TEST_F(CullRectTest, IntersectsVerticalRange) {
   CullRect cull_rect(IntRect(0, 0, 50, 100));
 
diff --git a/third_party/blink/renderer/platform/media/cache_util.h b/third_party/blink/renderer/platform/media/cache_util.h
index e7db731..70d94ebd 100644
--- a/third_party/blink/renderer/platform/media/cache_util.h
+++ b/third_party/blink/renderer/platform/media/cache_util.h
@@ -31,14 +31,14 @@
 // Return the logical OR of the reasons "response" cannot be used for a future
 // request (using the disk cache), or 0 if it might be useful.
 PLATFORM_EXPORT uint32_t
-GetReasonsForUncacheability(const blink::WebURLResponse& response);
+GetReasonsForUncacheability(const WebURLResponse& response);
 
 // Returns when we should evict data from this response from our
 // memory cache. Note that we may still cache data longer if
 // a audio/video tag is currently using it. Returns a TimeDelta
 // which is should be added to base::Time::Now() or base::TimeTicks::Now().
 PLATFORM_EXPORT base::TimeDelta GetCacheValidUntil(
-    const blink::WebURLResponse& response);
+    const WebURLResponse& response);
 
 }  // namespace blink
 
diff --git a/third_party/blink/renderer/platform/media/cdm_result_promise.h b/third_party/blink/renderer/platform/media/cdm_result_promise.h
index 6a5b7be..0a69723 100644
--- a/third_party/blink/renderer/platform/media/cdm_result_promise.h
+++ b/third_party/blink/renderer/platform/media/cdm_result_promise.h
@@ -29,7 +29,7 @@
 class PLATFORM_EXPORT CdmResultPromise
     : public media::CdmPromiseTemplate<T...> {
  public:
-  CdmResultPromise(const blink::WebContentDecryptionModuleResult& result,
+  CdmResultPromise(const WebContentDecryptionModuleResult& result,
                    const std::string& key_system_uma_prefix,
                    const std::string& uma_name);
   CdmResultPromise(const CdmResultPromise&) = delete;
@@ -47,7 +47,7 @@
   using media::CdmPromiseTemplate<T...>::MarkPromiseSettled;
   using media::CdmPromiseTemplate<T...>::RejectPromiseOnDestruction;
 
-  blink::WebContentDecryptionModuleResult web_cdm_result_;
+  WebContentDecryptionModuleResult web_cdm_result_;
 
   // UMA prefix and name to report result and time to.
   std::string key_system_uma_prefix_;
@@ -59,7 +59,7 @@
 
 template <typename... T>
 CdmResultPromise<T...>::CdmResultPromise(
-    const blink::WebContentDecryptionModuleResult& result,
+    const WebContentDecryptionModuleResult& result,
     const std::string& key_system_uma_prefix,
     const std::string& uma_name)
     : web_cdm_result_(result),
@@ -112,7 +112,7 @@
                      ConvertCdmExceptionToResultForUMA(exception_code));
   web_cdm_result_.CompleteWithError(ConvertCdmException(exception_code),
                                     system_code,
-                                    blink::WebString::FromUTF8(error_message));
+                                    WebString::FromUTF8(error_message));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/media/cdm_result_promise_helper.cc b/third_party/blink/renderer/platform/media/cdm_result_promise_helper.cc
index a03c66e..76168f5 100644
--- a/third_party/blink/renderer/platform/media/cdm_result_promise_helper.cc
+++ b/third_party/blink/renderer/platform/media/cdm_result_promise_helper.cc
@@ -25,44 +25,42 @@
   return INVALID_STATE_ERROR;
 }
 
-blink::WebContentDecryptionModuleException ConvertCdmException(
+WebContentDecryptionModuleException ConvertCdmException(
     media::CdmPromise::Exception exception_code) {
   switch (exception_code) {
     case media::CdmPromise::Exception::NOT_SUPPORTED_ERROR:
-      return blink::kWebContentDecryptionModuleExceptionNotSupportedError;
+      return kWebContentDecryptionModuleExceptionNotSupportedError;
     case media::CdmPromise::Exception::INVALID_STATE_ERROR:
-      return blink::kWebContentDecryptionModuleExceptionInvalidStateError;
+      return kWebContentDecryptionModuleExceptionInvalidStateError;
     case media::CdmPromise::Exception::QUOTA_EXCEEDED_ERROR:
-      return blink::kWebContentDecryptionModuleExceptionQuotaExceededError;
+      return kWebContentDecryptionModuleExceptionQuotaExceededError;
     case media::CdmPromise::Exception::TYPE_ERROR:
-      return blink::kWebContentDecryptionModuleExceptionTypeError;
+      return kWebContentDecryptionModuleExceptionTypeError;
   }
   NOTREACHED();
-  return blink::kWebContentDecryptionModuleExceptionInvalidStateError;
+  return kWebContentDecryptionModuleExceptionInvalidStateError;
 }
 
-blink::WebEncryptedMediaKeyInformation::KeyStatus ConvertCdmKeyStatus(
+WebEncryptedMediaKeyInformation::KeyStatus ConvertCdmKeyStatus(
     media::CdmKeyInformation::KeyStatus key_status) {
   switch (key_status) {
     case media::CdmKeyInformation::USABLE:
-      return blink::WebEncryptedMediaKeyInformation::KeyStatus::kUsable;
+      return WebEncryptedMediaKeyInformation::KeyStatus::kUsable;
     case media::CdmKeyInformation::INTERNAL_ERROR:
-      return blink::WebEncryptedMediaKeyInformation::KeyStatus::kInternalError;
+      return WebEncryptedMediaKeyInformation::KeyStatus::kInternalError;
     case media::CdmKeyInformation::EXPIRED:
-      return blink::WebEncryptedMediaKeyInformation::KeyStatus::kExpired;
+      return WebEncryptedMediaKeyInformation::KeyStatus::kExpired;
     case media::CdmKeyInformation::OUTPUT_RESTRICTED:
-      return blink::WebEncryptedMediaKeyInformation::KeyStatus::
-          kOutputRestricted;
+      return WebEncryptedMediaKeyInformation::KeyStatus::kOutputRestricted;
     case media::CdmKeyInformation::OUTPUT_DOWNSCALED:
-      return blink::WebEncryptedMediaKeyInformation::KeyStatus::
-          kOutputDownscaled;
+      return WebEncryptedMediaKeyInformation::KeyStatus::kOutputDownscaled;
     case media::CdmKeyInformation::KEY_STATUS_PENDING:
-      return blink::WebEncryptedMediaKeyInformation::KeyStatus::kStatusPending;
+      return WebEncryptedMediaKeyInformation::KeyStatus::kStatusPending;
     case media::CdmKeyInformation::RELEASED:
-      return blink::WebEncryptedMediaKeyInformation::KeyStatus::kReleased;
+      return WebEncryptedMediaKeyInformation::KeyStatus::kReleased;
   }
   NOTREACHED();
-  return blink::WebEncryptedMediaKeyInformation::KeyStatus::kInternalError;
+  return WebEncryptedMediaKeyInformation::KeyStatus::kInternalError;
 }
 
 void ReportCdmResultUMA(const std::string& uma_name,
diff --git a/third_party/blink/renderer/platform/media/cdm_result_promise_helper.h b/third_party/blink/renderer/platform/media/cdm_result_promise_helper.h
index 80a0161c..caf3bf5 100644
--- a/third_party/blink/renderer/platform/media/cdm_result_promise_helper.h
+++ b/third_party/blink/renderer/platform/media/cdm_result_promise_helper.h
@@ -35,11 +35,11 @@
 PLATFORM_EXPORT CdmResultForUMA
 ConvertCdmExceptionToResultForUMA(media::CdmPromise::Exception exception_code);
 
-PLATFORM_EXPORT blink::WebContentDecryptionModuleException ConvertCdmException(
-    media::CdmPromise::Exception exception_code);
+PLATFORM_EXPORT WebContentDecryptionModuleException
+ConvertCdmException(media::CdmPromise::Exception exception_code);
 
-PLATFORM_EXPORT blink::WebEncryptedMediaKeyInformation::KeyStatus
-ConvertCdmKeyStatus(media::CdmKeyInformation::KeyStatus key_status);
+PLATFORM_EXPORT WebEncryptedMediaKeyInformation::KeyStatus ConvertCdmKeyStatus(
+    media::CdmKeyInformation::KeyStatus key_status);
 
 PLATFORM_EXPORT void ReportCdmResultUMA(const std::string& uma_name,
                                         uint32_t system_code,
diff --git a/third_party/blink/renderer/platform/media/cdm_session_adapter.cc b/third_party/blink/renderer/platform/media/cdm_session_adapter.cc
index 95b2c01..32be1b7a 100644
--- a/third_party/blink/renderer/platform/media/cdm_session_adapter.cc
+++ b/third_party/blink/renderer/platform/media/cdm_session_adapter.cc
@@ -74,8 +74,7 @@
 }
 
 std::unique_ptr<WebContentDecryptionModuleSessionImpl>
-CdmSessionAdapter::CreateSession(
-    blink::WebEncryptedMediaSessionType session_type) {
+CdmSessionAdapter::CreateSession(WebEncryptedMediaSessionType session_type) {
   return std::make_unique<WebContentDecryptionModuleSessionImpl>(this,
                                                                  session_type);
 }
diff --git a/third_party/blink/renderer/platform/media/cdm_session_adapter.h b/third_party/blink/renderer/platform/media/cdm_session_adapter.h
index 650ff09..b74d194 100644
--- a/third_party/blink/renderer/platform/media/cdm_session_adapter.h
+++ b/third_party/blink/renderer/platform/media/cdm_session_adapter.h
@@ -66,7 +66,7 @@
   // Creates a new session and adds it to the internal map. RemoveSession()
   // must be called when destroying it, if RegisterSession() was called.
   std::unique_ptr<WebContentDecryptionModuleSessionImpl> CreateSession(
-      blink::WebEncryptedMediaSessionType session_type);
+      WebEncryptedMediaSessionType session_type);
 
   // Adds a session to the internal map. Called once the session is successfully
   // initialized. Returns true if the session was registered, false if there is
diff --git a/third_party/blink/renderer/platform/media/key_system_config_selector.cc b/third_party/blink/renderer/platform/media/key_system_config_selector.cc
index 48b6b1f..86d68a4 100644
--- a/third_party/blink/renderer/platform/media/key_system_config_selector.cc
+++ b/third_party/blink/renderer/platform/media/key_system_config_selector.cc
@@ -138,13 +138,13 @@
   return EmeConfigRule::PERSISTENCE_REQUIRED;
 }
 
-bool IsPersistentSessionType(blink::WebEncryptedMediaSessionType sessionType) {
+bool IsPersistentSessionType(WebEncryptedMediaSessionType sessionType) {
   switch (sessionType) {
-    case blink::WebEncryptedMediaSessionType::kTemporary:
+    case WebEncryptedMediaSessionType::kTemporary:
       return false;
-    case blink::WebEncryptedMediaSessionType::kPersistentLicense:
+    case WebEncryptedMediaSessionType::kPersistentLicense:
       return true;
-    case blink::WebEncryptedMediaSessionType::kUnknown:
+    case WebEncryptedMediaSessionType::kUnknown:
       break;
   }
 
@@ -207,9 +207,9 @@
 }
 
 bool KeySystemConfigSelector::WebLocalFrameDelegate::AllowStorageAccessSync(
-    blink::WebContentSettingsClient::StorageType storage_type) {
+    WebContentSettingsClient::StorageType storage_type) {
   DCHECK(web_frame_);
-  blink::WebContentSettingsClient* content_settings_client =
+  WebContentSettingsClient* content_settings_client =
       web_frame_->GetContentSettingsClient();
   return !content_settings_client ||
          content_settings_client->AllowStorageAccessSync(storage_type);
@@ -217,8 +217,7 @@
 
 struct KeySystemConfigSelector::SelectionRequest {
   std::string key_system;
-  blink::WebVector<blink::WebMediaKeySystemConfiguration>
-      candidate_configurations;
+  WebVector<WebMediaKeySystemConfiguration> candidate_configurations;
   SelectConfigCB cb;
   bool was_permission_requested = false;
   bool is_permission_granted = false;
@@ -467,11 +466,11 @@
 bool KeySystemConfigSelector::GetSupportedCapabilities(
     const std::string& key_system,
     EmeMediaType media_type,
-    const blink::WebVector<blink::WebMediaKeySystemMediaCapability>&
+    const WebVector<WebMediaKeySystemMediaCapability>&
         requested_media_capabilities,
     // Corresponds to the partial configuration, plus restrictions.
     KeySystemConfigSelector::ConfigState* config_state,
-    std::vector<blink::WebMediaKeySystemMediaCapability>*
+    std::vector<WebMediaKeySystemMediaCapability>*
         supported_media_capabilities) {
   // From "3.1.1.3 Get Supported Capabilities for Audio/Video Type".
   // https://w3c.github.io/encrypted-media/#get-supported-capabilities-for-audio-video-type
@@ -486,7 +485,7 @@
   for (size_t i = 0; i < requested_media_capabilities.size(); i++) {
     // 3.1. Let content type be requested media capability's contentType member.
     // 3.2. Let robustness be requested media capability's robustness member.
-    const blink::WebMediaKeySystemMediaCapability& capability =
+    const WebMediaKeySystemMediaCapability& capability =
         requested_media_capabilities[i];
     // 3.3. If contentType is the empty string, return null.
     if (capability.mime_type.IsEmpty()) {
@@ -588,9 +587,9 @@
 KeySystemConfigSelector::ConfigurationSupport
 KeySystemConfigSelector::GetSupportedConfiguration(
     const std::string& key_system,
-    const blink::WebMediaKeySystemConfiguration& candidate,
+    const WebMediaKeySystemConfiguration& candidate,
     ConfigState* config_state,
-    blink::WebMediaKeySystemConfiguration* accumulated_configuration) {
+    WebMediaKeySystemConfiguration* accumulated_configuration) {
   DVLOG(3) << __func__;
 
   // From
@@ -711,7 +710,7 @@
   // If preferences disallow local storage, then indicate persistent state is
   // not supported.
   if (!web_frame_delegate_->AllowStorageAccessSync(
-          blink::WebContentSettingsClient::StorageType::kLocalStorage)) {
+          WebContentSettingsClient::StorageType::kLocalStorage)) {
     if (persistent_state_support == EmeFeatureSupport::ALWAYS_ENABLED)
       return CONFIGURATION_NOT_SUPPORTED;
     persistent_state_support = EmeFeatureSupport::NOT_SUPPORTED;
@@ -735,14 +734,14 @@
   //         let session types be candidate configuration's sessionTypes member.
   //       - Otherwise, let session types be [ "temporary" ].
   //         (Done in MediaKeySystemAccessInitializer.)
-  blink::WebVector<blink::WebEncryptedMediaSessionType> session_types =
+  WebVector<WebEncryptedMediaSessionType> session_types =
       candidate.session_types;
 
   // 13. For each value in session types:
   for (size_t i = 0; i < session_types.size(); i++) {
     // 13.1. Let session type be the value.
-    blink::WebEncryptedMediaSessionType session_type = session_types[i];
-    if (session_type == blink::WebEncryptedMediaSessionType::kUnknown) {
+    WebEncryptedMediaSessionType session_type = session_types[i];
+    if (session_type == WebEncryptedMediaSessionType::kUnknown) {
       DVLOG(2) << "Rejecting requested configuration because "
                << "session type was not recognized.";
       return CONFIGURATION_NOT_SUPPORTED;
@@ -764,13 +763,13 @@
     //       return NotSupported.
     EmeConfigRule session_type_rule = EmeConfigRule::NOT_SUPPORTED;
     switch (session_type) {
-      case blink::WebEncryptedMediaSessionType::kUnknown:
+      case WebEncryptedMediaSessionType::kUnknown:
         NOTREACHED();
         return CONFIGURATION_NOT_SUPPORTED;
-      case blink::WebEncryptedMediaSessionType::kTemporary:
+      case WebEncryptedMediaSessionType::kTemporary:
         session_type_rule = EmeConfigRule::SUPPORTED;
         break;
-      case blink::WebEncryptedMediaSessionType::kPersistentLicense:
+      case WebEncryptedMediaSessionType::kPersistentLicense:
         session_type_rule = GetSessionTypeConfigRule(
             key_systems_->GetPersistentLicenseSessionSupport(key_system));
         break;
@@ -810,7 +809,7 @@
 
   // 16. If the videoCapabilities member in candidate configuration is
   //     non-empty:
-  std::vector<blink::WebMediaKeySystemMediaCapability> video_capabilities;
+  std::vector<WebMediaKeySystemMediaCapability> video_capabilities;
   if (!candidate.video_capabilities.empty()) {
     // 16.1. Let video capabilities be the result of executing the Get
     //       Supported Capabilities for Audio/Video Type algorithm on Video,
@@ -836,7 +835,7 @@
 
   // 17. If the audioCapabilities member in candidate configuration is
   //     non-empty:
-  std::vector<blink::WebMediaKeySystemMediaCapability> audio_capabilities;
+  std::vector<WebMediaKeySystemMediaCapability> audio_capabilities;
   if (!candidate.audio_capabilities.empty()) {
     // 17.1. Let audio capabilities be the result of executing the Get
     //       Supported Capabilities for Audio/Video Type algorithm on Audio,
@@ -980,9 +979,8 @@
 }
 
 void KeySystemConfigSelector::SelectConfig(
-    const blink::WebString& key_system,
-    const blink::WebVector<blink::WebMediaKeySystemConfiguration>&
-        candidate_configurations,
+    const WebString& key_system,
+    const WebVector<WebMediaKeySystemConfiguration>& candidate_configurations,
     SelectConfigCB cb) {
   // Continued from requestMediaKeySystemAccess(), step 6, from
   // https://w3c.github.io/encrypted-media/#requestmediakeysystemaccess
@@ -1053,7 +1051,7 @@
     //        and return a new MediaKeySystemAccess object.]
     ConfigState config_state(request->was_permission_requested,
                              request->is_permission_granted);
-    blink::WebMediaKeySystemConfiguration accumulated_configuration;
+    WebMediaKeySystemConfiguration accumulated_configuration;
     media::CdmConfig cdm_config;
     ConfigurationSupport support = GetSupportedConfiguration(
         request->key_system, request->candidate_configurations[i],
diff --git a/third_party/blink/renderer/platform/media/key_system_config_selector_unittest.cc b/third_party/blink/renderer/platform/media/key_system_config_selector_unittest.cc
index 22bc867..0b8394f 100644
--- a/third_party/blink/renderer/platform/media/key_system_config_selector_unittest.cc
+++ b/third_party/blink/renderer/platform/media/key_system_config_selector_unittest.cc
@@ -381,9 +381,8 @@
       : KeySystemConfigSelector::WebLocalFrameDelegate(nullptr) {}
   bool IsCrossOriginToMainFrame() override { return is_cross_origin_; }
   bool AllowStorageAccessSync(
-      blink::WebContentSettingsClient::StorageType storage_type) override {
-    if (storage_type ==
-        blink::WebContentSettingsClient::StorageType::kLocalStorage) {
+      WebContentSettingsClient::StorageType storage_type) override {
+    if (storage_type == WebContentSettingsClient::StorageType::kLocalStorage) {
       return local_storage_allowed_;
     }
     return true;
@@ -1275,13 +1274,13 @@
 
 TEST_F(KeySystemConfigSelectorTest,
        VideoCapabilities_EncryptionScheme_Supported) {
-  std::vector<blink::WebMediaKeySystemMediaCapability> video_capabilities(1);
+  std::vector<WebMediaKeySystemMediaCapability> video_capabilities(1);
   video_capabilities[0].content_type = "a";
   video_capabilities[0].mime_type = kSupportedVideoContainer;
   video_capabilities[0].codecs = kSupportedVideoCodec;
   video_capabilities[0].encryption_scheme = kSupportedEncryptionScheme;
 
-  blink::WebMediaKeySystemConfiguration config = EmptyConfiguration();
+  WebMediaKeySystemConfiguration config = EmptyConfiguration();
   config.video_capabilities = video_capabilities;
   configs_.push_back(config);
 
@@ -1293,14 +1292,14 @@
 
 TEST_F(KeySystemConfigSelectorTest,
        VideoCapabilities_EncryptionScheme_DisallowHwSecureCodec) {
-  std::vector<blink::WebMediaKeySystemMediaCapability> video_capabilities(1);
+  std::vector<WebMediaKeySystemMediaCapability> video_capabilities(1);
   video_capabilities[0].content_type = "a";
   video_capabilities[0].mime_type = kSupportedVideoContainer;
   video_capabilities[0].codecs = kSupportedVideoCodec;
   video_capabilities[0].encryption_scheme =
       kDisallowHwSecureCodecEncryptionScheme;
 
-  blink::WebMediaKeySystemConfiguration config = EmptyConfiguration();
+  WebMediaKeySystemConfiguration config = EmptyConfiguration();
   config.video_capabilities = video_capabilities;
   configs_.push_back(config);
 
@@ -1488,13 +1487,13 @@
 }
 
 TEST_F(KeySystemConfigSelectorTest, HwSecureCodec_EncryptionScheme_Supported) {
-  std::vector<blink::WebMediaKeySystemMediaCapability> video_capabilities(1);
+  std::vector<WebMediaKeySystemMediaCapability> video_capabilities(1);
   video_capabilities[0].content_type = "a";
   video_capabilities[0].mime_type = kSupportedVideoContainer;
   video_capabilities[0].codecs = kRequireHwSecureCodec;
   video_capabilities[0].encryption_scheme = kSupportedEncryptionScheme;
 
-  blink::WebMediaKeySystemConfiguration config = EmptyConfiguration();
+  WebMediaKeySystemConfiguration config = EmptyConfiguration();
   config.video_capabilities = video_capabilities;
   configs_.push_back(config);
 
@@ -1507,14 +1506,14 @@
 
 TEST_F(KeySystemConfigSelectorTest,
        HwSecureCodec_EncryptionScheme_DisallowHwSecureCodec) {
-  std::vector<blink::WebMediaKeySystemMediaCapability> video_capabilities(1);
+  std::vector<WebMediaKeySystemMediaCapability> video_capabilities(1);
   video_capabilities[0].content_type = "a";
   video_capabilities[0].mime_type = kSupportedVideoContainer;
   video_capabilities[0].codecs = kRequireHwSecureCodec;
   video_capabilities[0].encryption_scheme =
       kDisallowHwSecureCodecEncryptionScheme;
 
-  blink::WebMediaKeySystemConfiguration config = EmptyConfiguration();
+  WebMediaKeySystemConfiguration config = EmptyConfiguration();
   config.video_capabilities = video_capabilities;
   configs_.push_back(config);
 
diff --git a/third_party/blink/renderer/platform/media/multi_buffer_data_source_unittest.cc b/third_party/blink/renderer/platform/media/multi_buffer_data_source_unittest.cc
index b8d8b40..472735c 100644
--- a/third_party/blink/renderer/platform/media/multi_buffer_data_source_unittest.cc
+++ b/third_party/blink/renderer/platform/media/multi_buffer_data_source_unittest.cc
@@ -238,7 +238,7 @@
  public:
   MultiBufferDataSourceTest() : preload_(MultiBufferDataSource::AUTO) {
     ON_CALL(fetch_context_, CreateUrlLoader(_))
-        .WillByDefault(Invoke([](const blink::WebAssociatedURLLoaderOptions&) {
+        .WillByDefault(Invoke([](const WebAssociatedURLLoaderOptions&) {
           return std::make_unique<NiceMock<MockWebAssociatedURLLoader>>();
         }));
   }
@@ -438,13 +438,13 @@
   TestMultiBufferDataProvider* data_provider() {
     return multibuffer()->GetProvider();
   }
-  blink::WebAssociatedURLLoader* active_loader() {
+  WebAssociatedURLLoader* active_loader() {
     EXPECT_TRUE(data_provider());
     if (!data_provider())
       return nullptr;
     return data_provider()->active_loader_.get();
   }
-  blink::WebAssociatedURLLoader* active_loader_allownull() {
+  WebAssociatedURLLoader* active_loader_allownull() {
     TestMultiBufferDataProvider* data_provider =
         multibuffer()->GetProvider_allownull();
     if (!data_provider)
@@ -770,7 +770,7 @@
   WebURLResponse response1 =
       response_generator_->GeneratePartial206(0, kDataSize - 1);
   response1.SetWasFetchedViaServiceWorker(true);
-  std::vector<blink::WebURL> url_list = {GURL(kHttpUrl)};
+  std::vector<WebURL> url_list = {GURL(kHttpUrl)};
   response1.SetUrlListViaServiceWorker(url_list);
   WebURLResponse response2 =
       response_generator_->GeneratePartial206(kDataSize, kDataSize * 2 - 1);
@@ -785,7 +785,7 @@
   WebURLResponse response1 =
       response_generator_->GeneratePartial206(0, kDataSize - 1);
   response1.SetWasFetchedViaServiceWorker(true);
-  std::vector<blink::WebURL> url_list = {GURL(kHttpDifferentPathUrl)};
+  std::vector<WebURL> url_list = {GURL(kHttpDifferentPathUrl)};
   response1.SetUrlListViaServiceWorker(url_list);
   WebURLResponse response2 =
       response_generator_->GeneratePartial206(kDataSize, kDataSize * 2 - 1);
@@ -800,7 +800,7 @@
   WebURLResponse response1 =
       response_generator_->GeneratePartial206(0, kDataSize - 1);
   response1.SetWasFetchedViaServiceWorker(true);
-  std::vector<blink::WebURL> url_list = {GURL(kHttpDifferentOriginUrl)};
+  std::vector<WebURL> url_list = {GURL(kHttpDifferentOriginUrl)};
   response1.SetUrlListViaServiceWorker(url_list);
   WebURLResponse response2 =
       response_generator_->GeneratePartial206(kDataSize, kDataSize * 2 - 1);
@@ -815,7 +815,7 @@
   WebURLResponse response1 =
       response_generator_->GeneratePartial206(0, kDataSize - 1);
   response1.SetWasFetchedViaServiceWorker(true);
-  std::vector<blink::WebURL> url_list = {GURL(kHttpDifferentOriginUrl)};
+  std::vector<WebURL> url_list = {GURL(kHttpDifferentOriginUrl)};
   response1.SetUrlListViaServiceWorker(url_list);
   WebURLResponse response2 =
       response_generator_->GeneratePartial206(kDataSize, kDataSize * 2 - 1);
@@ -1436,8 +1436,8 @@
   run_loop.Run();
 
   // Server responds with a redirect.
-  blink::WebURL url{GURL(kHttpDifferentPathUrl)};
-  blink::WebURLResponse response((GURL(kHttpUrl)));
+  WebURL url{GURL(kHttpDifferentPathUrl)};
+  WebURLResponse response((GURL(kHttpUrl)));
   response.SetHttpStatusCode(307);
   data_provider()->WillFollowRedirect(url, response);
 
@@ -1454,8 +1454,8 @@
   Initialize(kHttpUrl, true);
 
   // Server responds with a redirect.
-  blink::WebURL url{GURL(kHttpDifferentPathUrl)};
-  blink::WebURLResponse response((GURL(kHttpUrl)));
+  WebURL url{GURL(kHttpDifferentPathUrl)};
+  WebURLResponse response((GURL(kHttpUrl)));
   response.SetHttpStatusCode(307);
   data_provider()->WillFollowRedirect(url, response);
 
@@ -1476,8 +1476,8 @@
   Initialize(kHttpUrl, true);
 
   // Server responds with a redirect.
-  blink::WebURL url{GURL(kHttpDifferentPathUrl)};
-  blink::WebURLResponse response((GURL(kHttpUrl)));
+  WebURL url{GURL(kHttpDifferentPathUrl)};
+  WebURLResponse response((GURL(kHttpUrl)));
   response.SetHttpStatusCode(307);
   data_provider()->WillFollowRedirect(url, response);
 
@@ -1490,8 +1490,8 @@
   Initialize(kHttpUrl, false);
 
   // Server responds with a redirect.
-  blink::WebURL url{GURL(kHttpDifferentPathUrl)};
-  blink::WebURLResponse response((GURL(kHttpUrl)));
+  WebURL url{GURL(kHttpDifferentPathUrl)};
+  WebURLResponse response((GURL(kHttpUrl)));
   response.SetHttpStatusCode(307);
   data_provider()->WillFollowRedirect(url, response);
 
@@ -1529,7 +1529,7 @@
 TEST_F(MultiBufferDataSourceTest, FileSizeLessThanBlockSize) {
   Initialize(kHttpUrl, true);
   GURL gurl(kHttpUrl);
-  blink::WebURLResponse response(gurl);
+  WebURLResponse response(gurl);
   response.SetHttpStatusCode(200);
   response.SetHttpHeaderField(
       WebString::FromUTF8("Content-Length"),
diff --git a/third_party/blink/renderer/platform/media/new_session_cdm_result_promise.cc b/third_party/blink/renderer/platform/media/new_session_cdm_result_promise.cc
index 7783e43..1c09abb 100644
--- a/third_party/blink/renderer/platform/media/new_session_cdm_result_promise.cc
+++ b/third_party/blink/renderer/platform/media/new_session_cdm_result_promise.cc
@@ -32,24 +32,24 @@
 
 }  // namespace
 
-static blink::WebContentDecryptionModuleResult::SessionStatus ConvertStatus(
+static WebContentDecryptionModuleResult::SessionStatus ConvertStatus(
     SessionInitStatus status) {
   switch (status) {
     case SessionInitStatus::UNKNOWN_STATUS:
       break;
     case SessionInitStatus::NEW_SESSION:
-      return blink::WebContentDecryptionModuleResult::kNewSession;
+      return WebContentDecryptionModuleResult::kNewSession;
     case SessionInitStatus::SESSION_NOT_FOUND:
-      return blink::WebContentDecryptionModuleResult::kSessionNotFound;
+      return WebContentDecryptionModuleResult::kSessionNotFound;
     case SessionInitStatus::SESSION_ALREADY_EXISTS:
-      return blink::WebContentDecryptionModuleResult::kSessionAlreadyExists;
+      return WebContentDecryptionModuleResult::kSessionAlreadyExists;
   }
   NOTREACHED();
-  return blink::WebContentDecryptionModuleResult::kSessionNotFound;
+  return WebContentDecryptionModuleResult::kSessionNotFound;
 }
 
 NewSessionCdmResultPromise::NewSessionCdmResultPromise(
-    const blink::WebContentDecryptionModuleResult& result,
+    const WebContentDecryptionModuleResult& result,
     const std::string& key_system_uma_prefix,
     const std::string& uma_name,
     SessionInitializedCB new_session_created_cb,
@@ -102,7 +102,7 @@
                      ConvertCdmExceptionToResultForUMA(exception_code));
   web_cdm_result_.CompleteWithError(ConvertCdmException(exception_code),
                                     system_code,
-                                    blink::WebString::FromUTF8(error_message));
+                                    WebString::FromUTF8(error_message));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/media/new_session_cdm_result_promise.h b/third_party/blink/renderer/platform/media/new_session_cdm_result_promise.h
index d9ee42d..fe2a297 100644
--- a/third_party/blink/renderer/platform/media/new_session_cdm_result_promise.h
+++ b/third_party/blink/renderer/platform/media/new_session_cdm_result_promise.h
@@ -46,7 +46,7 @@
     : public media::CdmPromiseTemplate<std::string> {
  public:
   NewSessionCdmResultPromise(
-      const blink::WebContentDecryptionModuleResult& result,
+      const WebContentDecryptionModuleResult& result,
       const std::string& key_system_uma_prefix,
       const std::string& uma_name,
       SessionInitializedCB new_session_created_cb,
@@ -63,7 +63,7 @@
               const std::string& error_message) override;
 
  private:
-  blink::WebContentDecryptionModuleResult web_cdm_result_;
+  WebContentDecryptionModuleResult web_cdm_result_;
 
   // UMA prefix and name to report result and time to.
   std::string key_system_uma_prefix_;
diff --git a/third_party/blink/renderer/platform/media/remote_playback_client_wrapper_impl.cc b/third_party/blink/renderer/platform/media/remote_playback_client_wrapper_impl.cc
index 5724d224..09516ef 100644
--- a/third_party/blink/renderer/platform/media/remote_playback_client_wrapper_impl.cc
+++ b/third_party/blink/renderer/platform/media/remote_playback_client_wrapper_impl.cc
@@ -11,7 +11,7 @@
 namespace blink {
 
 RemotePlaybackClientWrapperImpl::RemotePlaybackClientWrapperImpl(
-    blink::WebMediaPlayerClient* client)
+    WebMediaPlayerClient* client)
     : remote_playback_client_(client->RemotePlaybackClient()) {}
 
 RemotePlaybackClientWrapperImpl::~RemotePlaybackClientWrapperImpl() = default;
diff --git a/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider.cc b/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider.cc
index b5f4b15..27c045a7 100644
--- a/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider.cc
+++ b/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider.cc
@@ -78,8 +78,8 @@
   // Prepare the request.
   WebURLRequest request(url_data_->url());
   request.SetRequestContext(is_client_audio_element_
-                                ? blink::mojom::RequestContextType::AUDIO
-                                : blink::mojom::RequestContextType::VIDEO);
+                                ? mojom::RequestContextType::AUDIO
+                                : mojom::RequestContextType::VIDEO);
   request.SetRequestDestination(
       is_client_audio_element_ ? network::mojom::RequestDestination::kAudio
                                : network::mojom::RequestDestination::kVideo);
@@ -90,14 +90,14 @@
 
   if (url_data_->length() == kPositionNotSpecified &&
       url_data_->CachedSize() == 0 && url_data_->BytesReadFromCache() == 0 &&
-      blink::WebNetworkStateNotifier::SaveDataEnabled() &&
+      WebNetworkStateNotifier::SaveDataEnabled() &&
       (url_data_->url().SchemeIs(url::kHttpScheme) ||
        url_data_->url().SchemeIs(url::kHttpsScheme))) {
     // This lets the data reduction proxy know that we don't have any previously
     // cached data for this resource. We can only send it if this is the first
     // request for this resource.
     request.SetPreviewsState(request.GetPreviewsState() |
-                             blink::PreviewsTypes::kSrcVideoRedirectOn);
+                             PreviewsTypes::kSrcVideoRedirectOn);
   }
 
   // We would like to send an if-match header with the request to
@@ -112,7 +112,7 @@
       WebString::FromUTF8("identity;q=1, *;q=0"));
 
   // Start resource loading.
-  blink::WebAssociatedURLLoaderOptions options;
+  WebAssociatedURLLoaderOptions options;
   if (url_data_->cors_mode() != UrlData::CORS_UNSPECIFIED) {
     options.expose_all_response_headers = true;
     // The author header set is empty, no preflight should go ahead.
@@ -173,7 +173,7 @@
 // WebAssociatedURLLoaderClient implementation.
 
 bool ResourceMultiBufferDataProvider::WillFollowRedirect(
-    const blink::WebURL& new_url,
+    const WebURL& new_url,
     const WebURLResponse& redirect_response) {
   DVLOG(1) << "willFollowRedirect";
   redirects_to_ = new_url;
diff --git a/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider.h b/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider.h
index 14a3920..888eafe 100644
--- a/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider.h
+++ b/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider.h
@@ -30,7 +30,7 @@
 
 class PLATFORM_EXPORT ResourceMultiBufferDataProvider
     : public MultiBuffer::DataProvider,
-      public blink::WebAssociatedURLLoaderClient {
+      public WebAssociatedURLLoaderClient {
  public:
   // NUmber of times we'll retry if the connection fails.
   enum { kMaxRetries = 30 };
@@ -52,16 +52,15 @@
   scoped_refptr<media::DataBuffer> Read() override;
   void SetDeferred(bool defer) override;
 
-  // blink::WebAssociatedURLLoaderClient implementation.
-  bool WillFollowRedirect(
-      const blink::WebURL& new_url,
-      const blink::WebURLResponse& redirect_response) override;
+  // WebAssociatedURLLoaderClient implementation.
+  bool WillFollowRedirect(const WebURL& new_url,
+                          const WebURLResponse& redirect_response) override;
   void DidSendData(uint64_t bytesSent, uint64_t totalBytesToBeSent) override;
-  void DidReceiveResponse(const blink::WebURLResponse& response) override;
+  void DidReceiveResponse(const WebURLResponse& response) override;
   void DidDownloadData(uint64_t data_length) override;
   void DidReceiveData(const char* data, int data_length) override;
   void DidFinishLoading() override;
-  void DidFail(const blink::WebURLError&) override;
+  void DidFail(const WebURLError&) override;
 
   // Use protected instead of private for testing purposes.
  protected:
@@ -86,7 +85,7 @@
   int64_t block_size() const;
 
   // If we have made a range request, verify the response from the server.
-  bool VerifyPartialResponse(const blink::WebURLResponse& response,
+  bool VerifyPartialResponse(const WebURLResponse& response,
                              const scoped_refptr<UrlData>& url_data);
 
   // Current Position.
@@ -114,7 +113,7 @@
 
   // Keeps track of an active WebAssociatedURLLoader.
   // Only valid while loading resource.
-  std::unique_ptr<blink::WebAssociatedURLLoader> active_loader_;
+  std::unique_ptr<WebAssociatedURLLoader> active_loader_;
 
   // When we encounter a redirect, this is the source of the redirect.
   GURL redirects_to_;
diff --git a/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider_unittest.cc b/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider_unittest.cc
index 1a9f727..e9dc878 100644
--- a/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider_unittest.cc
+++ b/third_party/blink/renderer/platform/media/resource_multi_buffer_data_provider_unittest.cc
@@ -55,9 +55,9 @@
 // Predicate that checks the Accept-Encoding request header and FRFR previews
 // state.
 static bool CorrectAcceptEncodingAndPreviewsState(
-    const blink::WebURLRequest& request) {
+    const WebURLRequest& request) {
   bool has_frfr =
-      request.GetPreviewsState() & blink::PreviewsTypes::kSrcVideoRedirectOn;
+      request.GetPreviewsState() & PreviewsTypes::kSrcVideoRedirectOn;
   if (has_frfr != want_frfr) {
     return false;
   }
@@ -171,8 +171,8 @@
   }
 
   void Redirect(const char* url) {
-    blink::WebURL new_url{GURL(url)};
-    blink::WebURLResponse redirect_response(gurl_);
+    WebURL new_url{GURL(url)};
+    WebURLResponse redirect_response(gurl_);
 
     EXPECT_CALL(*this, RedirectCallback(_))
         .WillOnce(
@@ -210,8 +210,8 @@
   }
 
  protected:
-  std::unique_ptr<blink::WebAssociatedURLLoader> CreateUrlLoader(
-      const blink::WebAssociatedURLLoaderOptions& options) {
+  std::unique_ptr<WebAssociatedURLLoader> CreateUrlLoader(
+      const WebAssociatedURLLoaderOptions& options) {
     auto url_loader = std::make_unique<NiceMock<MockWebAssociatedURLLoader>>();
     EXPECT_CALL(*url_loader.get(),
                 LoadAsynchronously(Truly(CorrectAcceptEncodingAndPreviewsState),
@@ -370,8 +370,7 @@
   };
   for (const TestCase& test_case : kTestCases) {
     SCOPED_TRACE(test_case.label);
-    blink::WebNetworkStateNotifier::SetSaveDataEnabled(
-        test_case.enable_save_data);
+    WebNetworkStateNotifier::SetSaveDataEnabled(test_case.enable_save_data);
 
     Initialize(test_case.url.c_str(), 0);
     want_frfr = test_case.want_frfr_previews_enabled;
diff --git a/third_party/blink/renderer/platform/media/testing/mock_resource_fetch_context.h b/third_party/blink/renderer/platform/media/testing/mock_resource_fetch_context.h
index 23b0c69..90c312b 100644
--- a/third_party/blink/renderer/platform/media/testing/mock_resource_fetch_context.h
+++ b/third_party/blink/renderer/platform/media/testing/mock_resource_fetch_context.h
@@ -18,8 +18,8 @@
   ~MockResourceFetchContext() override;
 
   MOCK_METHOD1(CreateUrlLoader,
-               std::unique_ptr<blink::WebAssociatedURLLoader>(
-                   const blink::WebAssociatedURLLoaderOptions&));
+               std::unique_ptr<WebAssociatedURLLoader>(
+                   const WebAssociatedURLLoaderOptions&));
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/media/testing/mock_web_associated_url_loader.h b/third_party/blink/renderer/platform/media/testing/mock_web_associated_url_loader.h
index dd5bfb8..faef0ecb 100644
--- a/third_party/blink/renderer/platform/media/testing/mock_web_associated_url_loader.h
+++ b/third_party/blink/renderer/platform/media/testing/mock_web_associated_url_loader.h
@@ -11,7 +11,7 @@
 
 namespace blink {
 
-class MockWebAssociatedURLLoader : public blink::WebAssociatedURLLoader {
+class MockWebAssociatedURLLoader : public WebAssociatedURLLoader {
  public:
   MockWebAssociatedURLLoader();
   MockWebAssociatedURLLoader(const MockWebAssociatedURLLoader&) = delete;
@@ -20,8 +20,8 @@
   ~MockWebAssociatedURLLoader() override;
 
   MOCK_METHOD2(LoadAsynchronously,
-               void(const blink::WebURLRequest& request,
-                    blink::WebAssociatedURLLoaderClient* client));
+               void(const WebURLRequest& request,
+                    WebAssociatedURLLoaderClient* client));
   MOCK_METHOD0(Cancel, void());
   MOCK_METHOD1(SetDefersLoading, void(bool value));
   MOCK_METHOD1(SetLoadingTaskRunner,
diff --git a/third_party/blink/renderer/platform/media/testing/test_response_generator.h b/third_party/blink/renderer/platform/media/testing/test_response_generator.h
index c2ca2523..5152648 100644
--- a/third_party/blink/renderer/platform/media/testing/test_response_generator.h
+++ b/third_party/blink/renderer/platform/media/testing/test_response_generator.h
@@ -31,44 +31,44 @@
   TestResponseGenerator& operator=(const TestResponseGenerator&) = delete;
 
   // Generates a WebURLError object.
-  blink::WebURLError GenerateError();
+  WebURLError GenerateError();
 
   // Generates a regular HTTP 200 response.
-  blink::WebURLResponse Generate200();
+  WebURLResponse Generate200();
 
   // Generates a regular HTTP 206 response starting from |first_byte_offset|
   // until the end of the resource.
-  blink::WebURLResponse Generate206(int64_t first_byte_offset);
+  WebURLResponse Generate206(int64_t first_byte_offset);
 
   // Generates a custom HTTP 206 response starting from |first_byte_offset|
   // until the end of the resource. You can tweak what gets included in the
   // headers via |flags|.
-  blink::WebURLResponse Generate206(int64_t first_byte_offset, Flags flags);
+  WebURLResponse Generate206(int64_t first_byte_offset, Flags flags);
 
   // Generates a regular HTTP 206 response starting from |first_byte_offset|
   // until |last_byte_offset|.
-  blink::WebURLResponse GeneratePartial206(int64_t first_byte_offset,
-                                           int64_t last_byte_offset);
+  WebURLResponse GeneratePartial206(int64_t first_byte_offset,
+                                    int64_t last_byte_offset);
 
   // Generates a custom HTTP 206 response starting from |first_byte_offset|
   // until |last_byte_offset|. You can tweak what gets included in the
   // headers via |flags|.
-  blink::WebURLResponse GeneratePartial206(int64_t first_byte_offset,
-                                           int64_t last_byte_offset,
-                                           Flags flags);
+  WebURLResponse GeneratePartial206(int64_t first_byte_offset,
+                                    int64_t last_byte_offset,
+                                    Flags flags);
 
   // Generates a regular HTTP 404 response.
-  blink::WebURLResponse Generate404();
+  WebURLResponse Generate404();
 
   // Generate a HTTP response with specified code.
-  blink::WebURLResponse GenerateResponse(int code);
+  WebURLResponse GenerateResponse(int code);
 
   // Generates a file:// response starting from |first_byte_offset| until the
   // end of the resource.
   //
   // If |first_byte_offset| is negative a response containing no content length
   // will be returned.
-  blink::WebURLResponse GenerateFileResponse(int64_t first_byte_offset);
+  WebURLResponse GenerateFileResponse(int64_t first_byte_offset);
 
   int64_t content_length() { return content_length_; }
 
diff --git a/third_party/blink/renderer/platform/media/text_track_impl.cc b/third_party/blink/renderer/platform/media/text_track_impl.cc
index 26939631..f6661c0 100644
--- a/third_party/blink/renderer/platform/media/text_track_impl.cc
+++ b/third_party/blink/renderer/platform/media/text_track_impl.cc
@@ -18,7 +18,7 @@
 
 TextTrackImpl::TextTrackImpl(
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
-    blink::WebMediaPlayerClient* client,
+    WebMediaPlayerClient* client,
     std::unique_ptr<WebInbandTextTrackImpl> text_track)
     : task_runner_(task_runner),
       client_(client),
@@ -48,16 +48,15 @@
                              const std::string& id,
                              const std::string& content,
                              const std::string& settings) {
-  if (blink::WebInbandTextTrackClient* client = text_track->Client()) {
+  if (WebInbandTextTrackClient* client = text_track->Client()) {
     client->AddWebVTTCue(start.InSecondsF(), end.InSecondsF(),
-                         blink::WebString::FromUTF8(id),
-                         blink::WebString::FromUTF8(content),
-                         blink::WebString::FromUTF8(settings));
+                         WebString::FromUTF8(id), WebString::FromUTF8(content),
+                         WebString::FromUTF8(settings));
   }
 }
 
 void TextTrackImpl::OnRemoveTrack(
-    blink::WebMediaPlayerClient* client,
+    WebMediaPlayerClient* client,
     std::unique_ptr<WebInbandTextTrackImpl> text_track) {
   if (text_track->Client())
     client->RemoveTextTrack(text_track.get());
diff --git a/third_party/blink/renderer/platform/media/text_track_impl.h b/third_party/blink/renderer/platform/media/text_track_impl.h
index 14895bd..31bf37cf 100644
--- a/third_party/blink/renderer/platform/media/text_track_impl.h
+++ b/third_party/blink/renderer/platform/media/text_track_impl.h
@@ -23,7 +23,7 @@
  public:
   // Constructor assumes ownership of the |text_track| object.
   TextTrackImpl(const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
-                blink::WebMediaPlayerClient* client,
+                WebMediaPlayerClient* client,
                 std::unique_ptr<WebInbandTextTrackImpl> text_track);
 
   TextTrackImpl(const TextTrackImpl&) = delete;
@@ -44,11 +44,11 @@
                        const std::string& content,
                        const std::string& settings);
 
-  static void OnRemoveTrack(blink::WebMediaPlayerClient* client,
+  static void OnRemoveTrack(WebMediaPlayerClient* client,
                             std::unique_ptr<WebInbandTextTrackImpl> text_track);
 
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-  blink::WebMediaPlayerClient* client_;
+  WebMediaPlayerClient* client_;
   std::unique_ptr<WebInbandTextTrackImpl> text_track_;
 };
 
diff --git a/third_party/blink/renderer/platform/media/video_frame_compositor.cc b/third_party/blink/renderer/platform/media/video_frame_compositor.cc
index ad1bb0e..925ea37 100644
--- a/third_party/blink/renderer/platform/media/video_frame_compositor.cc
+++ b/third_party/blink/renderer/platform/media/video_frame_compositor.cc
@@ -31,7 +31,7 @@
 
 VideoFrameCompositor::VideoFrameCompositor(
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
-    std::unique_ptr<blink::WebVideoFrameSubmitter> submitter)
+    std::unique_ptr<WebVideoFrameSubmitter> submitter)
     : task_runner_(task_runner),
       tick_clock_(base::DefaultTickClock::GetInstance()),
       background_rendering_timer_(
@@ -313,10 +313,10 @@
   submitter_->SetForceBeginFrames(false);
 }
 
-std::unique_ptr<blink::WebMediaPlayer::VideoFramePresentationMetadata>
+std::unique_ptr<WebMediaPlayer::VideoFramePresentationMetadata>
 VideoFrameCompositor::GetLastPresentedFrameMetadata() {
   auto frame_metadata =
-      std::make_unique<blink::WebMediaPlayer::VideoFramePresentationMetadata>();
+      std::make_unique<WebMediaPlayer::VideoFramePresentationMetadata>();
 
   scoped_refptr<media::VideoFrame> last_frame;
   {
diff --git a/third_party/blink/renderer/platform/media/video_frame_compositor_unittest.cc b/third_party/blink/renderer/platform/media/video_frame_compositor_unittest.cc
index b63afd3..2c4c639 100644
--- a/third_party/blink/renderer/platform/media/video_frame_compositor_unittest.cc
+++ b/third_party/blink/renderer/platform/media/video_frame_compositor_unittest.cc
@@ -31,9 +31,9 @@
 
 using RenderingMode = ::media::VideoRendererSink::RenderCallback::RenderingMode;
 
-class MockWebVideoFrameSubmitter : public blink::WebVideoFrameSubmitter {
+class MockWebVideoFrameSubmitter : public WebVideoFrameSubmitter {
  public:
-  // blink::WebVideoFrameSubmitter implementation.
+  // WebVideoFrameSubmitter implementation.
   void StopUsingProvider() override {}
   MOCK_METHOD1(EnableSubmission, void(viz::SurfaceId));
   MOCK_METHOD0(StartRendering, void());
diff --git a/third_party/blink/renderer/platform/media/watch_time_reporter_unittest.cc b/third_party/blink/renderer/platform/media/watch_time_reporter_unittest.cc
index f09c75d..fddf4b96 100644
--- a/third_party/blink/renderer/platform/media/watch_time_reporter_unittest.cc
+++ b/third_party/blink/renderer/platform/media/watch_time_reporter_unittest.cc
@@ -310,7 +310,7 @@
     if (wtr_ && IsMonitoring())
       EXPECT_WATCH_TIME_FINALIZED();
 
-    wtr_ = std::make_unique<blink::WatchTimeReporter>(
+    wtr_ = std::make_unique<WatchTimeReporter>(
         media::mojom::PlaybackProperties::New(
             has_audio_, has_video_, false, false, is_mse, is_encrypted, false,
             media::mojom::MediaStreamType::kNone),
@@ -319,8 +319,7 @@
                             base::Unretained(this)),
         base::BindRepeating(&WatchTimeReporterTest::GetPipelineStatistics,
                             base::Unretained(this)),
-        &fake_metrics_provider_,
-        blink::scheduler::GetSequencedTaskRunnerForTesting(),
+        &fake_metrics_provider_, scheduler::GetSequencedTaskRunnerForTesting(),
         task_environment_.GetMockTickClock());
     reporting_interval_ = wtr_->reporting_interval_;
 
@@ -372,7 +371,7 @@
             : wtr_->OnNativeControlsDisabled();
   }
 
-  void OnDisplayTypeChanged(blink::DisplayType display_type) {
+  void OnDisplayTypeChanged(DisplayType display_type) {
     wtr_->OnDisplayTypeChanged(display_type);
   }
 
@@ -443,7 +442,7 @@
     if (TestFlags & kStartWithNativeControls)
       OnNativeControlsEnabled(true);
     if (TestFlags & kStartWithDisplayFullscreen)
-      OnDisplayTypeChanged(blink::DisplayType::kFullscreen);
+      OnDisplayTypeChanged(DisplayType::kFullscreen);
 
     // Setup all current time expectations first since they need to use the
     // InSequence macro for ease of use, but we don't want the watch time
@@ -643,7 +642,7 @@
   const bool has_audio_;
 
   FakeMediaMetricsProvider fake_metrics_provider_;
-  std::unique_ptr<blink::WatchTimeReporter> wtr_;
+  std::unique_ptr<WatchTimeReporter> wtr_;
   base::TimeDelta reporting_interval_;
 };
 
@@ -1444,7 +1443,7 @@
   EXPECT_TRUE(IsBackgroundMonitoring());
   EXPECT_FALSE(IsMonitoring());
 
-  OnDisplayTypeChanged(blink::DisplayType::kFullscreen);
+  OnDisplayTypeChanged(DisplayType::kFullscreen);
 
   EXPECT_BACKGROUND_WATCH_TIME(Ac, kWatchTime1);
   EXPECT_BACKGROUND_WATCH_TIME(All, kWatchTime1);
@@ -1578,7 +1577,7 @@
     wtr_->OnPlaying();
     EXPECT_TRUE(IsMonitoring());
 
-    OnDisplayTypeChanged(blink::DisplayType::kFullscreen);
+    OnDisplayTypeChanged(DisplayType::kFullscreen);
     OnPowerStateChange(true);
 
     EXPECT_WATCH_TIME(Ac, kWatchTime1);
@@ -1620,7 +1619,7 @@
 
     OnNativeControlsEnabled(true);
     OnPowerStateChange(true);
-    OnDisplayTypeChanged(blink::DisplayType::kPictureInPicture);
+    OnDisplayTypeChanged(DisplayType::kPictureInPicture);
 
     EXPECT_WATCH_TIME(Ac, kWatchTime1);
     EXPECT_WATCH_TIME(All, kWatchTime1);
@@ -1861,7 +1860,7 @@
       .WillOnce(testing::Return(base::TimeDelta()))
       .WillOnce(testing::Return(kWatchTime));
   Initialize(false, false, kSizeJustRight);
-  OnDisplayTypeChanged(blink::DisplayType::kFullscreen);
+  OnDisplayTypeChanged(DisplayType::kFullscreen);
   wtr_->OnPlaying();
   SetOnBatteryPower(true);
   EXPECT_TRUE(IsMonitoring());
@@ -1879,7 +1878,7 @@
       .WillOnce(testing::Return(kWatchTime));
   Initialize(false, false, kSizeJustRight);
   OnNativeControlsEnabled(true);
-  OnDisplayTypeChanged(blink::DisplayType::kPictureInPicture);
+  OnDisplayTypeChanged(DisplayType::kPictureInPicture);
   wtr_->OnPlaying();
   EXPECT_TRUE(IsMonitoring());
   EXPECT_WATCH_TIME(Ac, kWatchTime);
@@ -2010,8 +2009,8 @@
   RunHysteresisTest<kAccumulationContinuesAfterTest |
                     kFinalizeExitDoesNotRequireCurrentTime |
                     kStartWithDisplayFullscreen>([this]() {
-    OnDisplayTypeChanged(blink::DisplayType::kInline);
-    OnDisplayTypeChanged(blink::DisplayType::kFullscreen);
+    OnDisplayTypeChanged(DisplayType::kInline);
+    OnDisplayTypeChanged(DisplayType::kFullscreen);
   });
 }
 
@@ -2019,15 +2018,15 @@
        OnDisplayTypeChangeHysteresisNativeFinalized) {
   RunHysteresisTest<kAccumulationContinuesAfterTest |
                     kFinalizeDisplayWatchTime | kStartWithDisplayFullscreen>(
-      [this]() { OnDisplayTypeChanged(blink::DisplayType::kInline); });
+      [this]() { OnDisplayTypeChanged(DisplayType::kInline); });
 }
 
 TEST_P(DisplayTypeWatchTimeReporterTest,
        OnDisplayTypeChangeHysteresisInlineContinuation) {
   RunHysteresisTest<kAccumulationContinuesAfterTest |
                     kFinalizeExitDoesNotRequireCurrentTime>([this]() {
-    OnDisplayTypeChanged(blink::DisplayType::kFullscreen);
-    OnDisplayTypeChanged(blink::DisplayType::kInline);
+    OnDisplayTypeChanged(DisplayType::kFullscreen);
+    OnDisplayTypeChanged(DisplayType::kInline);
   });
 }
 
@@ -2035,7 +2034,7 @@
        OnDisplayTypeChangeHysteresisNativeOffFinalized) {
   RunHysteresisTest<kAccumulationContinuesAfterTest |
                     kFinalizeDisplayWatchTime>(
-      [this]() { OnDisplayTypeChanged(blink::DisplayType::kFullscreen); });
+      [this]() { OnDisplayTypeChanged(DisplayType::kFullscreen); });
 }
 
 TEST_P(DisplayTypeWatchTimeReporterTest,
@@ -2043,14 +2042,14 @@
   RunHysteresisTest<kAccumulationContinuesAfterTest |
                     kFinalizeDisplayWatchTime | kStartWithDisplayFullscreen |
                     kTransitionDisplayWatchTime>(
-      [this]() { OnDisplayTypeChanged(blink::DisplayType::kInline); });
+      [this]() { OnDisplayTypeChanged(DisplayType::kInline); });
 }
 
 TEST_P(DisplayTypeWatchTimeReporterTest,
        OnDisplayTypeChangeFullscreenToInline) {
   RunHysteresisTest<kAccumulationContinuesAfterTest |
                     kFinalizeDisplayWatchTime | kTransitionDisplayWatchTime>(
-      [this]() { OnDisplayTypeChanged(blink::DisplayType::kFullscreen); });
+      [this]() { OnDisplayTypeChanged(DisplayType::kFullscreen); });
 }
 
 // Tests that the first finalize is the only one that matters.
@@ -2345,7 +2344,7 @@
   EXPECT_TRUE(IsMutedMonitoring());
   EXPECT_FALSE(IsMonitoring());
 
-  OnDisplayTypeChanged(blink::DisplayType::kFullscreen);
+  OnDisplayTypeChanged(DisplayType::kFullscreen);
   EXPECT_MUTED_WATCH_TIME_IF_AUDIO_VIDEO(Ac, kWatchTime1);
   EXPECT_MUTED_WATCH_TIME_IF_AUDIO_VIDEO(All, kWatchTime1);
   EXPECT_MUTED_WATCH_TIME_IF_AUDIO_VIDEO(Eme, kWatchTime1);
diff --git a/third_party/blink/renderer/platform/media/web_content_decryption_module_access_impl.cc b/third_party/blink/renderer/platform/media/web_content_decryption_module_access_impl.cc
index 767f8518..c9c7ca5d 100644
--- a/third_party/blink/renderer/platform/media/web_content_decryption_module_access_impl.cc
+++ b/third_party/blink/renderer/platform/media/web_content_decryption_module_access_impl.cc
@@ -17,15 +17,15 @@
 // The caller owns the created cdm (passed back using |result|).
 static void CreateCdm(
     const base::WeakPtr<WebEncryptedMediaClientImpl>& client,
-    const blink::WebString& key_system,
-    const blink::WebSecurityOrigin& security_origin,
+    const WebString& key_system,
+    const WebSecurityOrigin& security_origin,
     const media::CdmConfig& cdm_config,
-    std::unique_ptr<blink::WebContentDecryptionModuleResult> result) {
+    std::unique_ptr<WebContentDecryptionModuleResult> result) {
   // If |client| is gone (due to the frame getting destroyed), it is
   // impossible to create the CDM, so fail.
   if (!client) {
     result->CompleteWithError(
-        blink::kWebContentDecryptionModuleExceptionInvalidStateError, 0,
+        kWebContentDecryptionModuleExceptionInvalidStateError, 0,
         "Failed to create CDM.");
     return;
   }
@@ -36,15 +36,15 @@
 // static
 WebContentDecryptionModuleAccessImpl*
 WebContentDecryptionModuleAccessImpl::From(
-    blink::WebContentDecryptionModuleAccess* cdm_access) {
+    WebContentDecryptionModuleAccess* cdm_access) {
   return static_cast<WebContentDecryptionModuleAccessImpl*>(cdm_access);
 }
 
 std::unique_ptr<WebContentDecryptionModuleAccessImpl>
 WebContentDecryptionModuleAccessImpl::Create(
-    const blink::WebString& key_system,
-    const blink::WebSecurityOrigin& security_origin,
-    const blink::WebMediaKeySystemConfiguration& configuration,
+    const WebString& key_system,
+    const WebSecurityOrigin& security_origin,
+    const WebMediaKeySystemConfiguration& configuration,
     const media::CdmConfig& cdm_config,
     const base::WeakPtr<WebEncryptedMediaClientImpl>& client) {
   return std::make_unique<WebContentDecryptionModuleAccessImpl>(
@@ -52,9 +52,9 @@
 }
 
 WebContentDecryptionModuleAccessImpl::WebContentDecryptionModuleAccessImpl(
-    const blink::WebString& key_system,
-    const blink::WebSecurityOrigin& security_origin,
-    const blink::WebMediaKeySystemConfiguration& configuration,
+    const WebString& key_system,
+    const WebSecurityOrigin& security_origin,
+    const WebMediaKeySystemConfiguration& configuration,
     const media::CdmConfig& cdm_config,
     const base::WeakPtr<WebEncryptedMediaClientImpl>& client)
     : key_system_(key_system),
@@ -66,24 +66,24 @@
 WebContentDecryptionModuleAccessImpl::~WebContentDecryptionModuleAccessImpl() =
     default;
 
-blink::WebString WebContentDecryptionModuleAccessImpl::GetKeySystem() {
+WebString WebContentDecryptionModuleAccessImpl::GetKeySystem() {
   return key_system_;
 }
 
-blink::WebMediaKeySystemConfiguration
+WebMediaKeySystemConfiguration
 WebContentDecryptionModuleAccessImpl::GetConfiguration() {
   return configuration_;
 }
 
 void WebContentDecryptionModuleAccessImpl::CreateContentDecryptionModule(
-    blink::WebContentDecryptionModuleResult result,
+    WebContentDecryptionModuleResult result,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
   // This method needs to run asynchronously, as it may need to load the CDM.
   // As this object's lifetime is controlled by MediaKeySystemAccess on the
   // blink side, copy all values needed by CreateCdm() in case the blink object
   // gets garbage-collected.
-  std::unique_ptr<blink::WebContentDecryptionModuleResult> result_copy(
-      new blink::WebContentDecryptionModuleResult(result));
+  std::unique_ptr<WebContentDecryptionModuleResult> result_copy(
+      new WebContentDecryptionModuleResult(result));
   task_runner->PostTask(
       FROM_HERE,
       base::BindOnce(&CreateCdm, client_, key_system_, security_origin_,
diff --git a/third_party/blink/renderer/platform/media/web_content_decryption_module_access_impl.h b/third_party/blink/renderer/platform/media/web_content_decryption_module_access_impl.h
index 19b6d0e51..f985fb3 100644
--- a/third_party/blink/renderer/platform/media/web_content_decryption_module_access_impl.h
+++ b/third_party/blink/renderer/platform/media/web_content_decryption_module_access_impl.h
@@ -20,22 +20,22 @@
 class WebEncryptedMediaClientImpl;
 
 class PLATFORM_EXPORT WebContentDecryptionModuleAccessImpl
-    : public blink::WebContentDecryptionModuleAccess {
+    : public WebContentDecryptionModuleAccess {
  public:
   // Allow typecasting from blink type as this is the only implementation.
   static WebContentDecryptionModuleAccessImpl* From(
-      blink::WebContentDecryptionModuleAccess* cdm_access);
+      WebContentDecryptionModuleAccess* cdm_access);
 
   static std::unique_ptr<WebContentDecryptionModuleAccessImpl> Create(
-      const blink::WebString& key_system,
-      const blink::WebSecurityOrigin& security_origin,
-      const blink::WebMediaKeySystemConfiguration& configuration,
+      const WebString& key_system,
+      const WebSecurityOrigin& security_origin,
+      const WebMediaKeySystemConfiguration& configuration,
       const media::CdmConfig& cdm_config,
       const base::WeakPtr<WebEncryptedMediaClientImpl>& client);
   WebContentDecryptionModuleAccessImpl(
-      const blink::WebString& key_system,
-      const blink::WebSecurityOrigin& security_origin,
-      const blink::WebMediaKeySystemConfiguration& configuration,
+      const WebString& key_system,
+      const WebSecurityOrigin& security_origin,
+      const WebMediaKeySystemConfiguration& configuration,
       const media::CdmConfig& cdm_config,
       const base::WeakPtr<WebEncryptedMediaClientImpl>& client);
   WebContentDecryptionModuleAccessImpl(
@@ -44,18 +44,18 @@
       const WebContentDecryptionModuleAccessImpl&) = delete;
   ~WebContentDecryptionModuleAccessImpl() override;
 
-  // blink::WebContentDecryptionModuleAccess interface.
-  blink::WebString GetKeySystem() override;
-  blink::WebMediaKeySystemConfiguration GetConfiguration() override;
+  // WebContentDecryptionModuleAccess interface.
+  WebString GetKeySystem() override;
+  WebMediaKeySystemConfiguration GetConfiguration() override;
   void CreateContentDecryptionModule(
-      blink::WebContentDecryptionModuleResult result,
+      WebContentDecryptionModuleResult result,
       scoped_refptr<base::SingleThreadTaskRunner> task_runner) override;
   bool UseHardwareSecureCodecs() const override;
 
  private:
-  const blink::WebString key_system_;
-  const blink::WebSecurityOrigin security_origin_;
-  const blink::WebMediaKeySystemConfiguration configuration_;
+  const WebString key_system_;
+  const WebSecurityOrigin security_origin_;
+  const WebMediaKeySystemConfiguration configuration_;
   const media::CdmConfig cdm_config_;
 
   // Keep a WeakPtr as client is owned by render_frame_impl.
diff --git a/third_party/blink/renderer/platform/media/web_content_decryption_module_impl.cc b/third_party/blink/renderer/platform/media/web_content_decryption_module_impl.cc
index ed555ae..8f8b523 100644
--- a/third_party/blink/renderer/platform/media/web_content_decryption_module_impl.cc
+++ b/third_party/blink/renderer/platform/media/web_content_decryption_module_impl.cc
@@ -31,7 +31,7 @@
 const char kSetServerCertificateUMAName[] = "SetServerCertificate";
 const char kGetStatusForPolicyUMAName[] = "GetStatusForPolicy";
 
-bool ConvertHdcpVersion(const blink::WebString& hdcp_version_string,
+bool ConvertHdcpVersion(const WebString& hdcp_version_string,
                         media::HdcpVersion* hdcp_version) {
   if (!hdcp_version_string.ContainsOnlyASCII())
     return false;
@@ -71,7 +71,7 @@
 void WebContentDecryptionModuleImpl::Create(
     media::CdmFactory* cdm_factory,
     const std::u16string& key_system,
-    const blink::WebSecurityOrigin& security_origin,
+    const WebSecurityOrigin& security_origin,
     const media::CdmConfig& cdm_config,
     WebCdmCreatedCB web_cdm_created_cb) {
   DCHECK(!security_origin.IsNull());
@@ -118,9 +118,9 @@
 
 WebContentDecryptionModuleImpl::~WebContentDecryptionModuleImpl() = default;
 
-std::unique_ptr<blink::WebContentDecryptionModuleSession>
+std::unique_ptr<WebContentDecryptionModuleSession>
 WebContentDecryptionModuleImpl::CreateSession(
-    blink::WebEncryptedMediaSessionType session_type) {
+    WebEncryptedMediaSessionType session_type) {
   base::UmaHistogramEnumeration(
       adapter_->GetKeySystemUMAPrefix() + kCreateSessionSessionTypeUMAName,
       session_type);
@@ -130,7 +130,7 @@
 void WebContentDecryptionModuleImpl::SetServerCertificate(
     const uint8_t* server_certificate,
     size_t server_certificate_length,
-    blink::WebContentDecryptionModuleResult result) {
+    WebContentDecryptionModuleResult result) {
   DCHECK(server_certificate);
   adapter_->SetServerCertificate(
       std::vector<uint8_t>(server_certificate,
@@ -141,13 +141,12 @@
 }
 
 void WebContentDecryptionModuleImpl::GetStatusForPolicy(
-    const blink::WebString& min_hdcp_version_string,
-    blink::WebContentDecryptionModuleResult result) {
+    const WebString& min_hdcp_version_string,
+    WebContentDecryptionModuleResult result) {
   media::HdcpVersion min_hdcp_version;
   if (!ConvertHdcpVersion(min_hdcp_version_string, &min_hdcp_version)) {
-    result.CompleteWithError(
-        blink::kWebContentDecryptionModuleExceptionTypeError, 0,
-        "Invalid HDCP version");
+    result.CompleteWithError(kWebContentDecryptionModuleExceptionTypeError, 0,
+                             "Invalid HDCP version");
     return;
   }
 
diff --git a/third_party/blink/renderer/platform/media/web_content_decryption_module_impl.h b/third_party/blink/renderer/platform/media/web_content_decryption_module_impl.h
index 3797a1e..3d53d9f 100644
--- a/third_party/blink/renderer/platform/media/web_content_decryption_module_impl.h
+++ b/third_party/blink/renderer/platform/media/web_content_decryption_module_impl.h
@@ -28,15 +28,15 @@
 class WebSecurityOrigin;
 
 using WebCdmCreatedCB =
-    base::OnceCallback<void(blink::WebContentDecryptionModule* cdm,
+    base::OnceCallback<void(WebContentDecryptionModule* cdm,
                             const std::string& error_message)>;
 
 class PLATFORM_EXPORT WebContentDecryptionModuleImpl
-    : public blink::WebContentDecryptionModule {
+    : public WebContentDecryptionModule {
  public:
   static void Create(media::CdmFactory* cdm_factory,
                      const std::u16string& key_system,
-                     const blink::WebSecurityOrigin& security_origin,
+                     const WebSecurityOrigin& security_origin,
                      const media::CdmConfig& cdm_config,
                      WebCdmCreatedCB web_cdm_created_cb);
 
@@ -46,16 +46,14 @@
       const WebContentDecryptionModuleImpl&) = delete;
   ~WebContentDecryptionModuleImpl() override;
 
-  // blink::WebContentDecryptionModule implementation.
-  std::unique_ptr<blink::WebContentDecryptionModuleSession> CreateSession(
-      blink::WebEncryptedMediaSessionType session_type) override;
-  void SetServerCertificate(
-      const uint8_t* server_certificate,
-      size_t server_certificate_length,
-      blink::WebContentDecryptionModuleResult result) override;
-  void GetStatusForPolicy(
-      const blink::WebString& min_hdcp_version_string,
-      blink::WebContentDecryptionModuleResult result) override;
+  // WebContentDecryptionModule implementation.
+  std::unique_ptr<WebContentDecryptionModuleSession> CreateSession(
+      WebEncryptedMediaSessionType session_type) override;
+  void SetServerCertificate(const uint8_t* server_certificate,
+                            size_t server_certificate_length,
+                            WebContentDecryptionModuleResult result) override;
+  void GetStatusForPolicy(const WebString& min_hdcp_version_string,
+                          WebContentDecryptionModuleResult result) override;
 
   std::unique_ptr<media::CdmContextRef> GetCdmContextRef();
 
@@ -75,7 +73,7 @@
 // Allow typecasting from blink type as this is the only implementation.
 PLATFORM_EXPORT
 inline WebContentDecryptionModuleImpl* ToWebContentDecryptionModuleImpl(
-    blink::WebContentDecryptionModule* cdm) {
+    WebContentDecryptionModule* cdm) {
   return static_cast<WebContentDecryptionModuleImpl*>(cdm);
 }
 
diff --git a/third_party/blink/renderer/platform/media/web_content_decryption_module_session_impl.cc b/third_party/blink/renderer/platform/media/web_content_decryption_module_session_impl.cc
index 9f6cb4f..b4e53f5 100644
--- a/third_party/blink/renderer/platform/media/web_content_decryption_module_session_impl.cc
+++ b/third_party/blink/renderer/platform/media/web_content_decryption_module_session_impl.cc
@@ -43,13 +43,13 @@
 const char kKeyStatusSystemCodeUMAName[] = "KeyStatusSystemCode";
 
 media::CdmSessionType ConvertSessionType(
-    blink::WebEncryptedMediaSessionType session_type) {
+    WebEncryptedMediaSessionType session_type) {
   switch (session_type) {
-    case blink::WebEncryptedMediaSessionType::kTemporary:
+    case WebEncryptedMediaSessionType::kTemporary:
       return media::CdmSessionType::kTemporary;
-    case blink::WebEncryptedMediaSessionType::kPersistentLicense:
+    case WebEncryptedMediaSessionType::kPersistentLicense:
       return media::CdmSessionType::kPersistentLicense;
-    case blink::WebEncryptedMediaSessionType::kUnknown:
+    case WebEncryptedMediaSessionType::kUnknown:
       break;
   }
 
@@ -116,7 +116,7 @@
   return false;
 }
 
-bool SanitizeSessionId(const blink::WebString& session_id,
+bool SanitizeSessionId(const WebString& session_id,
                        std::string* sanitized_session_id) {
   // The user agent should thoroughly validate the sessionId value before
   // passing it to the CDM. At a minimum, this should include checking that
@@ -185,7 +185,7 @@
 
 WebContentDecryptionModuleSessionImpl::WebContentDecryptionModuleSessionImpl(
     const scoped_refptr<CdmSessionAdapter>& adapter,
-    blink::WebEncryptedMediaSessionType session_type)
+    WebEncryptedMediaSessionType session_type)
     : adapter_(adapter),
       session_type_(ConvertSessionType(session_type)),
       has_close_been_called_(false),
@@ -220,15 +220,15 @@
   client_ = client;
 }
 
-blink::WebString WebContentDecryptionModuleSessionImpl::SessionId() const {
-  return blink::WebString::FromUTF8(session_id_);
+WebString WebContentDecryptionModuleSessionImpl::SessionId() const {
+  return WebString::FromUTF8(session_id_);
 }
 
 void WebContentDecryptionModuleSessionImpl::InitializeNewSession(
     media::EmeInitDataType eme_init_data_type,
     const unsigned char* init_data,
     size_t init_data_length,
-    blink::WebContentDecryptionModuleResult result) {
+    WebContentDecryptionModuleResult result) {
   DCHECK(init_data);
   DCHECK(session_id_.empty());
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
@@ -243,8 +243,8 @@
     std::string message =
         "The initialization data type is not supported by the key system.";
     result.CompleteWithError(
-        blink::kWebContentDecryptionModuleExceptionNotSupportedError, 0,
-        blink::WebString::FromUTF8(message));
+        kWebContentDecryptionModuleExceptionNotSupportedError, 0,
+        WebString::FromUTF8(message));
     return;
   }
 
@@ -267,9 +267,8 @@
   std::string message;
   if (!SanitizeInitData(eme_init_data_type, init_data, init_data_length,
                         &sanitized_init_data, &message)) {
-    result.CompleteWithError(
-        blink::kWebContentDecryptionModuleExceptionTypeError, 0,
-        blink::WebString::FromUTF8(message));
+    result.CompleteWithError(kWebContentDecryptionModuleExceptionTypeError, 0,
+                             WebString::FromUTF8(message));
     return;
   }
 
@@ -277,7 +276,7 @@
   //      NotSupportedError.
   if (sanitized_init_data.empty()) {
     result.CompleteWithError(
-        blink::kWebContentDecryptionModuleExceptionNotSupportedError, 0,
+        kWebContentDecryptionModuleExceptionNotSupportedError, 0,
         "No initialization data provided.");
     return;
   }
@@ -305,8 +304,8 @@
 }
 
 void WebContentDecryptionModuleSessionImpl::Load(
-    const blink::WebString& session_id,
-    blink::WebContentDecryptionModuleResult result) {
+    const WebString& session_id,
+    WebContentDecryptionModuleResult result) {
   DCHECK(!session_id.IsEmpty());
   DCHECK(session_id_.empty());
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
@@ -321,9 +320,8 @@
   //     reject promise with a newly created TypeError.
   std::string sanitized_session_id;
   if (!SanitizeSessionId(session_id, &sanitized_session_id)) {
-    result.CompleteWithError(
-        blink::kWebContentDecryptionModuleExceptionTypeError, 0,
-        "Invalid session ID.");
+    result.CompleteWithError(kWebContentDecryptionModuleExceptionTypeError, 0,
+                             "Invalid session ID.");
     return;
   }
 
@@ -342,7 +340,7 @@
 void WebContentDecryptionModuleSessionImpl::Update(
     const uint8_t* response,
     size_t response_length,
-    blink::WebContentDecryptionModuleResult result) {
+    WebContentDecryptionModuleResult result) {
   DCHECK(response);
   DCHECK(!session_id_.empty());
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
@@ -360,9 +358,8 @@
   std::vector<uint8_t> sanitized_response;
   if (!SanitizeResponse(adapter_->GetKeySystem(), response, response_length,
                         &sanitized_response)) {
-    result.CompleteWithError(
-        blink::kWebContentDecryptionModuleExceptionTypeError, 0,
-        "Invalid response.");
+    result.CompleteWithError(kWebContentDecryptionModuleExceptionTypeError, 0,
+                             "Invalid response.");
     return;
   }
 
@@ -373,7 +370,7 @@
 }
 
 void WebContentDecryptionModuleSessionImpl::Close(
-    blink::WebContentDecryptionModuleResult result) {
+    WebContentDecryptionModuleResult result) {
   DCHECK(!session_id_.empty());
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
@@ -395,7 +392,7 @@
 }
 
 void WebContentDecryptionModuleSessionImpl::Remove(
-    blink::WebContentDecryptionModuleResult result) {
+    WebContentDecryptionModuleResult result) {
   DCHECK(!session_id_.empty());
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
@@ -417,12 +414,11 @@
     bool has_additional_usable_key,
     media::CdmKeysInfo keys_info) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  blink::WebVector<blink::WebEncryptedMediaKeyInformation> keys(
-      keys_info.size());
+  WebVector<WebEncryptedMediaKeyInformation> keys(keys_info.size());
   for (size_t i = 0; i < keys_info.size(); ++i) {
     auto& key_info = keys_info[i];
-    keys[i].SetId(blink::WebData(reinterpret_cast<char*>(&key_info->key_id[0]),
-                                 key_info->key_id.size()));
+    keys[i].SetId(WebData(reinterpret_cast<char*>(&key_info->key_id[0]),
+                          key_info->key_id.size()));
     keys[i].SetStatus(ConvertCdmKeyStatus(key_info->status));
     keys[i].SetSystemCode(key_info->system_code);
 
diff --git a/third_party/blink/renderer/platform/media/web_content_decryption_module_session_impl.h b/third_party/blink/renderer/platform/media/web_content_decryption_module_session_impl.h
index 694b1bf..8586a5d9e 100644
--- a/third_party/blink/renderer/platform/media/web_content_decryption_module_session_impl.h
+++ b/third_party/blink/renderer/platform/media/web_content_decryption_module_session_impl.h
@@ -25,33 +25,32 @@
 class CdmSessionAdapter;
 
 class PLATFORM_EXPORT WebContentDecryptionModuleSessionImpl
-    : public blink::WebContentDecryptionModuleSession {
+    : public WebContentDecryptionModuleSession {
  public:
   WebContentDecryptionModuleSessionImpl(
       const scoped_refptr<CdmSessionAdapter>& adapter,
-      blink::WebEncryptedMediaSessionType session_type);
+      WebEncryptedMediaSessionType session_type);
   WebContentDecryptionModuleSessionImpl(
       const WebContentDecryptionModuleSessionImpl&) = delete;
   WebContentDecryptionModuleSessionImpl& operator=(
       const WebContentDecryptionModuleSessionImpl&) = delete;
   ~WebContentDecryptionModuleSessionImpl() override;
 
-  // blink::WebContentDecryptionModuleSession implementation.
+  // WebContentDecryptionModuleSession implementation.
   void SetClientInterface(Client* client) override;
-  blink::WebString SessionId() const override;
+  WebString SessionId() const override;
 
-  void InitializeNewSession(
-      media::EmeInitDataType init_data_type,
-      const unsigned char* initData,
-      size_t initDataLength,
-      blink::WebContentDecryptionModuleResult result) override;
-  void Load(const blink::WebString& session_id,
-            blink::WebContentDecryptionModuleResult result) override;
+  void InitializeNewSession(media::EmeInitDataType init_data_type,
+                            const unsigned char* initData,
+                            size_t initDataLength,
+                            WebContentDecryptionModuleResult result) override;
+  void Load(const WebString& session_id,
+            WebContentDecryptionModuleResult result) override;
   void Update(const uint8_t* response,
               size_t response_length,
-              blink::WebContentDecryptionModuleResult result) override;
-  void Close(blink::WebContentDecryptionModuleResult result) override;
-  void Remove(blink::WebContentDecryptionModuleResult result) override;
+              WebContentDecryptionModuleResult result) override;
+  void Close(WebContentDecryptionModuleResult result) override;
+  void Remove(WebContentDecryptionModuleResult result) override;
 
   // Callbacks.
   void OnSessionMessage(media::CdmMessageType message_type,
diff --git a/third_party/blink/renderer/platform/media/web_encrypted_media_client_impl.cc b/third_party/blink/renderer/platform/media/web_encrypted_media_client_impl.cc
index bc50a8511..a2602ab 100644
--- a/third_party/blink/renderer/platform/media/web_encrypted_media_client_impl.cc
+++ b/third_party/blink/renderer/platform/media/web_encrypted_media_client_impl.cc
@@ -28,18 +28,18 @@
 const char kKeySystemSupportUMAPrefix[] =
     "Media.EME.RequestMediaKeySystemAccess.";
 
-// A helper function to complete blink::WebContentDecryptionModuleResult. Used
-// to convert blink::WebContentDecryptionModuleResult to a callback.
+// A helper function to complete WebContentDecryptionModuleResult. Used
+// to convert WebContentDecryptionModuleResult to a callback.
 void CompleteWebContentDecryptionModuleResult(
-    std::unique_ptr<blink::WebContentDecryptionModuleResult> result,
-    blink::WebContentDecryptionModule* cdm,
+    std::unique_ptr<WebContentDecryptionModuleResult> result,
+    WebContentDecryptionModule* cdm,
     const std::string& error_message) {
   DCHECK(result);
 
   if (!cdm) {
     result->CompleteWithError(
-        blink::kWebContentDecryptionModuleExceptionNotSupportedError, 0,
-        blink::WebString::FromUTF8(error_message));
+        kWebContentDecryptionModuleExceptionNotSupportedError, 0,
+        WebString::FromUTF8(error_message));
     return;
   }
 
@@ -109,7 +109,7 @@
 WebEncryptedMediaClientImpl::~WebEncryptedMediaClientImpl() = default;
 
 void WebEncryptedMediaClientImpl::RequestMediaKeySystemAccess(
-    blink::WebEncryptedMediaRequest request) {
+    WebEncryptedMediaRequest request) {
   GetReporter(request.KeySystem())->ReportRequested();
 
   key_system_config_selector_.SelectConfig(
@@ -119,10 +119,10 @@
 }
 
 void WebEncryptedMediaClientImpl::CreateCdm(
-    const blink::WebString& key_system,
-    const blink::WebSecurityOrigin& security_origin,
+    const WebString& key_system,
+    const WebSecurityOrigin& security_origin,
     const media::CdmConfig& cdm_config,
-    std::unique_ptr<blink::WebContentDecryptionModuleResult> result) {
+    std::unique_ptr<WebContentDecryptionModuleResult> result) {
   WebContentDecryptionModuleImpl::Create(
       cdm_factory_, key_system.Utf16(), security_origin, cdm_config,
       base::BindOnce(&CompleteWebContentDecryptionModuleResult,
@@ -130,9 +130,9 @@
 }
 
 void WebEncryptedMediaClientImpl::OnConfigSelected(
-    blink::WebEncryptedMediaRequest request,
+    WebEncryptedMediaRequest request,
     KeySystemConfigSelector::Status status,
-    blink::WebMediaKeySystemConfiguration* accumulated_configuration,
+    WebMediaKeySystemConfiguration* accumulated_configuration,
     media::CdmConfig* cdm_config) {
   // Update encrypted_media_supported_types_browsertest.cc if updating these
   // strings.
@@ -159,7 +159,7 @@
   // requestMediaKeySystemAccess request succeeding. However, the blink
   // objects may have been cleared, so check if this is the case and simply
   // reject the request.
-  blink::WebSecurityOrigin origin = request.GetSecurityOrigin();
+  WebSecurityOrigin origin = request.GetSecurityOrigin();
   if (origin.IsNull()) {
     request.RequestNotSupported("Unable to create MediaKeySystemAccess");
     return;
@@ -171,7 +171,7 @@
 }
 
 WebEncryptedMediaClientImpl::Reporter* WebEncryptedMediaClientImpl::GetReporter(
-    const blink::WebString& key_system) {
+    const WebString& key_system) {
   // Assumes that empty will not be found by GetKeySystemNameForUMA().
   // TODO(sandersd): Avoid doing ASCII conversion more than once.
   std::string key_system_ascii;
diff --git a/third_party/blink/renderer/platform/media/web_inband_text_track_impl.cc b/third_party/blink/renderer/platform/media/web_inband_text_track_impl.cc
index d5d79bd..4aa2c060 100644
--- a/third_party/blink/renderer/platform/media/web_inband_text_track_impl.cc
+++ b/third_party/blink/renderer/platform/media/web_inband_text_track_impl.cc
@@ -9,9 +9,9 @@
 namespace blink {
 
 WebInbandTextTrackImpl::WebInbandTextTrackImpl(Kind kind,
-                                               const blink::WebString& label,
-                                               const blink::WebString& language,
-                                               const blink::WebString& id)
+                                               const WebString& label,
+                                               const WebString& language,
+                                               const WebString& id)
     : client_(nullptr),
       kind_(kind),
       label_(label),
@@ -22,12 +22,11 @@
   DCHECK(!client_);
 }
 
-void WebInbandTextTrackImpl::SetClient(
-    blink::WebInbandTextTrackClient* client) {
+void WebInbandTextTrackImpl::SetClient(WebInbandTextTrackClient* client) {
   client_ = client;
 }
 
-blink::WebInbandTextTrackClient* WebInbandTextTrackImpl::Client() {
+WebInbandTextTrackClient* WebInbandTextTrackImpl::Client() {
   return client_;
 }
 
@@ -35,15 +34,15 @@
   return kind_;
 }
 
-blink::WebString WebInbandTextTrackImpl::Label() const {
+WebString WebInbandTextTrackImpl::Label() const {
   return label_;
 }
 
-blink::WebString WebInbandTextTrackImpl::Language() const {
+WebString WebInbandTextTrackImpl::Language() const {
   return language_;
 }
 
-blink::WebString WebInbandTextTrackImpl::Id() const {
+WebString WebInbandTextTrackImpl::Id() const {
   return id_;
 }
 
diff --git a/third_party/blink/renderer/platform/media/web_inband_text_track_impl.h b/third_party/blink/renderer/platform/media/web_inband_text_track_impl.h
index d697458..2612809 100644
--- a/third_party/blink/renderer/platform/media/web_inband_text_track_impl.h
+++ b/third_party/blink/renderer/platform/media/web_inband_text_track_impl.h
@@ -11,32 +11,31 @@
 
 namespace blink {
 
-class PLATFORM_EXPORT WebInbandTextTrackImpl
-    : public blink::WebInbandTextTrack {
+class PLATFORM_EXPORT WebInbandTextTrackImpl : public WebInbandTextTrack {
  public:
   WebInbandTextTrackImpl(Kind kind,
-                         const blink::WebString& label,
-                         const blink::WebString& language,
-                         const blink::WebString& id);
+                         const WebString& label,
+                         const WebString& language,
+                         const WebString& id);
   WebInbandTextTrackImpl(const WebInbandTextTrackImpl&) = delete;
   WebInbandTextTrackImpl& operator=(const WebInbandTextTrackImpl&) = delete;
   ~WebInbandTextTrackImpl() override;
 
-  void SetClient(blink::WebInbandTextTrackClient* client) override;
-  blink::WebInbandTextTrackClient* Client() override;
+  void SetClient(WebInbandTextTrackClient* client) override;
+  WebInbandTextTrackClient* Client() override;
 
   Kind GetKind() const override;
 
-  blink::WebString Label() const override;
-  blink::WebString Language() const override;
-  blink::WebString Id() const override;
+  WebString Label() const override;
+  WebString Language() const override;
+  WebString Id() const override;
 
  private:
-  blink::WebInbandTextTrackClient* client_;
+  WebInbandTextTrackClient* client_;
   Kind kind_;
-  blink::WebString label_;
-  blink::WebString language_;
-  blink::WebString id_;
+  WebString label_;
+  WebString language_;
+  WebString id_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/media/web_media_player_impl.cc b/third_party/blink/renderer/platform/media/web_media_player_impl.cc
index 3ececbd..1811469 100644
--- a/third_party/blink/renderer/platform/media/web_media_player_impl.cc
+++ b/third_party/blink/renderer/platform/media/web_media_player_impl.cc
@@ -109,10 +109,9 @@
   UMA_HISTOGRAM_ENUMERATION(kWatchTimeHistogram, type);
 }
 
-void SetSinkIdOnMediaThread(
-    scoped_refptr<blink::WebAudioSourceProviderImpl> sink,
-    const std::string& device_id,
-    media::OutputDeviceStatusCB callback) {
+void SetSinkIdOnMediaThread(scoped_refptr<WebAudioSourceProviderImpl> sink,
+                            const std::string& device_id,
+                            media::OutputDeviceStatusCB callback) {
   sink->SwitchOutputDevice(device_id, std::move(callback));
 }
 
@@ -132,11 +131,11 @@
   return base::FeatureList::IsEnabled(media::kBackgroundVideoPauseOptimization);
 }
 
-bool IsNetworkStateError(blink::WebMediaPlayer::NetworkState state) {
-  bool result = state == blink::WebMediaPlayer::kNetworkStateFormatError ||
-                state == blink::WebMediaPlayer::kNetworkStateNetworkError ||
-                state == blink::WebMediaPlayer::kNetworkStateDecodeError;
-  DCHECK_EQ(state > blink::WebMediaPlayer::kNetworkStateLoaded, result);
+bool IsNetworkStateError(WebMediaPlayer::NetworkState state) {
+  bool result = state == WebMediaPlayer::kNetworkStateFormatError ||
+                state == WebMediaPlayer::kNetworkStateNetworkError ||
+                state == WebMediaPlayer::kNetworkStateDecodeError;
+  DCHECK_EQ(state > WebMediaPlayer::kNetworkStateLoaded, result);
   return result;
 }
 
@@ -171,11 +170,11 @@
     case media::MediaObserverClient::ReasonToSwitchToLocal::PIPELINE_ERROR:
       return IDS_MEDIA_REMOTING_STOP_BY_ERROR_TEXT;
     case media::MediaObserverClient::ReasonToSwitchToLocal::ROUTE_TERMINATED:
-      return blink::WebMediaPlayerClient::kMediaRemotingStopNoText;
+      return WebMediaPlayerClient::kMediaRemotingStopNoText;
   }
   NOTREACHED();
   // To suppress compiler warning on Windows.
-  return blink::WebMediaPlayerClient::kMediaRemotingStopNoText;
+  return WebMediaPlayerClient::kMediaRemotingStopNoText;
 }
 
 // These values are persisted to UMA. Entries should not be renumbered and
@@ -215,7 +214,7 @@
     std::unique_ptr<media::CdmContextRef> cdm_context_2,
     std::unique_ptr<media::MediaLog> media_log,
     std::unique_ptr<media::RendererFactorySelector> renderer_factory_selector,
-    std::unique_ptr<blink::WebSurfaceLayerBridge> bridge,
+    std::unique_ptr<WebSurfaceLayerBridge> bridge,
     bool is_chunk_demuxer) {
   // We release |bridge| after pipeline stop to ensure layout tests receive
   // painted video frames before test harness exit.
@@ -267,7 +266,7 @@
           std::move(media_log)));
 }
 
-std::string SanitizeUserStringProperty(blink::WebString value) {
+std::string SanitizeUserStringProperty(WebString value) {
   std::string converted = value.Utf8();
   return base::IsStringUTF8(converted) ? converted : "[invalid property]";
 }
@@ -338,17 +337,16 @@
                    UrlData::CORS_USE_CREDENTIALS);
 
 WebMediaPlayerImpl::WebMediaPlayerImpl(
-    blink::WebLocalFrame* frame,
-    blink::WebMediaPlayerClient* client,
-    blink::WebMediaPlayerEncryptedMediaClient* encrypted_client,
-    blink::WebMediaPlayerDelegate* delegate,
+    WebLocalFrame* frame,
+    WebMediaPlayerClient* client,
+    WebMediaPlayerEncryptedMediaClient* encrypted_client,
+    WebMediaPlayerDelegate* delegate,
     std::unique_ptr<media::RendererFactorySelector> renderer_factory_selector,
     UrlIndex* url_index,
     std::unique_ptr<VideoFrameCompositor> compositor,
     std::unique_ptr<WebMediaPlayerParams> params)
     : frame_(frame),
-      main_task_runner_(
-          frame->GetTaskRunner(blink::TaskType::kMediaElementEvent)),
+      main_task_runner_(frame->GetTaskRunner(TaskType::kMediaElementEvent)),
       media_task_runner_(params->media_task_runner()),
       worker_task_runner_(params->worker_task_runner()),
       media_log_(params->take_media_log()),
@@ -445,7 +443,7 @@
 
   auto on_audio_source_provider_set_client_callback = base::BindOnce(
       [](base::WeakPtr<WebMediaPlayerImpl> self,
-         blink::WebMediaPlayerClient* const client) {
+         WebMediaPlayerClient* const client) {
         if (!self)
           return;
         client->DidDisableAudioOutputSinkChanges();
@@ -454,7 +452,7 @@
 
   // TODO(xhwang): When we use an external Renderer, many methods won't work,
   // e.g. GetCurrentFrameFromCompositor(). See http://crbug.com/434861
-  audio_source_provider_ = new blink::WebAudioSourceProviderImpl(
+  audio_source_provider_ = new WebAudioSourceProviderImpl(
       params->audio_renderer_sink(), media_log_.get(),
       std::move(on_audio_source_provider_set_client_callback));
 
@@ -462,7 +460,7 @@
     observer_->SetClient(this);
 
   memory_usage_reporting_timer_.SetTaskRunner(
-      frame_->GetTaskRunner(blink::TaskType::kInternalMedia));
+      frame_->GetTaskRunner(TaskType::kInternalMedia));
 
   main_thread_mem_dumper_ = std::make_unique<media::MemoryDumpProviderProxy>(
       "WebMediaPlayer_MainThread", main_task_runner_,
@@ -522,8 +520,7 @@
   // Destruct compositor resources in the proper order.
   client_->SetCcLayer(nullptr);
 
-  client_->MediaRemotingStopped(
-      blink::WebMediaPlayerClient::kMediaRemotingStopNoText);
+  client_->MediaRemotingStopped(WebMediaPlayerClient::kMediaRemotingStopNoText);
 
   if (!surface_layer_for_video_enabled_ && video_layer_)
     video_layer_->StopUsingProvider();
@@ -567,12 +564,12 @@
 
 WebMediaPlayer::LoadTiming WebMediaPlayerImpl::Load(
     LoadType load_type,
-    const blink::WebMediaPlayerSource& source,
+    const WebMediaPlayerSource& source,
     CorsMode cors_mode,
     bool is_cache_disabled) {
   // Only URL or MSE blob URL is supported.
   DCHECK(source.IsURL());
-  blink::WebURL url = source.GetAsURL();
+  WebURL url = source.GetAsURL();
   DVLOG(1) << __func__ << "(" << load_type << ", " << GURL(url) << ", "
            << cors_mode << ")";
 
@@ -684,13 +681,13 @@
 }
 
 void WebMediaPlayerImpl::SetIsEffectivelyFullscreen(
-    blink::WebFullscreenVideoStatus fullscreen_video_status) {
+    WebFullscreenVideoStatus fullscreen_video_status) {
   if (power_status_helper_) {
     // We don't care about pip, so anything that's "not fullscreen" is good
     // enough for us.
     power_status_helper_->SetIsFullscreen(
         fullscreen_video_status !=
-        blink::WebFullscreenVideoStatus::kNotEffectivelyFullscreen);
+        WebFullscreenVideoStatus::kNotEffectivelyFullscreen);
   }
 }
 
@@ -704,26 +701,26 @@
     watch_time_reporter_->OnNativeControlsDisabled();
 }
 
-void WebMediaPlayerImpl::OnDisplayTypeChanged(blink::DisplayType display_type) {
+void WebMediaPlayerImpl::OnDisplayTypeChanged(DisplayType display_type) {
   if (surface_layer_for_video_enabled_) {
     vfc_task_runner_->PostTask(
         FROM_HERE,
         base::BindOnce(&VideoFrameCompositor::SetForceSubmit,
                        base::Unretained(compositor_.get()),
-                       display_type == blink::DisplayType::kPictureInPicture));
+                       display_type == DisplayType::kPictureInPicture));
   }
 
   if (!watch_time_reporter_)
     return;
 
   switch (display_type) {
-    case blink::DisplayType::kInline:
+    case DisplayType::kInline:
       watch_time_reporter_->OnDisplayTypeInline();
       break;
-    case blink::DisplayType::kFullscreen:
+    case DisplayType::kFullscreen:
       watch_time_reporter_->OnDisplayTypeFullscreen();
       break;
-    case blink::DisplayType::kPictureInPicture:
+    case DisplayType::kPictureInPicture:
       watch_time_reporter_->OnDisplayTypePictureInPicture();
 
       // Resumes playback if it was paused when hidden.
@@ -736,7 +733,7 @@
 }
 
 void WebMediaPlayerImpl::DoLoad(LoadType load_type,
-                                const blink::WebURL& url,
+                                const WebURL& url,
                                 CorsMode cors_mode,
                                 bool is_cache_disabled) {
   TRACE_EVENT1("media", "WebMediaPlayerImpl::DoLoad", "id", media_log_->id());
@@ -796,7 +793,7 @@
 
   media_metrics_provider_->Initialize(
       load_type == kLoadTypeMediaSource,
-      load_type == kLoadTypeURL ? blink::GetMediaURLScheme(loaded_url_)
+      load_type == kLoadTypeURL ? GetMediaURLScheme(loaded_url_)
                                 : media::mojom::MediaURLScheme::kUnknown,
       media::mojom::MediaStreamType::kNone);
 
@@ -1081,8 +1078,8 @@
 }
 
 bool WebMediaPlayerImpl::SetSinkId(
-    const blink::WebString& sink_id,
-    blink::WebSetSinkIdCompleteCallback completion_callback) {
+    const WebString& sink_id,
+    WebSetSinkIdCompleteCallback completion_callback) {
   DCHECK(main_task_runner_->BelongsToCurrentThread());
   DVLOG(1) << __func__;
 
@@ -1122,7 +1119,7 @@
 }
 
 void WebMediaPlayerImpl::EnabledAudioTracksChanged(
-    const blink::WebVector<blink::WebMediaPlayer::TrackId>& enabledTrackIds) {
+    const WebVector<WebMediaPlayer::TrackId>& enabledTrackIds) {
   DCHECK(main_task_runner_->BelongsToCurrentThread());
 
   std::ostringstream logstr;
@@ -1138,7 +1135,7 @@
 }
 
 void WebMediaPlayerImpl::SelectedVideoTrackChanged(
-    blink::WebMediaPlayer::TrackId* selectedTrackId) {
+    WebMediaPlayer::TrackId* selectedTrackId) {
   DCHECK(main_task_runner_->BelongsToCurrentThread());
 
   absl::optional<MediaTrack::Id> selected_video_track_id;
@@ -1262,17 +1259,17 @@
   return ready_state_;
 }
 
-blink::WebMediaPlayer::SurfaceLayerMode
-WebMediaPlayerImpl::GetVideoSurfaceLayerMode() const {
+WebMediaPlayer::SurfaceLayerMode WebMediaPlayerImpl::GetVideoSurfaceLayerMode()
+    const {
   return surface_layer_mode_;
 }
 
-blink::WebString WebMediaPlayerImpl::GetErrorMessage() const {
+WebString WebMediaPlayerImpl::GetErrorMessage() const {
   DCHECK(main_task_runner_->BelongsToCurrentThread());
-  return blink::WebString::FromUTF8(media_log_->GetErrorMessage());
+  return WebString::FromUTF8(media_log_->GetErrorMessage());
 }
 
-blink::WebTimeRanges WebMediaPlayerImpl::Buffered() const {
+WebTimeRanges WebMediaPlayerImpl::Buffered() const {
   DCHECK(main_task_runner_->BelongsToCurrentThread());
 
   media::Ranges<base::TimeDelta> buffered_time_ranges =
@@ -1283,14 +1280,14 @@
     buffered_data_source_host_->AddBufferedTimeRanges(&buffered_time_ranges,
                                                       duration);
   }
-  return blink::ConvertToWebTimeRanges(buffered_time_ranges);
+  return ConvertToWebTimeRanges(buffered_time_ranges);
 }
 
-blink::WebTimeRanges WebMediaPlayerImpl::Seekable() const {
+WebTimeRanges WebMediaPlayerImpl::Seekable() const {
   DCHECK(main_task_runner_->BelongsToCurrentThread());
 
   if (ready_state_ < WebMediaPlayer::kReadyStateHaveMetadata)
-    return blink::WebTimeRanges();
+    return WebTimeRanges();
 
   const double seekable_end = Duration();
 
@@ -1308,9 +1305,9 @@
   // TODO(dalecurtis): Technically this allows seeking on media which return an
   // infinite duration so long as DataSource::IsStreaming() is false. While not
   // expected, disabling this breaks semi-live players, http://crbug.com/427412.
-  const blink::WebTimeRange seekable_range(
-      0.0, force_seeks_to_zero ? 0.0 : seekable_end);
-  return blink::WebTimeRanges(&seekable_range, 1);
+  const WebTimeRange seekable_range(0.0,
+                                    force_seeks_to_zero ? 0.0 : seekable_end);
+  return WebTimeRanges(&seekable_range, 1);
 }
 
 bool WebMediaPlayerImpl::IsPrerollAttemptNeeded() {
@@ -1436,8 +1433,8 @@
 }
 
 void WebMediaPlayerImpl::SetContentDecryptionModule(
-    blink::WebContentDecryptionModule* cdm,
-    blink::WebContentDecryptionModuleResult result) {
+    WebContentDecryptionModule* cdm,
+    WebContentDecryptionModuleResult result) {
   DVLOG(1) << __func__ << ": cdm = " << cdm;
   DCHECK(main_task_runner_->BelongsToCurrentThread());
 
@@ -1446,7 +1443,7 @@
   // http://crbug.com/462365#c7.
   if (!cdm) {
     result.CompleteWithError(
-        blink::kWebContentDecryptionModuleExceptionInvalidStateError, 0,
+        kWebContentDecryptionModuleExceptionInvalidStateError, 0,
         "The existing ContentDecryptionModule object cannot be removed at this "
         "time.");
     return;
@@ -1457,8 +1454,7 @@
   // on the wrong thread in some failure conditions. Blink should prevent
   // multiple simultaneous calls.
   DCHECK(!set_cdm_result_);
-  set_cdm_result_ =
-      std::make_unique<blink::WebContentDecryptionModuleResult>(result);
+  set_cdm_result_ = std::make_unique<WebContentDecryptionModuleResult>(result);
 
   SetCdmInternal(cdm);
 }
@@ -1503,20 +1499,18 @@
   bool is_first_video_track = true;
   for (const auto& track : tracks->tracks()) {
     if (track->type() == MediaTrack::Audio) {
-      client_->AddAudioTrack(
-          blink::WebString::FromUTF8(track->id().value()),
-          blink::WebMediaPlayerClient::kAudioTrackKindMain,
-          blink::WebString::FromUTF8(track->label().value()),
-          blink::WebString::FromUTF8(track->language().value()),
-          is_first_audio_track);
+      client_->AddAudioTrack(WebString::FromUTF8(track->id().value()),
+                             WebMediaPlayerClient::kAudioTrackKindMain,
+                             WebString::FromUTF8(track->label().value()),
+                             WebString::FromUTF8(track->language().value()),
+                             is_first_audio_track);
       is_first_audio_track = false;
     } else if (track->type() == MediaTrack::Video) {
-      client_->AddVideoTrack(
-          blink::WebString::FromUTF8(track->id().value()),
-          blink::WebMediaPlayerClient::kVideoTrackKindMain,
-          blink::WebString::FromUTF8(track->label().value()),
-          blink::WebString::FromUTF8(track->language().value()),
-          is_first_video_track);
+      client_->AddVideoTrack(WebString::FromUTF8(track->id().value()),
+                             WebMediaPlayerClient::kVideoTrackKindMain,
+                             WebString::FromUTF8(track->label().value()),
+                             WebString::FromUTF8(track->language().value()),
+                             is_first_video_track);
       is_first_video_track = false;
     } else {
       // Text tracks are not supported through this code path yet.
@@ -1525,8 +1519,7 @@
   }
 }
 
-void WebMediaPlayerImpl::SetCdmInternal(
-    blink::WebContentDecryptionModule* cdm) {
+void WebMediaPlayerImpl::SetCdmInternal(WebContentDecryptionModule* cdm) {
   DCHECK(main_task_runner_->BelongsToCurrentThread());
   DCHECK(cdm);
 
@@ -1596,7 +1589,7 @@
   pending_cdm_context_ref_.reset();
   if (set_cdm_result_) {
     set_cdm_result_->CompleteWithError(
-        blink::kWebContentDecryptionModuleExceptionNotSupportedError, 0,
+        kWebContentDecryptionModuleExceptionNotSupportedError, 0,
         "Unable to set ContentDecryptionModule object");
     set_cdm_result_.reset();
   }
@@ -1870,7 +1863,7 @@
     // be considered a format error.
     SetNetworkState(WebMediaPlayer::kNetworkStateFormatError);
   } else {
-    SetNetworkState(blink::PipelineErrorToNetworkState(status));
+    SetNetworkState(PipelineErrorToNetworkState(status));
   }
 
   // PipelineController::Stop() is idempotent.
@@ -1943,8 +1936,7 @@
         DisableOverlay();
     }
 
-    if (surface_layer_mode_ ==
-        blink::WebMediaPlayer::SurfaceLayerMode::kAlways) {
+    if (surface_layer_mode_ == WebMediaPlayer::SurfaceLayerMode::kAlways) {
       ActivateSurfaceLayerForVideo();
     } else {
       DCHECK(!video_layer_);
@@ -2083,7 +2075,7 @@
                           base::Unretained(this)),
       pipeline_metadata_.video_decoder_config.profile(),
       pipeline_metadata_.natural_size, key_system_, cdm_config_,
-      frame_->GetTaskRunner(blink::TaskType::kInternalMedia));
+      frame_->GetTaskRunner(TaskType::kInternalMedia));
 
   if (delegate_->IsFrameHidden())
     video_decode_stats_reporter_->OnHidden();
@@ -2270,10 +2262,9 @@
 
   const WebInbandTextTrackImpl::Kind web_kind =
       static_cast<WebInbandTextTrackImpl::Kind>(config.kind());
-  const blink::WebString web_label = blink::WebString::FromUTF8(config.label());
-  const blink::WebString web_language =
-      blink::WebString::FromUTF8(config.language());
-  const blink::WebString web_id = blink::WebString::FromUTF8(config.id());
+  const WebString web_label = WebString::FromUTF8(config.label());
+  const WebString web_language = WebString::FromUTF8(config.language());
+  const WebString web_id = WebString::FromUTF8(config.id());
 
   std::unique_ptr<WebInbandTextTrackImpl> web_inband_text_track(
       new WebInbandTextTrackImpl(web_kind, web_label, web_language, web_id));
@@ -2615,7 +2606,7 @@
 }
 #endif  // defined(OS_ANDROID)
 
-void WebMediaPlayerImpl::SetPoster(const blink::WebURL& poster) {
+void WebMediaPlayerImpl::SetPoster(const WebURL& poster) {
   has_poster_ = !poster.IsEmpty();
 }
 
@@ -2913,7 +2904,7 @@
   client_->ReadyStateChanged();
 }
 
-scoped_refptr<blink::WebAudioSourceProviderImpl>
+scoped_refptr<WebAudioSourceProviderImpl>
 WebMediaPlayerImpl::GetAudioSourceProvider() {
   return audio_source_provider_;
 }
@@ -3337,8 +3328,7 @@
 
   // Idle timeout chosen arbitrarily.
   background_pause_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(5),
-                                client_,
-                                &blink::WebMediaPlayerClient::PausePlayback);
+                                client_, &WebMediaPlayerClient::PausePlayback);
 }
 
 void WebMediaPlayerImpl::CreateWatchTimeReporter() {
@@ -3353,7 +3343,7 @@
   }
 
   // Create the watch time reporter and synchronize its initial state.
-  watch_time_reporter_ = std::make_unique<blink::WatchTimeReporter>(
+  watch_time_reporter_ = std::make_unique<WatchTimeReporter>(
       media::mojom::PlaybackProperties::New(
           pipeline_metadata_.has_audio, has_video, false, false,
           !!chunk_demuxer_, is_encrypted_, embedded_media_experience_enabled_,
@@ -3364,7 +3354,7 @@
       base::BindRepeating(&WebMediaPlayerImpl::GetPipelineStatistics,
                           base::Unretained(this)),
       media_metrics_provider_.get(),
-      frame_->GetTaskRunner(blink::TaskType::kInternalMedia));
+      frame_->GetTaskRunner(TaskType::kInternalMedia));
   watch_time_reporter_->OnVolumeChange(volume_);
   watch_time_reporter_->OnDurationChanged(GetPipelineMediaDuration());
 
@@ -3379,13 +3369,13 @@
     watch_time_reporter_->OnNativeControlsDisabled();
 
   switch (client_->GetDisplayType()) {
-    case blink::DisplayType::kInline:
+    case DisplayType::kInline:
       watch_time_reporter_->OnDisplayTypeInline();
       break;
-    case blink::DisplayType::kFullscreen:
+    case DisplayType::kFullscreen:
       watch_time_reporter_->OnDisplayTypeFullscreen();
       break;
-    case blink::DisplayType::kPictureInPicture:
+    case DisplayType::kPictureInPicture:
       watch_time_reporter_->OnDisplayTypePictureInPicture();
       break;
   }
@@ -3478,7 +3468,7 @@
   client_->OnRequestVideoFrameCallback();
 }
 
-std::unique_ptr<blink::WebMediaPlayer::VideoFramePresentationMetadata>
+std::unique_ptr<WebMediaPlayer::VideoFramePresentationMetadata>
 WebMediaPlayerImpl::GetVideoFramePresentationMetadata() {
   return compositor_->GetLastPresentedFrameMetadata();
 }
@@ -3495,7 +3485,7 @@
                      VideoFrameCompositor::UpdateType::kBypassClient));
 }
 
-base::WeakPtr<blink::WebMediaPlayer> WebMediaPlayerImpl::AsWeakPtr() {
+base::WeakPtr<WebMediaPlayer> WebMediaPlayerImpl::AsWeakPtr() {
   return weak_this_;
 }
 
@@ -3817,7 +3807,7 @@
 
 bool WebMediaPlayerImpl::IsInPictureInPicture() const {
   DCHECK(client_);
-  return client_->GetDisplayType() == blink::DisplayType::kPictureInPicture;
+  return client_->GetDisplayType() == DisplayType::kPictureInPicture;
 }
 
 void WebMediaPlayerImpl::MaybeSetContainerNameForMetrics() {
diff --git a/third_party/blink/renderer/platform/media/web_media_player_impl_unittest.cc b/third_party/blink/renderer/platform/media/web_media_player_impl_unittest.cc
index ed48b089..a6312fe 100644
--- a/third_party/blink/renderer/platform/media/web_media_player_impl_unittest.cc
+++ b/third_party/blink/renderer/platform/media/web_media_player_impl_unittest.cc
@@ -118,7 +118,7 @@
                                   std::string(new_rate_string));
 }
 
-class MockWebMediaPlayerClient : public blink::WebMediaPlayerClient {
+class MockWebMediaPlayerClient : public WebMediaPlayerClient {
  public:
   MockWebMediaPlayerClient() = default;
 
@@ -130,34 +130,31 @@
   MOCK_METHOD0(SizeChanged, void());
   MOCK_METHOD1(SetCcLayer, void(cc::Layer*));
   MOCK_METHOD5(AddAudioTrack,
-               blink::WebMediaPlayer::TrackId(
-                   const blink::WebString&,
-                   blink::WebMediaPlayerClient::AudioTrackKind,
-                   const blink::WebString&,
-                   const blink::WebString&,
-                   bool));
-  MOCK_METHOD1(RemoveAudioTrack, void(blink::WebMediaPlayer::TrackId));
+               WebMediaPlayer::TrackId(const WebString&,
+                                       WebMediaPlayerClient::AudioTrackKind,
+                                       const WebString&,
+                                       const WebString&,
+                                       bool));
+  MOCK_METHOD1(RemoveAudioTrack, void(WebMediaPlayer::TrackId));
   MOCK_METHOD5(AddVideoTrack,
-               blink::WebMediaPlayer::TrackId(
-                   const blink::WebString&,
-                   blink::WebMediaPlayerClient::VideoTrackKind,
-                   const blink::WebString&,
-                   const blink::WebString&,
-                   bool));
-  MOCK_METHOD1(RemoveVideoTrack, void(blink::WebMediaPlayer::TrackId));
-  MOCK_METHOD1(AddTextTrack, void(blink::WebInbandTextTrack*));
-  MOCK_METHOD1(RemoveTextTrack, void(blink::WebInbandTextTrack*));
-  MOCK_METHOD1(MediaSourceOpened, void(blink::WebMediaSource*));
-  MOCK_METHOD2(RemotePlaybackCompatibilityChanged,
-               void(const blink::WebURL&, bool));
+               WebMediaPlayer::TrackId(const WebString&,
+                                       WebMediaPlayerClient::VideoTrackKind,
+                                       const WebString&,
+                                       const WebString&,
+                                       bool));
+  MOCK_METHOD1(RemoveVideoTrack, void(WebMediaPlayer::TrackId));
+  MOCK_METHOD1(AddTextTrack, void(WebInbandTextTrack*));
+  MOCK_METHOD1(RemoveTextTrack, void(WebInbandTextTrack*));
+  MOCK_METHOD1(MediaSourceOpened, void(WebMediaSource*));
+  MOCK_METHOD2(RemotePlaybackCompatibilityChanged, void(const WebURL&, bool));
   MOCK_METHOD0(WasAlwaysMuted, bool());
   MOCK_METHOD0(HasSelectedVideoTrack, bool());
-  MOCK_METHOD0(GetSelectedVideoTrackId, blink::WebMediaPlayer::TrackId());
+  MOCK_METHOD0(GetSelectedVideoTrackId, WebMediaPlayer::TrackId());
   MOCK_METHOD0(HasNativeControls, bool());
   MOCK_METHOD0(IsAudioElement, bool());
-  MOCK_CONST_METHOD0(GetDisplayType, blink::DisplayType());
+  MOCK_CONST_METHOD0(GetDisplayType, DisplayType());
   MOCK_CONST_METHOD0(IsInAutoPIP, bool());
-  MOCK_METHOD1(MediaRemotingStarted, void(const blink::WebString&));
+  MOCK_METHOD1(MediaRemotingStarted, void(const WebString&));
   MOCK_METHOD1(MediaRemotingStopped, void(int));
   MOCK_METHOD0(PictureInPictureStopped, void());
   MOCK_METHOD0(OnPictureInPictureStateChange, void());
@@ -181,7 +178,7 @@
   MOCK_METHOD0(DidSeek, void());
   MOCK_METHOD0(GetFeatures, Features(void));
   MOCK_METHOD0(OnRequestVideoFrameCallback, void());
-  MOCK_METHOD0(GetTextTrackMetadata, std::vector<blink::TextTrackMetadata>());
+  MOCK_METHOD0(GetTextTrackMetadata, std::vector<TextTrackMetadata>());
 
   bool was_always_muted_ = false;
 
@@ -190,7 +187,7 @@
 };
 
 class MockWebMediaPlayerEncryptedMediaClient
-    : public blink::WebMediaPlayerEncryptedMediaClient {
+    : public WebMediaPlayerEncryptedMediaClient {
  public:
   MockWebMediaPlayerEncryptedMediaClient() = default;
 
@@ -203,12 +200,12 @@
   DISALLOW_COPY_AND_ASSIGN(MockWebMediaPlayerEncryptedMediaClient);
 };
 
-class MockWebMediaPlayerDelegate : public blink::WebMediaPlayerDelegate {
+class MockWebMediaPlayerDelegate : public WebMediaPlayerDelegate {
  public:
   MockWebMediaPlayerDelegate() = default;
   ~MockWebMediaPlayerDelegate() override = default;
 
-  // blink::WebMediaPlayerDelegate implementation.
+  // WebMediaPlayerDelegate implementation.
   int AddObserver(Observer* observer) override {
     DCHECK_EQ(nullptr, observer_);
     observer_ = observer;
@@ -283,7 +280,7 @@
   bool is_hidden_ = false;
 };
 
-class MockSurfaceLayerBridge : public blink::WebSurfaceLayerBridge {
+class MockSurfaceLayerBridge : public WebSurfaceLayerBridge {
  public:
   MOCK_CONST_METHOD0(GetCcLayer, cc::Layer*());
   MOCK_CONST_METHOD0(GetFrameSinkId, const viz::FrameSinkId&());
@@ -306,7 +303,7 @@
   MOCK_METHOD1(SetIsPageVisible, void(bool));
   MOCK_METHOD0(
       GetLastPresentedFrameMetadata,
-      std::unique_ptr<blink::WebMediaPlayer::VideoFramePresentationMetadata>());
+      std::unique_ptr<WebMediaPlayer::VideoFramePresentationMetadata>());
   MOCK_METHOD0(GetCurrentFrameOnAnyThread, scoped_refptr<media::VideoFrame>());
   MOCK_METHOD1(UpdateCurrentFrameIfStale,
                void(VideoFrameCompositor::UpdateType));
@@ -318,17 +315,16 @@
 
 class WebMediaPlayerImplTest
     : public testing::Test,
-      private blink::WebTestingSupport::WebScopedMockScrollbars {
+      private WebTestingSupport::WebScopedMockScrollbars {
  public:
   WebMediaPlayerImplTest()
       : WebMediaPlayerImplTest(
-            blink::scheduler::WebThreadScheduler::MainThreadScheduler()
+            scheduler::WebThreadScheduler::MainThreadScheduler()
                 ->CreateAgentGroupScheduler()) {}
   explicit WebMediaPlayerImplTest(
-      std::unique_ptr<blink::scheduler::WebAgentGroupScheduler>
-          agent_group_scheduler)
+      std::unique_ptr<scheduler::WebAgentGroupScheduler> agent_group_scheduler)
       : media_thread_("MediaThreadForTest"),
-        web_view_(blink::WebView::Create(
+        web_view_(WebView::Create(
             /*client=*/nullptr,
             /*is_hidden=*/false,
             /*is_inside_portal=*/false,
@@ -339,12 +335,11 @@
             *agent_group_scheduler,
             /*session_storage_namespace_id=*/base::EmptyString(),
             /*page_base_background_color=*/absl::nullopt)),
-        web_local_frame_(
-            blink::WebLocalFrame::CreateMainFrame(web_view_,
-                                                  &web_frame_client_,
-                                                  nullptr,
-                                                  blink::LocalFrameToken(),
-                                                  nullptr)),
+        web_local_frame_(WebLocalFrame::CreateMainFrame(web_view_,
+                                                        &web_frame_client_,
+                                                        nullptr,
+                                                        LocalFrameToken(),
+                                                        nullptr)),
         context_provider_(viz::TestContextProvider::Create()),
         audio_parameters_(media::TestAudioParameters::Normal()),
         memory_dump_manager_(
@@ -452,7 +447,7 @@
         base::BindOnce(&WebMediaPlayerImplTest::CreateMockSurfaceLayerBridge,
                        base::Unretained(this)),
         viz::TestContextProvider::Create(),
-        blink::WebMediaPlayer::SurfaceLayerMode::kAlways,
+        WebMediaPlayer::SurfaceLayerMode::kAlways,
         is_background_suspend_enabled_, is_background_video_playback_enabled_,
         true, std::move(demuxer_override), nullptr);
 
@@ -466,25 +461,25 @@
         std::move(params));
   }
 
-  std::unique_ptr<blink::WebSurfaceLayerBridge> CreateMockSurfaceLayerBridge(
-      blink::WebSurfaceLayerBridgeObserver*,
+  std::unique_ptr<WebSurfaceLayerBridge> CreateMockSurfaceLayerBridge(
+      WebSurfaceLayerBridgeObserver*,
       cc::UpdateSubmissionStateCB) {
     return std::move(surface_layer_bridge_);
   }
 
-  blink::WebLocalFrame* GetWebLocalFrame() { return web_local_frame_; }
+  WebLocalFrame* GetWebLocalFrame() { return web_local_frame_; }
 
   int64_t OnAdjustAllocatedMemory(int64_t delta) {
     reported_memory_ += delta;
     return 0;
   }
 
-  void SetNetworkState(blink::WebMediaPlayer::NetworkState state) {
+  void SetNetworkState(WebMediaPlayer::NetworkState state) {
     EXPECT_CALL(client_, NetworkStateChanged());
     wmpi_->SetNetworkState(state);
   }
 
-  void SetReadyState(blink::WebMediaPlayer::ReadyState state) {
+  void SetReadyState(WebMediaPlayer::ReadyState state) {
     EXPECT_CALL(client_, ReadyStateChanged());
     wmpi_->SetReadyState(state);
   }
@@ -519,10 +514,10 @@
   }
 
   void SetMetadata(bool has_audio, bool has_video) {
-    wmpi_->SetNetworkState(blink::WebMediaPlayer::kNetworkStateLoaded);
+    wmpi_->SetNetworkState(WebMediaPlayer::kNetworkStateLoaded);
 
     EXPECT_CALL(client_, ReadyStateChanged());
-    wmpi_->SetReadyState(blink::WebMediaPlayer::kReadyStateHaveMetadata);
+    wmpi_->SetReadyState(WebMediaPlayer::kReadyStateHaveMetadata);
     wmpi_->pipeline_metadata_.has_audio = has_audio;
     wmpi_->pipeline_metadata_.has_video = has_video;
 
@@ -648,7 +643,7 @@
     wmpi_->SetSuspendState(is_suspended);
   }
 
-  void SetLoadType(blink::WebMediaPlayer::LoadType load_type) {
+  void SetLoadType(WebMediaPlayer::LoadType load_type) {
     wmpi_->load_type_ = load_type;
   }
 
@@ -707,7 +702,7 @@
     // the resource is fully buffered locally. We can use a fake one here since
     // we're injecting the response artificially. It's value is unknown to the
     // underlying demuxer.
-    const blink::KURL kTestURL(
+    const KURL kTestURL(
         String::FromUTF8(std::string(is_streaming ? "http" : "file") +
                          "://example.com/sample.webm"));
 
@@ -715,19 +710,19 @@
     // to the WebAssociatedURLLoaderClient handed out by the DataSource after it
     // requests loading of a resource. We then use that client as if we are the
     // network stack and "serve" an in memory file to the DataSource.
-    blink::WebAssociatedURLLoaderClient* client = nullptr;
+    WebAssociatedURLLoaderClient* client = nullptr;
     EXPECT_CALL(mock_resource_fetch_context_, CreateUrlLoader(_))
         .WillRepeatedly(
-            Invoke([&client](const blink::WebAssociatedURLLoaderOptions&) {
+            Invoke([&client](const WebAssociatedURLLoaderOptions&) {
               auto a = std::make_unique<NiceMock<MockWebAssociatedURLLoader>>();
               EXPECT_CALL(*a, LoadAsynchronously(_, _))
                   .WillRepeatedly(testing::SaveArg<1>(&client));
               return a;
             }));
 
-    wmpi_->Load(blink::WebMediaPlayer::kLoadTypeURL,
-                blink::WebMediaPlayerSource(blink::WebURL(kTestURL)),
-                blink::WebMediaPlayer::kCorsModeUnspecified,
+    wmpi_->Load(WebMediaPlayer::kLoadTypeURL,
+                WebMediaPlayerSource(WebURL(kTestURL)),
+                WebMediaPlayer::kCorsModeUnspecified,
                 /*is_cache_disabled=*/false);
 
     base::RunLoop().RunUntilIdle();
@@ -739,10 +734,10 @@
     // "Serve" the file to the DataSource. Note: We respond with 200 okay, which
     // will prevent range requests or partial responses from being used. For
     // streaming responses, we'll pretend we don't know the content length.
-    blink::WebURLResponse response(kTestURL);
+    WebURLResponse response(kTestURL);
     response.SetHttpHeaderField(
-        blink::WebString::FromUTF8("Content-Length"),
-        blink::WebString::FromUTF8(
+        WebString::FromUTF8("Content-Length"),
+        WebString::FromUTF8(
             is_streaming ? "-1" : base::NumberToString(data->data_size())));
     response.SetExpectedContentLength(is_streaming ? -1 : data->data_size());
     response.SetHttpStatusCode(200);
@@ -763,7 +758,7 @@
   // unreliable due to asynchronous execution of tasks on the
   // base::test:TaskEnvironment.
   void LoadAndWaitForReadyState(std::string data_file,
-                                blink::WebMediaPlayer::ReadyState ready_state) {
+                                WebMediaPlayer::ReadyState ready_state) {
     Load(data_file);
     while (wmpi_->GetReadyState() < ready_state) {
       base::RunLoop loop;
@@ -779,13 +774,13 @@
     EXPECT_TRUE(wmpi_->data_source_);
     EXPECT_TRUE(wmpi_->demuxer_);
 
-    if (ready_state > blink::WebMediaPlayer::kReadyStateHaveCurrentData)
+    if (ready_state > WebMediaPlayer::kReadyStateHaveCurrentData)
       EXPECT_FALSE(wmpi_->seeking_);
   }
 
   void LoadAndWaitForCurrentData(std::string data_file) {
     LoadAndWaitForReadyState(data_file,
-                             blink::WebMediaPlayer::kReadyStateHaveCurrentData);
+                             WebMediaPlayer::kReadyStateHaveCurrentData);
   }
 
   void CycleThreads() {
@@ -802,7 +797,7 @@
   void OnProgress() { wmpi_->OnProgress(); }
 
   void OnCdmCreated(base::RepeatingClosure quit_closure,
-                    blink::WebContentDecryptionModule* cdm,
+                    WebContentDecryptionModule* cdm,
                     const std::string& error_message) {
     LOG_IF(ERROR, !error_message.empty()) << error_message;
     EXPECT_TRUE(cdm);
@@ -813,8 +808,8 @@
   void CreateCdm() {
     // Must use a supported key system on a secure context.
     std::u16string key_system = u"org.w3.clearkey";
-    auto test_origin = blink::WebSecurityOrigin::CreateFromString(
-        blink::WebString::FromUTF8("https://test.origin"));
+    auto test_origin = WebSecurityOrigin::CreateFromString(
+        WebString::FromUTF8("https://test.origin"));
 
     base::RunLoop run_loop;
     WebContentDecryptionModuleImpl::Create(
@@ -846,9 +841,9 @@
   base::Thread media_thread_;
 
   // Blink state.
-  blink::WebLocalFrameClient web_frame_client_;
-  blink::WebView* web_view_;
-  blink::WebLocalFrame* web_local_frame_;
+  WebLocalFrameClient web_frame_client_;
+  WebView* web_view_;
+  WebLocalFrame* web_local_frame_;
 
   scoped_refptr<viz::TestContextProvider> context_provider_;
   NiceMock<MockVideoFrameCompositor>* compositor_;
@@ -871,7 +866,7 @@
   scoped_refptr<media::MockCdm> mock_cdm_ =
       base::MakeRefCounted<media::MockCdm>();
   media::MockCdmFactory mock_cdm_factory_{mock_cdm_};
-  std::unique_ptr<blink::WebContentDecryptionModule> web_cdm_;
+  std::unique_ptr<WebContentDecryptionModule> web_cdm_;
   media::MockCdmContext mock_cdm_context_;
 
   viz::FrameSinkId frame_sink_id_ = viz::FrameSinkId(1, 1);
@@ -904,8 +899,7 @@
 
   std::unique_ptr<base::trace_event::MemoryDumpManager> memory_dump_manager_;
 
-  std::unique_ptr<blink::scheduler::WebAgentGroupScheduler>
-      agent_group_scheduler_;
+  std::unique_ptr<scheduler::WebAgentGroupScheduler> agent_group_scheduler_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerImplTest);
@@ -920,7 +914,7 @@
 TEST_F(WebMediaPlayerImplTest, LoadAndDestroy) {
   InitializeWebMediaPlayerImpl();
   EXPECT_FALSE(IsSuspended());
-  wmpi_->SetPreload(blink::WebMediaPlayer::kPreloadAuto);
+  wmpi_->SetPreload(WebMediaPlayer::kPreloadAuto);
   LoadAndWaitForCurrentData(kAudioOnlyTestFile);
   EXPECT_FALSE(IsSuspended());
   CycleThreads();
@@ -936,9 +930,9 @@
 TEST_F(WebMediaPlayerImplTest, LoadAndDestroyDataUrl) {
   InitializeWebMediaPlayerImpl();
   EXPECT_FALSE(IsSuspended());
-  wmpi_->SetPreload(blink::WebMediaPlayer::kPreloadAuto);
+  wmpi_->SetPreload(WebMediaPlayer::kPreloadAuto);
 
-  const blink::KURL kMp3DataUrl(
+  const KURL kMp3DataUrl(
       "data://audio/mp3;base64,SUQzAwAAAAAAFlRFTkMAAAAMAAAAQW1hZGV1cyBQcm//"
       "+5DEAAAAAAAAAAAAAAAAAAAAAABYaW5nAAAADwAAAAwAAAftABwcHBwcHBwcMTExMTExMTFG"
       "RkZGRkZGRlpaWlpaWlpaWm9vb29vb29vhISEhISEhISYmJiYmJiYmJitra2tra2trcLCwsLC"
@@ -991,9 +985,9 @@
       "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
       "AAAAAAAAAAAAAAAAAAP8=");
 
-  wmpi_->Load(blink::WebMediaPlayer::kLoadTypeURL,
-              blink::WebMediaPlayerSource(blink::WebURL(kMp3DataUrl)),
-              blink::WebMediaPlayer::kCorsModeUnspecified,
+  wmpi_->Load(WebMediaPlayer::kLoadTypeURL,
+              WebMediaPlayerSource(WebURL(kMp3DataUrl)),
+              WebMediaPlayer::kCorsModeUnspecified,
               /*is_cache_disabled=*/false);
 
   base::RunLoop().RunUntilIdle();
@@ -1001,8 +995,7 @@
   // This runs until we reach the have current data state. Attempting to wait
   // for states < kReadyStateHaveCurrentData is unreliable due to asynchronous
   // execution of tasks on the base::test:TaskEnvironment.
-  while (wmpi_->GetReadyState() <
-         blink::WebMediaPlayer::kReadyStateHaveCurrentData) {
+  while (wmpi_->GetReadyState() < WebMediaPlayer::kReadyStateHaveCurrentData) {
     base::RunLoop loop;
     EXPECT_CALL(client_, ReadyStateChanged())
         .WillRepeatedly(RunClosure(loop.QuitClosure()));
@@ -1020,9 +1013,9 @@
 TEST_F(WebMediaPlayerImplTest, LoadPreloadMetadataSuspend) {
   InitializeWebMediaPlayerImpl();
   EXPECT_CALL(client_, CouldPlayIfEnoughData()).WillRepeatedly(Return(false));
-  wmpi_->SetPreload(blink::WebMediaPlayer::kPreloadMetaData);
+  wmpi_->SetPreload(WebMediaPlayer::kPreloadMetaData);
   LoadAndWaitForReadyState(kAudioOnlyTestFile,
-                           blink::WebMediaPlayer::kReadyStateHaveMetadata);
+                           WebMediaPlayer::kReadyStateHaveMetadata);
   testing::Mock::VerifyAndClearExpectations(&client_);
   EXPECT_CALL(client_, ReadyStateChanged()).Times(AnyNumber());
   CycleThreads();
@@ -1040,16 +1033,15 @@
 TEST_F(WebMediaPlayerImplTest, NoBufferSizeIncreaseUntilHaveEnough) {
   InitializeWebMediaPlayerImpl();
   EXPECT_CALL(client_, CouldPlayIfEnoughData()).WillRepeatedly(Return(true));
-  wmpi_->SetPreload(blink::WebMediaPlayer::kPreloadAuto);
+  wmpi_->SetPreload(WebMediaPlayer::kPreloadAuto);
   LoadAndWaitForReadyState(kAudioOnlyTestFile,
-                           blink::WebMediaPlayer::kReadyStateHaveMetadata);
+                           WebMediaPlayer::kReadyStateHaveMetadata);
   testing::Mock::VerifyAndClearExpectations(&client_);
   EXPECT_CALL(client_, ReadyStateChanged()).Times(AnyNumber());
   wmpi_->Play();
   EXPECT_FALSE(IsDataSourceMarkedAsPlaying());
 
-  while (wmpi_->GetReadyState() <
-         blink::WebMediaPlayer::kReadyStateHaveEnoughData) {
+  while (wmpi_->GetReadyState() < WebMediaPlayer::kReadyStateHaveEnoughData) {
     // Clear the mock so it doesn't have a stale QuitClosure.
     testing::Mock::VerifyAndClearExpectations(&client_);
 
@@ -1066,7 +1058,7 @@
 TEST_F(WebMediaPlayerImplTest, LoadPreloadMetadataSuspendNoStreaming) {
   InitializeWebMediaPlayerImpl();
   EXPECT_CALL(client_, CouldPlayIfEnoughData()).WillRepeatedly(Return(false));
-  wmpi_->SetPreload(blink::WebMediaPlayer::kPreloadMetaData);
+  wmpi_->SetPreload(WebMediaPlayer::kPreloadMetaData);
 
   // This test needs a file which is larger than the MultiBuffer block size;
   // otherwise we'll never complete initialization of the MultiBufferDataSource.
@@ -1074,8 +1066,7 @@
   Load(kLargeAudioOnlyTestFile, LoadType::kStreaming);
 
   // This runs until we reach the metadata state.
-  while (wmpi_->GetReadyState() <
-         blink::WebMediaPlayer::kReadyStateHaveMetadata) {
+  while (wmpi_->GetReadyState() < WebMediaPlayer::kReadyStateHaveMetadata) {
     base::RunLoop loop;
     EXPECT_CALL(client_, ReadyStateChanged())
         .WillRepeatedly(RunClosure(loop.QuitClosure()));
@@ -1097,12 +1088,12 @@
   scoped_feature_list.InitAndEnableFeature(media::kPreloadMetadataLazyLoad);
   InitializeWebMediaPlayerImpl();
   EXPECT_CALL(client_, CouldPlayIfEnoughData()).WillRepeatedly(Return(false));
-  wmpi_->SetPreload(blink::WebMediaPlayer::kPreloadMetaData);
+  wmpi_->SetPreload(WebMediaPlayer::kPreloadMetaData);
 
   // Don't set poster, but ensure we still reach suspended state.
 
   LoadAndWaitForReadyState(kVideoOnlyTestFile,
-                           blink::WebMediaPlayer::kReadyStateHaveMetadata);
+                           WebMediaPlayer::kReadyStateHaveMetadata);
   testing::Mock::VerifyAndClearExpectations(&client_);
   EXPECT_CALL(client_, ReadyStateChanged()).Times(AnyNumber());
   CycleThreads();
@@ -1123,11 +1114,11 @@
 TEST_F(WebMediaPlayerImplTest, LoadPreloadMetadataSuspendNoVideoMemoryUsage) {
   InitializeWebMediaPlayerImpl();
   EXPECT_CALL(client_, CouldPlayIfEnoughData()).WillRepeatedly(Return(false));
-  wmpi_->SetPreload(blink::WebMediaPlayer::kPreloadMetaData);
-  wmpi_->SetPoster(blink::WebURL(blink::KURL("file://example.com/sample.jpg")));
+  wmpi_->SetPreload(WebMediaPlayer::kPreloadMetaData);
+  wmpi_->SetPoster(WebURL(KURL("file://example.com/sample.jpg")));
 
   LoadAndWaitForReadyState(kVideoOnlyTestFile,
-                           blink::WebMediaPlayer::kReadyStateHaveMetadata);
+                           WebMediaPlayer::kReadyStateHaveMetadata);
   testing::Mock::VerifyAndClearExpectations(&client_);
   EXPECT_CALL(client_, ReadyStateChanged()).Times(AnyNumber());
   CycleThreads();
@@ -1147,7 +1138,7 @@
 TEST_F(WebMediaPlayerImplTest, LoadPreloadMetadataSuspendCouldPlay) {
   InitializeWebMediaPlayerImpl();
   EXPECT_CALL(client_, CouldPlayIfEnoughData()).WillRepeatedly(Return(true));
-  wmpi_->SetPreload(blink::WebMediaPlayer::kPreloadMetaData);
+  wmpi_->SetPreload(WebMediaPlayer::kPreloadMetaData);
   LoadAndWaitForCurrentData(kAudioOnlyTestFile);
   testing::Mock::VerifyAndClearExpectations(&client_);
   EXPECT_CALL(client_, ReadyStateChanged()).Times(AnyNumber());
@@ -1177,7 +1168,7 @@
 
 TEST_F(WebMediaPlayerImplTest, IdleSuspendIsEnabledIfLoadingHasStalled) {
   InitializeWebMediaPlayerImpl();
-  SetNetworkState(blink::WebMediaPlayer::kNetworkStateLoading);
+  SetNetworkState(WebMediaPlayer::kNetworkStateLoading);
   base::SimpleTestTickClock clock;
   clock.Advance(base::TimeDelta::FromSeconds(1));
   SetTickClock(&clock);
@@ -1193,7 +1184,7 @@
 TEST_F(WebMediaPlayerImplTest, DidLoadingProgressTriggersResume) {
   // Same setup as IdleSuspendIsEnabledBeforeLoadingBegins.
   InitializeWebMediaPlayerImpl();
-  SetNetworkState(blink::WebMediaPlayer::kNetworkStateLoading);
+  SetNetworkState(WebMediaPlayer::kNetworkStateLoading);
   EXPECT_TRUE(delegate_.ExpireForTesting());
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(IsSuspended());
@@ -1266,7 +1257,7 @@
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_HaveFutureData) {
   InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
-  SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
+  SetReadyState(WebMediaPlayer::kReadyStateHaveFutureData);
   WebMediaPlayerImpl::PlayState state = ComputePlayState();
   EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PAUSED, state.delegate_state);
   EXPECT_TRUE(state.is_idle);
@@ -1278,7 +1269,7 @@
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_PlayingError) {
   InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
-  SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
+  SetReadyState(WebMediaPlayer::kReadyStateHaveFutureData);
   SetPaused(false);
   WebMediaPlayerImpl::PlayState state = ComputePlayState();
   EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PLAYING, state.delegate_state);
@@ -1295,7 +1286,7 @@
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_Playing) {
   InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
-  SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
+  SetReadyState(WebMediaPlayer::kReadyStateHaveFutureData);
   SetPaused(false);
   WebMediaPlayerImpl::PlayState state = ComputePlayState();
   EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PLAYING, state.delegate_state);
@@ -1307,7 +1298,7 @@
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_PlayingVideoOnly) {
   InitializeWebMediaPlayerImpl();
   SetMetadata(false, true);
-  SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
+  SetReadyState(WebMediaPlayer::kReadyStateHaveFutureData);
   SetPaused(false);
   WebMediaPlayerImpl::PlayState state = ComputePlayState();
   EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PLAYING, state.delegate_state);
@@ -1319,9 +1310,9 @@
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_Underflow) {
   InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
-  SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
+  SetReadyState(WebMediaPlayer::kReadyStateHaveFutureData);
   SetPaused(false);
-  SetReadyState(blink::WebMediaPlayer::kReadyStateHaveCurrentData);
+  SetReadyState(WebMediaPlayer::kReadyStateHaveCurrentData);
   WebMediaPlayerImpl::PlayState state = ComputePlayState();
   EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PLAYING, state.delegate_state);
   EXPECT_FALSE(state.is_idle);
@@ -1332,7 +1323,7 @@
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_FrameHidden) {
   InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
-  SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
+  SetReadyState(WebMediaPlayer::kReadyStateHaveFutureData);
   SetPaused(false);
 
   WebMediaPlayerImpl::PlayState state = ComputePlayState_FrameHidden();
@@ -1345,7 +1336,7 @@
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_FrameHiddenAudioOnly) {
   InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
-  SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
+  SetReadyState(WebMediaPlayer::kReadyStateHaveFutureData);
   SetPaused(false);
 
   SetMetadata(true, false);
@@ -1363,7 +1354,7 @@
 
   InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
-  SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
+  SetReadyState(WebMediaPlayer::kReadyStateHaveFutureData);
   SetPaused(false);
   WebMediaPlayerImpl::PlayState state = ComputePlayState_FrameHidden();
   EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PLAYING, state.delegate_state);
@@ -1386,7 +1377,7 @@
 
   InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
-  SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
+  SetReadyState(WebMediaPlayer::kReadyStateHaveFutureData);
   SetPaused(false);
 
   WebMediaPlayerImpl::PlayState state = ComputePlayState_FrameHidden();
@@ -1399,7 +1390,7 @@
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_FrameClosed) {
   InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
-  SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
+  SetReadyState(WebMediaPlayer::kReadyStateHaveFutureData);
   SetPaused(false);
   SetWasSuspendedForFrameClosed(true);
   WebMediaPlayerImpl::PlayState state = ComputePlayState();
@@ -1412,7 +1403,7 @@
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_PausedSeek) {
   InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
-  SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
+  SetReadyState(WebMediaPlayer::kReadyStateHaveFutureData);
   SetSeeking(true);
   WebMediaPlayerImpl::PlayState state = ComputePlayState();
   EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PAUSED, state.delegate_state);
@@ -1424,7 +1415,7 @@
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_Ended) {
   InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
-  SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
+  SetReadyState(WebMediaPlayer::kReadyStateHaveFutureData);
   SetPaused(false);
   SetEnded(true);
 
@@ -1448,7 +1439,7 @@
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_DoesNotStaySuspended) {
   InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
-  SetReadyState(blink::WebMediaPlayer::kReadyStateHaveMetadata);
+  SetReadyState(WebMediaPlayer::kReadyStateHaveMetadata);
 
   // Should stay suspended even though not stale or backgrounded.
   WebMediaPlayerImpl::PlayState state = ComputePlayState_Suspended();
@@ -1461,7 +1452,7 @@
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_StaysSuspended) {
   InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
-  SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
+  SetReadyState(WebMediaPlayer::kReadyStateHaveFutureData);
 
   // Should stay suspended even though not stale or backgrounded.
   WebMediaPlayerImpl::PlayState state = ComputePlayState_Suspended();
@@ -1474,7 +1465,7 @@
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_ResumeForNeedFirstFrame) {
   InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
-  SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
+  SetReadyState(WebMediaPlayer::kReadyStateHaveFutureData);
 
   // Should stay suspended even though not stale or backgrounded.
   WebMediaPlayerImpl::PlayState state = ComputePlayState_Suspended();
@@ -1494,7 +1485,7 @@
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_Flinging) {
   InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
-  SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
+  SetReadyState(WebMediaPlayer::kReadyStateHaveFutureData);
 
   // Remote media via the FlingingRenderer should not be idle.
   WebMediaPlayerImpl::PlayState state = ComputePlayState_Flinging();
@@ -1507,7 +1498,7 @@
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_Fullscreen) {
   InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
-  SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
+  SetReadyState(WebMediaPlayer::kReadyStateHaveFutureData);
   SetFullscreen(true);
   SetPaused(true);
   delegate_.SetStaleForTesting(true);
@@ -1523,7 +1514,7 @@
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_Streaming) {
   InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
-  SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
+  SetReadyState(WebMediaPlayer::kReadyStateHaveFutureData);
   SetPaused(true);
   delegate_.SetStaleForTesting(true);
 
@@ -1558,7 +1549,7 @@
   EXPECT_CALL(delegate_, DidMediaMetadataChange(_, true, true, _)).Times(2);
 
   OnMetadata(metadata);
-  SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
+  SetReadyState(WebMediaPlayer::kReadyStateHaveFutureData);
   Play();
   // Cause PlayerGone
   Pause();
@@ -1598,7 +1589,7 @@
 TEST_F(WebMediaPlayerImplTest, MediaPositionState_Playing) {
   InitializeWebMediaPlayerImpl();
   LoadAndWaitForReadyState(kAudioOnlyTestFile,
-                           blink::WebMediaPlayer::kReadyStateHaveFutureData);
+                           WebMediaPlayer::kReadyStateHaveFutureData);
   wmpi_->SetRate(1.0);
   Play();
 
@@ -1611,7 +1602,7 @@
 TEST_F(WebMediaPlayerImplTest, MediaPositionState_Paused) {
   InitializeWebMediaPlayerImpl();
   LoadAndWaitForReadyState(kAudioOnlyTestFile,
-                           blink::WebMediaPlayer::kReadyStateHaveFutureData);
+                           WebMediaPlayer::kReadyStateHaveFutureData);
   wmpi_->SetRate(1.0);
 
   // The effective playback rate is 0.0 while paused.
@@ -1624,7 +1615,7 @@
 TEST_F(WebMediaPlayerImplTest, MediaPositionState_PositionChange) {
   InitializeWebMediaPlayerImpl();
   LoadAndWaitForReadyState(kAudioOnlyTestFile,
-                           blink::WebMediaPlayer::kReadyStateHaveFutureData);
+                           WebMediaPlayer::kReadyStateHaveFutureData);
   wmpi_->SetRate(0.5);
   Play();
 
@@ -1643,7 +1634,7 @@
                   0.5, kAudioOnlyTestFileDuration,
                   base::TimeDelta::FromSecondsD(0.1), /*end_of_media=*/false))
       .InSequence(sequence);
-  SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
+  SetReadyState(WebMediaPlayer::kReadyStateHaveFutureData);
   wmpi_->OnTimeUpdate();
 
   // No media time progress -> no MediaPositionState change.
@@ -1653,10 +1644,10 @@
 TEST_F(WebMediaPlayerImplTest, MediaPositionState_EndOfMedia) {
   InitializeWebMediaPlayerImpl();
   LoadAndWaitForReadyState(kAudioOnlyTestFile,
-                           blink::WebMediaPlayer::kReadyStateHaveFutureData);
+                           WebMediaPlayer::kReadyStateHaveFutureData);
   wmpi_->SetRate(1.0);
   Play();
-  SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
+  SetReadyState(WebMediaPlayer::kReadyStateHaveFutureData);
 
   testing::Sequence sequence;
   EXPECT_CALL(client_, DidPlayerMediaPositionStateChange(
@@ -1677,7 +1668,7 @@
 TEST_F(WebMediaPlayerImplTest, MediaPositionState_Underflow) {
   InitializeWebMediaPlayerImpl();
   LoadAndWaitForReadyState(kAudioOnlyTestFile,
-                           blink::WebMediaPlayer::kReadyStateHaveFutureData);
+                           WebMediaPlayer::kReadyStateHaveFutureData);
   wmpi_->SetRate(1.0);
   Play();
 
@@ -1685,7 +1676,7 @@
   EXPECT_CALL(client_, DidPlayerMediaPositionStateChange(
                            0.0, kAudioOnlyTestFileDuration, base::TimeDelta(),
                            /*end_of_media=*/false));
-  SetReadyState(blink::WebMediaPlayer::kReadyStateHaveCurrentData);
+  SetReadyState(WebMediaPlayer::kReadyStateHaveCurrentData);
   wmpi_->OnTimeUpdate();
 }
 
@@ -1727,17 +1718,15 @@
   // No assertions in the production code should fail.
   OnMetadata(metadata);
 
-  EXPECT_EQ(wmpi_->GetNetworkState(),
-            blink::WebMediaPlayer::kNetworkStateFormatError);
-  EXPECT_EQ(wmpi_->GetReadyState(),
-            blink::WebMediaPlayer::kReadyStateHaveNothing);
+  EXPECT_EQ(wmpi_->GetNetworkState(), WebMediaPlayer::kNetworkStateFormatError);
+  EXPECT_EQ(wmpi_->GetReadyState(), WebMediaPlayer::kReadyStateHaveNothing);
 }
 
 TEST_F(WebMediaPlayerImplTest, Encrypted) {
   InitializeWebMediaPlayerImpl();
 
   // To avoid PreloadMetadataLazyLoad.
-  wmpi_->SetPreload(blink::WebMediaPlayer::kPreloadAuto);
+  wmpi_->SetPreload(WebMediaPlayer::kPreloadAuto);
 
   {
     base::RunLoop run_loop;
@@ -1762,8 +1751,7 @@
     // error.
     base::RunLoop run_loop;
     EXPECT_CALL(client_, NetworkStateChanged()).WillOnce(Invoke([&] {
-      if (wmpi_->GetNetworkState() ==
-          blink::WebMediaPlayer::kNetworkStateFormatError)
+      if (wmpi_->GetNetworkState() == WebMediaPlayer::kNetworkStateFormatError)
         run_loop.QuitClosure().Run();
     }));
     SetCdm();
@@ -1793,7 +1781,7 @@
 TEST_F(WebMediaPlayerImplTest, FallbackToMediaFoundationRenderer) {
   InitializeWebMediaPlayerImpl();
   // To avoid PreloadMetadataLazyLoad.
-  wmpi_->SetPreload(blink::WebMediaPlayer::kPreloadAuto);
+  wmpi_->SetPreload(WebMediaPlayer::kPreloadAuto);
 
   // Use MockRendererFactory for kMediaFoundation where the created Renderer
   // will take the CDM, complete Renderer initialization and report HAVE_ENOUGH
@@ -1961,7 +1949,7 @@
 
   // With a user gesture it does unlock the player.
   GetWebLocalFrame()->NotifyUserActivation(
-      blink::mojom::UserActivationNotificationType::kTest);
+      mojom::UserActivationNotificationType::kTest);
   Play();
   EXPECT_FALSE(IsVideoLockedWhenPausedWhenHidden());
 
@@ -1972,7 +1960,7 @@
 
   // With a user gesture, pause does lock the player.
   GetWebLocalFrame()->NotifyUserActivation(
-      blink::mojom::UserActivationNotificationType::kTest);
+      mojom::UserActivationNotificationType::kTest);
   Pause();
   EXPECT_TRUE(IsVideoLockedWhenPausedWhenHidden());
 
@@ -2097,7 +2085,7 @@
   OnMetadata(metadata);
 
   EXPECT_CALL(client_, GetDisplayType())
-      .WillRepeatedly(Return(blink::DisplayType::kPictureInPicture));
+      .WillRepeatedly(Return(DisplayType::kPictureInPicture));
   EXPECT_CALL(client_, OnPictureInPictureStateChange()).Times(1);
 
   wmpi_->OnSurfaceIdUpdated(surface_id_);
@@ -2109,15 +2097,14 @@
   InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
 
-  for (auto rs = blink::WebMediaPlayer::kReadyStateHaveNothing;
-       rs <= blink::WebMediaPlayer::kReadyStateHaveEnoughData;
-       rs = static_cast<blink::WebMediaPlayer::ReadyState>(
-           static_cast<int>(rs) + 1)) {
+  for (auto rs = WebMediaPlayer::kReadyStateHaveNothing;
+       rs <= WebMediaPlayer::kReadyStateHaveEnoughData;
+       rs = static_cast<WebMediaPlayer::ReadyState>(static_cast<int>(rs) + 1)) {
     SetReadyState(rs);
     delegate_.SetStaleForTesting(true);
     OnProgress();
     EXPECT_EQ(delegate_.IsStale(delegate_.player_id()),
-              rs >= blink::WebMediaPlayer::kReadyStateHaveFutureData);
+              rs >= WebMediaPlayer::kReadyStateHaveFutureData);
   }
 }
 
@@ -2131,7 +2118,7 @@
   auto* dump_manager = base::trace_event::MemoryDumpManager::GetInstance();
   InitializeWebMediaPlayerImpl();
 
-  wmpi_->SetPreload(blink::WebMediaPlayer::kPreloadAuto);
+  wmpi_->SetPreload(WebMediaPlayer::kPreloadAuto);
   auto* main_dumper = GetMainThreadMemDumper();
   EXPECT_TRUE(dump_manager->IsDumpProviderRegisteredForTesting(main_dumper));
   LoadAndWaitForCurrentData(kVideoAudioTestFile);
@@ -2150,7 +2137,7 @@
 TEST_F(WebMediaPlayerImplTest, MemDumpReporting) {
   InitializeWebMediaPlayerImpl();
 
-  wmpi_->SetPreload(blink::WebMediaPlayer::kPreloadAuto);
+  wmpi_->SetPreload(WebMediaPlayer::kPreloadAuto);
   LoadAndWaitForCurrentData(kVideoAudioTestFile);
 
   CycleThreads();
@@ -2240,11 +2227,10 @@
   InitializeWebMediaPlayerImplInternal(std::move(demuxer));
 
   EXPECT_FALSE(IsSuspended());
-  wmpi_->Load(
-      blink::WebMediaPlayer::kLoadTypeURL,
-      blink::WebMediaPlayerSource(blink::WebURL(blink::KURL("data://test"))),
-      blink::WebMediaPlayer::kCorsModeUnspecified,
-      /*is_cache_disabled=*/false);
+  wmpi_->Load(WebMediaPlayer::kLoadTypeURL,
+              WebMediaPlayerSource(WebURL(KURL("data://test"))),
+              WebMediaPlayer::kCorsModeUnspecified,
+              /*is_cache_disabled=*/false);
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(IsSuspended());
 }
@@ -2297,15 +2283,15 @@
 
     InitializeWebMediaPlayerImpl();
     bool is_media_source = std::get<kIsMediaSource>(GetParam());
-    SetLoadType(is_media_source ? blink::WebMediaPlayer::kLoadTypeMediaSource
-                                : blink::WebMediaPlayer::kLoadTypeURL);
+    SetLoadType(is_media_source ? WebMediaPlayer::kLoadTypeMediaSource
+                                : WebMediaPlayer::kLoadTypeURL);
     SetVideoKeyframeDistanceAverage(
         base::TimeDelta::FromSeconds(GetAverageKeyframeDistanceSec()));
     SetDuration(base::TimeDelta::FromSeconds(GetDurationSec()));
 
     if (IsPictureInPictureOn()) {
       EXPECT_CALL(client_, GetDisplayType())
-          .WillRepeatedly(Return(blink::DisplayType::kPictureInPicture));
+          .WillRepeatedly(Return(DisplayType::kPictureInPicture));
 
       wmpi_->OnSurfaceIdUpdated(surface_id_);
     }
diff --git a/third_party/blink/renderer/platform/media/web_media_player_params.cc b/third_party/blink/renderer/platform/media/web_media_player_params.cc
index 2198aeef..ca72aba 100644
--- a/third_party/blink/renderer/platform/media/web_media_player_params.cc
+++ b/third_party/blink/renderer/platform/media/web_media_player_params.cc
@@ -22,7 +22,7 @@
     const scoped_refptr<base::SingleThreadTaskRunner>&
         video_frame_compositor_task_runner,
     const AdjustAllocatedMemoryCB& adjust_allocated_memory_cb,
-    blink::WebContentDecryptionModule* initial_cdm,
+    WebContentDecryptionModule* initial_cdm,
     media::RequestRoutingTokenCallback request_routing_token_cb,
     base::WeakPtr<media::MediaObserver> media_observer,
     bool enable_instant_source_buffer_gc,
@@ -30,7 +30,7 @@
     mojo::PendingRemote<media::mojom::MediaMetricsProvider> metrics_provider,
     CreateSurfaceLayerBridgeCB create_bridge_callback,
     scoped_refptr<viz::RasterContextProvider> raster_context_provider,
-    blink::WebMediaPlayer::SurfaceLayerMode use_surface_layer_for_video,
+    WebMediaPlayer::SurfaceLayerMode use_surface_layer_for_video,
     bool is_background_suspend_enabled,
     bool is_background_video_playback_enabled,
     bool is_background_video_track_optimization_supported,
diff --git a/third_party/blink/renderer/platform/media/web_media_source_impl.cc b/third_party/blink/renderer/platform/media/web_media_source_impl.cc
index 80b8f0c..24b0a1a2 100644
--- a/third_party/blink/renderer/platform/media/web_media_source_impl.cc
+++ b/third_party/blink/renderer/platform/media/web_media_source_impl.cc
@@ -30,9 +30,9 @@
 
 WebMediaSourceImpl::~WebMediaSourceImpl() = default;
 
-std::unique_ptr<blink::WebSourceBuffer> WebMediaSourceImpl::AddSourceBuffer(
-    const blink::WebString& content_type,
-    const blink::WebString& codecs,
+std::unique_ptr<WebSourceBuffer> WebMediaSourceImpl::AddSourceBuffer(
+    const WebString& content_type,
+    const WebString& codecs,
     WebMediaSource::AddStatus& out_status /* out */) {
   std::string id = base::GenerateGUID();
 
@@ -45,7 +45,7 @@
   return nullptr;
 }
 
-std::unique_ptr<blink::WebSourceBuffer> WebMediaSourceImpl::AddSourceBuffer(
+std::unique_ptr<WebSourceBuffer> WebMediaSourceImpl::AddSourceBuffer(
     std::unique_ptr<media::AudioDecoderConfig> audio_config,
     WebMediaSource::AddStatus& out_status /* out */) {
   std::string id = base::GenerateGUID();
@@ -59,7 +59,7 @@
   return nullptr;
 }
 
-std::unique_ptr<blink::WebSourceBuffer> WebMediaSourceImpl::AddSourceBuffer(
+std::unique_ptr<WebSourceBuffer> WebMediaSourceImpl::AddSourceBuffer(
     std::unique_ptr<media::VideoDecoderConfig> video_config,
     WebMediaSource::AddStatus& out_status /* out */) {
   std::string id = base::GenerateGUID();
diff --git a/third_party/blink/renderer/platform/media/web_media_source_impl.h b/third_party/blink/renderer/platform/media/web_media_source_impl.h
index f308fdab..efc0e46 100644
--- a/third_party/blink/renderer/platform/media/web_media_source_impl.h
+++ b/third_party/blink/renderer/platform/media/web_media_source_impl.h
@@ -18,22 +18,22 @@
 
 namespace blink {
 
-class PLATFORM_EXPORT WebMediaSourceImpl : public blink::WebMediaSource {
+class PLATFORM_EXPORT WebMediaSourceImpl : public WebMediaSource {
  public:
   WebMediaSourceImpl(media::ChunkDemuxer* demuxer);
   WebMediaSourceImpl(const WebMediaSourceImpl&) = delete;
   WebMediaSourceImpl& operator=(const WebMediaSourceImpl&) = delete;
   ~WebMediaSourceImpl() override;
 
-  // blink::WebMediaSource implementation.
-  std::unique_ptr<blink::WebSourceBuffer> AddSourceBuffer(
-      const blink::WebString& content_type,
-      const blink::WebString& codecs,
+  // WebMediaSource implementation.
+  std::unique_ptr<WebSourceBuffer> AddSourceBuffer(
+      const WebString& content_type,
+      const WebString& codecs,
       AddStatus& out_status /* out */) override;
-  std::unique_ptr<blink::WebSourceBuffer> AddSourceBuffer(
+  std::unique_ptr<WebSourceBuffer> AddSourceBuffer(
       std::unique_ptr<media::AudioDecoderConfig> audio_config,
       AddStatus& out_status /* out */) override;
-  std::unique_ptr<blink::WebSourceBuffer> AddSourceBuffer(
+  std::unique_ptr<WebSourceBuffer> AddSourceBuffer(
       std::unique_ptr<media::VideoDecoderConfig> video_config,
       AddStatus& out_status /* out */) override;
   double Duration() override;
diff --git a/third_party/blink/renderer/platform/media/web_source_buffer_impl.cc b/third_party/blink/renderer/platform/media/web_source_buffer_impl.cc
index 765d34a76..d5792123 100644
--- a/third_party/blink/renderer/platform/media/web_source_buffer_impl.cc
+++ b/third_party/blink/renderer/platform/media/web_source_buffer_impl.cc
@@ -22,11 +22,11 @@
 
 namespace blink {
 
-static blink::WebSourceBufferClient::ParseWarning ParseWarningToBlink(
+static WebSourceBufferClient::ParseWarning ParseWarningToBlink(
     const media::SourceBufferParseWarning warning) {
 #define CHROMIUM_PARSE_WARNING_TO_BLINK_ENUM_CASE(name) \
   case media::SourceBufferParseWarning::name:           \
-    return blink::WebSourceBufferClient::ParseWarning::name
+    return WebSourceBufferClient::ParseWarning::name
 
   switch (warning) {
     CHROMIUM_PARSE_WARNING_TO_BLINK_ENUM_CASE(
@@ -37,8 +37,7 @@
   }
 
   NOTREACHED();
-  return blink::WebSourceBufferClient::ParseWarning::
-      kKeyframeTimeGreaterThanDependant;
+  return WebSourceBufferClient::ParseWarning::kKeyframeTimeGreaterThanDependant;
 
 #undef CHROMIUM_PARSE_WARNING_TO_BLINK_ENUM_CASE
 }
@@ -77,7 +76,7 @@
 
 WebSourceBufferImpl::~WebSourceBufferImpl() = default;
 
-void WebSourceBufferImpl::SetClient(blink::WebSourceBufferClient* client) {
+void WebSourceBufferImpl::SetClient(WebSourceBufferClient* client) {
   DCHECK(client);
   DCHECK(!client_);
   client_ = client;
@@ -104,9 +103,9 @@
   return false;
 }
 
-blink::WebTimeRanges WebSourceBufferImpl::Buffered() {
+WebTimeRanges WebSourceBufferImpl::Buffered() {
   media::Ranges<base::TimeDelta> ranges = demuxer_->GetBufferedRanges(id_);
-  blink::WebTimeRanges result(ranges.size());
+  WebTimeRanges result(ranges.size());
   for (size_t i = 0; i < ranges.size(); i++) {
     result[i].start = ranges.start(i).InSecondsF();
     result[i].end = ranges.end(i).InSecondsF();
@@ -177,13 +176,13 @@
   demuxer_->Remove(id_, DoubleToTimeDelta(start), DoubleToTimeDelta(end));
 }
 
-bool WebSourceBufferImpl::CanChangeType(const blink::WebString& content_type,
-                                        const blink::WebString& codecs) {
+bool WebSourceBufferImpl::CanChangeType(const WebString& content_type,
+                                        const WebString& codecs) {
   return demuxer_->CanChangeType(id_, content_type.Utf8(), codecs.Utf8());
 }
 
-void WebSourceBufferImpl::ChangeType(const blink::WebString& content_type,
-                                     const blink::WebString& codecs) {
+void WebSourceBufferImpl::ChangeType(const WebString& content_type,
+                                     const WebString& codecs) {
   // Caller must first call ResetParserState() to flush any pending frames.
   DCHECK(!demuxer_->IsParsingMediaSegment(id_));
 
@@ -219,18 +218,17 @@
   client_ = nullptr;
 }
 
-blink::WebMediaPlayer::TrackType mediaTrackTypeToBlink(
-    media::MediaTrack::Type type) {
+WebMediaPlayer::TrackType mediaTrackTypeToBlink(media::MediaTrack::Type type) {
   switch (type) {
     case media::MediaTrack::Audio:
-      return blink::WebMediaPlayer::kAudioTrack;
+      return WebMediaPlayer::kAudioTrack;
     case media::MediaTrack::Text:
-      return blink::WebMediaPlayer::kTextTrack;
+      return WebMediaPlayer::kTextTrack;
     case media::MediaTrack::Video:
-      return blink::WebMediaPlayer::kVideoTrack;
+      return WebMediaPlayer::kVideoTrack;
   }
   NOTREACHED();
-  return blink::WebMediaPlayer::kAudioTrack;
+  return WebMediaPlayer::kAudioTrack;
 }
 
 void WebSourceBufferImpl::InitSegmentReceived(
@@ -238,16 +236,16 @@
   DCHECK(tracks.get());
   DVLOG(1) << __func__ << " tracks=" << tracks->tracks().size();
 
-  std::vector<blink::WebSourceBufferClient::MediaTrackInfo> trackInfoVector;
+  std::vector<WebSourceBufferClient::MediaTrackInfo> trackInfoVector;
   for (const auto& track : tracks->tracks()) {
-    blink::WebSourceBufferClient::MediaTrackInfo trackInfo;
+    WebSourceBufferClient::MediaTrackInfo trackInfo;
     trackInfo.track_type = mediaTrackTypeToBlink(track->type());
-    trackInfo.id = blink::WebString::FromUTF8(track->id().value());
-    trackInfo.byte_stream_track_id = blink::WebString::FromUTF8(
-        base::NumberToString(track->bytestream_track_id()));
-    trackInfo.kind = blink::WebString::FromUTF8(track->kind().value());
-    trackInfo.label = blink::WebString::FromUTF8(track->label().value());
-    trackInfo.language = blink::WebString::FromUTF8(track->language().value());
+    trackInfo.id = WebString::FromUTF8(track->id().value());
+    trackInfo.byte_stream_track_id =
+        WebString::FromUTF8(base::NumberToString(track->bytestream_track_id()));
+    trackInfo.kind = WebString::FromUTF8(track->kind().value());
+    trackInfo.label = WebString::FromUTF8(track->label().value());
+    trackInfo.language = WebString::FromUTF8(track->language().value());
     trackInfoVector.push_back(trackInfo);
   }
 
diff --git a/third_party/blink/renderer/platform/media/web_source_buffer_impl.h b/third_party/blink/renderer/platform/media/web_source_buffer_impl.h
index 00f82ec..2e8b3b54 100644
--- a/third_party/blink/renderer/platform/media/web_source_buffer_impl.h
+++ b/third_party/blink/renderer/platform/media/web_source_buffer_impl.h
@@ -23,18 +23,18 @@
 
 namespace blink {
 
-class PLATFORM_EXPORT WebSourceBufferImpl : public blink::WebSourceBuffer {
+class PLATFORM_EXPORT WebSourceBufferImpl : public WebSourceBuffer {
  public:
   WebSourceBufferImpl(const std::string& id, media::ChunkDemuxer* demuxer);
   WebSourceBufferImpl(const WebSourceBufferImpl&) = delete;
   WebSourceBufferImpl& operator=(const WebSourceBufferImpl&) = delete;
   ~WebSourceBufferImpl() override;
 
-  // blink::WebSourceBuffer implementation.
-  void SetClient(blink::WebSourceBufferClient* client) override;
+  // WebSourceBuffer implementation.
+  void SetClient(WebSourceBufferClient* client) override;
   bool GetGenerateTimestampsFlag() override;
   bool SetMode(AppendMode mode) override;
-  blink::WebTimeRanges Buffered() override;
+  WebTimeRanges Buffered() override;
   double HighestPresentationTimestamp() override;
   bool EvictCodedFrames(double currentPlaybackTime,
                         size_t newDataSize) override;
@@ -46,10 +46,10 @@
       double* timestamp_offset) override;
   void ResetParserState() override;
   void Remove(double start, double end) override;
-  bool CanChangeType(const blink::WebString& content_type,
-                     const blink::WebString& codecs) override;
-  void ChangeType(const blink::WebString& content_type,
-                  const blink::WebString& codecs) override;
+  bool CanChangeType(const WebString& content_type,
+                     const WebString& codecs) override;
+  void ChangeType(const WebString& content_type,
+                  const WebString& codecs) override;
   bool SetTimestampOffset(double offset) override;
   void SetAppendWindowStart(double start) override;
   void SetAppendWindowEnd(double end) override;
@@ -66,7 +66,7 @@
   std::string id_;
   media::ChunkDemuxer* demuxer_;  // Owned by WebMediaPlayerImpl.
 
-  blink::WebSourceBufferClient* client_;
+  WebSourceBufferClient* client_;
 
   // Controls the offset applied to timestamps when processing appended media
   // segments. It is initially 0, which indicates that no offset is being
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 001562d..e6a3edb 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -1022,6 +1022,7 @@
 crbug.com/982194 [ Win10 ] fast/writing-mode/border-image-vertical-lr.html [ Failure Pass ]
 
 ### Tests passing with LayoutNGBlockFragmentation enabled:
+virtual/layout_ng_block_frag/external/wpt/css/css-break/abspos-in-opacity-001.html [ Pass ]
 virtual/layout_ng_block_frag/external/wpt/css/css-break/avoid-border-break.html [ Pass ]
 virtual/layout_ng_block_frag/external/wpt/css/css-break/borders-000.html [ Pass ]
 virtual/layout_ng_block_frag/external/wpt/css/css-break/borders-001.html [ Pass ]
@@ -1047,6 +1048,7 @@
 virtual/layout_ng_block_frag/external/wpt/css/css-break/out-of-flow-in-multicolumn-030.html [ Pass ]
 virtual/layout_ng_block_frag/external/wpt/css/css-break/out-of-flow-in-multicolumn-032.html [ Pass ]
 virtual/layout_ng_block_frag/external/wpt/css/css-break/out-of-flow-in-multicolumn-034.html [ Pass ]
+virtual/layout_ng_block_frag/external/wpt/css/css-break/out-of-flow-in-multicolumn-035.html [ Pass ]
 virtual/layout_ng_block_frag/external/wpt/css/css-break/out-of-flow-in-multicolumn-036.html [ Pass ]
 virtual/layout_ng_block_frag/external/wpt/css/css-break/out-of-flow-in-multicolumn-038.html [ Pass ]
 virtual/layout_ng_block_frag/external/wpt/css/css-break/out-of-flow-in-multicolumn-039.html [ Pass ]
@@ -1074,6 +1076,7 @@
 virtual/layout_ng_block_frag/external/wpt/css/css-break/trailing-child-margin-000.html [ Pass ]
 virtual/layout_ng_block_frag/external/wpt/css/css-break/trailing-child-margin-002.html [ Pass ]
 virtual/layout_ng_block_frag/external/wpt/css/css-break/transform-006.html [ Pass ]
+virtual/layout_ng_block_frag/external/wpt/css/css-break/transform-008.html [ Pass ]
 virtual/layout_ng_block_frag/external/wpt/css/css-contain/contain-size-monolithic-002.html [ Pass ]
 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/abspos-containing-block-outside-spanner.html [ Pass ]
 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/balance-break-avoidance-001.html [ Pass ]
@@ -1151,11 +1154,12 @@
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/nested-with-padding.html [ Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/span/outer-column-break-after-inner-spanner-2.html [ Failure ]
 crbug.com/1079031 virtual/layout_ng_block_frag/fast/multicol/tall-line-in-short-block.html [ Failure ]
-crbug.com/1079031 virtual/layout_ng_block_frag/fast/multicol/transform-with-fixedpos.html [ Failure ]
 crbug.com/1058792 virtual/layout_ng_block_frag/fast/multicol/vertical-rl/composited-relpos-overlapping-will-change.html [ Failure ]
 
 ### With LayoutNGFragmentTraversal (and LayoutNGFragmentItem) enabled:
 
+crbug.com/1225304 virtual/layout_ng_fragment_traversal/external/wpt/css/CSS2/positioning/toogle-abspos-on-relpos-inline-child.html [ Failure ]
+
 # Lots of manual tests here; just skip everything - not too interesting for LayoutNGFragmentTraversal anyway:
 virtual/layout_ng_fragment_traversal/external/wpt/css/CSS2/cascade/* [ Skip ]
 virtual/layout_ng_fragment_traversal/external/wpt/css/CSS2/text/* [ Skip ]
@@ -3726,6 +3730,7 @@
 # Failure due to on-going off-thread paint worklet project.
 crbug.com/957457 virtual/off-main-thread-css-paint/external/wpt/css/css-paint-api/invalid-image-pending-script.https.html [ Crash ]
 
+crbug.com/829028 external/wpt/css/css-break/abspos-in-opacity-001.html [ Failure ]
 crbug.com/829028 external/wpt/css/css-break/avoid-border-break.html [ Failure ]
 crbug.com/829028 external/wpt/css/css-break/borders-000.html [ Failure ]
 crbug.com/829028 external/wpt/css/css-break/borders-001.html [ Failure ]
@@ -3751,6 +3756,7 @@
 crbug.com/829028 external/wpt/css/css-break/out-of-flow-in-multicolumn-030.html [ Failure ]
 crbug.com/829028 external/wpt/css/css-break/out-of-flow-in-multicolumn-032.html [ Failure ]
 crbug.com/829028 external/wpt/css/css-break/out-of-flow-in-multicolumn-034.html [ Failure ]
+crbug.com/829028 external/wpt/css/css-break/out-of-flow-in-multicolumn-035.html [ Failure ]
 crbug.com/829028 external/wpt/css/css-break/out-of-flow-in-multicolumn-036.html [ Failure ]
 crbug.com/829028 external/wpt/css/css-break/out-of-flow-in-multicolumn-038.html [ Failure ]
 crbug.com/829028 external/wpt/css/css-break/out-of-flow-in-multicolumn-039.html [ Failure ]
@@ -3785,6 +3791,8 @@
 crbug.com/1058792 external/wpt/css/css-break/transform-005.html [ Failure ]
 crbug.com/829028 external/wpt/css/css-break/transform-006.html [ Failure ]
 crbug.com/1058792 external/wpt/css/css-break/transform-007.html [ Failure ]
+crbug.com/829028 external/wpt/css/css-break/transform-008.html [ Failure ]
+crbug.com/1224888 external/wpt/css/css-break/transform-009.html [ Failure ]
 crbug.com/1156312 external/wpt/css/css-break/widows-orphans-017.html [ Failure ]
 crbug.com/829028 external/wpt/css/css-multicol/abspos-containing-block-outside-spanner.html [ Failure ]
 crbug.com/967329 external/wpt/css/css-multicol/columnfill-auto-max-height-001.html [ Failure ]
@@ -3842,6 +3850,7 @@
 crbug.com/829028 external/wpt/css/css-multicol/spanner-fragmentation-010.html [ Failure ]
 crbug.com/829028 external/wpt/css/css-multicol/spanner-fragmentation-011.html [ Failure ]
 crbug.com/1191124 external/wpt/css/css-multicol/spanner-fragmentation-012.html [ Failure ]
+crbug.com/1224888 external/wpt/css/css-multicol/spanner-in-opacity.html [ Failure ]
 
 crbug.com/1031667 external/wpt/css/css-pseudo/marker-content-007.tentative.html [ Failure ]
 crbug.com/1031667 external/wpt/css/css-pseudo/marker-content-008.tentative.html [ Failure ]
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/abspos-in-opacity-000-ref.html b/third_party/blink/web_tests/external/wpt/css/css-break/abspos-in-opacity-000-ref.html
new file mode 100644
index 0000000..b7013a9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/abspos-in-opacity-000-ref.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<p>There should be a purple square below.</p>
+<div style="width:100px; height:100px; background:blue;">
+  <div style="opacity:0.5;">
+    <div style="width:100px; height:100px; background:red;"></div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/abspos-in-opacity-000.html b/third_party/blink/web_tests/external/wpt/css/css-break/abspos-in-opacity-000.html
new file mode 100644
index 0000000..f41c0353
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/abspos-in-opacity-000.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/css-break-3/">
+<link rel="match" href="abspos-in-opacity-000-ref.html">
+<p>There should be a purple square below.</p>
+<div style="columns:2; column-gap:0; column-fill:auto; width:100px; height:100px; background:blue;">
+  <div style="opacity:0.5;">
+    <div style="position:absolute; width:100px; height:100px; background:red;"></div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/abspos-in-opacity-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-break/abspos-in-opacity-001-ref.html
new file mode 100644
index 0000000..b7013a9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/abspos-in-opacity-001-ref.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<p>There should be a purple square below.</p>
+<div style="width:100px; height:100px; background:blue;">
+  <div style="opacity:0.5;">
+    <div style="width:100px; height:100px; background:red;"></div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/abspos-in-opacity-001.html b/third_party/blink/web_tests/external/wpt/css/css-break/abspos-in-opacity-001.html
new file mode 100644
index 0000000..e81c558
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/abspos-in-opacity-001.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/css-break-3/">
+<link rel="match" href="abspos-in-opacity-001-ref.html">
+<p>There should be a purple square below.</p>
+<div style="columns:2; column-gap:0; column-fill:auto; width:100px; height:100px; background:blue;">
+  <div style="position:relative;">
+    <div style="opacity:0.5; height:200px;">
+      <div style="position:absolute; width:50px; height:200px; background:red;"></div>
+    </div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/change-inline-color-ref.html b/third_party/blink/web_tests/external/wpt/css/css-break/change-inline-color-ref.html
new file mode 100644
index 0000000..7f99f57
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/change-inline-color-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/css-break-3/">
+<style>
+  .fakecolumn {
+      width: 1em;
+      text-align: center;
+  }
+</style>
+<p>The word PASS should be seen below.</p>
+<div style="display:flex; color:green;">
+  <div class="fakecolumn">P</div>
+  <div class="fakecolumn">A</div>
+  <div class="fakecolumn">S</div>
+  <div class="fakecolumn">S</div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/change-inline-color.html b/third_party/blink/web_tests/external/wpt/css/css-break/change-inline-color.html
new file mode 100644
index 0000000..c4334af
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/change-inline-color.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/css-break-3/">
+<link rel="match" href="change-inline-color-ref.html">
+<p>The word PASS should be seen below.</p>
+<div style="columns:4; width:4em; text-align:center; column-gap:0; orphans:1; widows:1; color:white;">
+  <span id="span">
+    P A S S
+  </span>
+</div>
+<script>
+  requestAnimationFrame(()=> {
+      requestAnimationFrame(()=> {
+          span.style.color = "green";
+      });
+  });
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/contain-strict-with-opacity-and-oof-ref.html b/third_party/blink/web_tests/external/wpt/css/css-break/contain-strict-with-opacity-and-oof-ref.html
new file mode 100644
index 0000000..a9c82c4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/contain-strict-with-opacity-and-oof-ref.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<p>There should be a (pale) green square below, and no (pale) red.</p>
+<div style="will-change:transform; contain:strict; width:100px; height:100px;">
+  <div style="opacity:0.2; width:100px; height:100px;">
+    <div style="width:100px; height:100px; background:green;"></div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/contain-strict-with-opacity-and-oof.html b/third_party/blink/web_tests/external/wpt/css/css-break/contain-strict-with-opacity-and-oof.html
new file mode 100644
index 0000000..b3323a6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/contain-strict-with-opacity-and-oof.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/css-break-3/">
+<link rel="match" href="contain-strict-with-opacity-and-oof-ref.html">
+<p>There should be a (pale) green square below, and no (pale) red.</p>
+<div style="columns:3; margin-top:-50px; column-fill:auto; height:200px;">
+  <div style="height:50px;"></div>
+  <div style="will-change:transform; contain:strict; width:100px; height:100px;">
+    <div style="opacity:0.2; width:100px; height:100px; background:red;">
+      <div style="position:absolute; width:100px; height:100px; background:green;"></div>
+    </div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-035.html b/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-035.html
index 6a2d527..f1fff40 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-035.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/out-of-flow-in-multicolumn-035.html
@@ -11,7 +11,8 @@
     column-gap: 0px;
     height: 100px;
     width: 100px;
-    margin-left: -200px;
+    margin-left: -250px;
+    margin-top: -50px;
   }
   .abs {
     position: absolute;
@@ -31,7 +32,7 @@
 <p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
 <div class="multicol">
   <div style="height: 400px;"></div>
-  <div style="transform: translateX(0);">
+  <div style="transform: translate(50px,50px); ">
     <div style="height: 200px;"></div>
     <div class="abs">
       <div class="fixed"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/transform-008-ref.html b/third_party/blink/web_tests/external/wpt/css/css-break/transform-008-ref.html
new file mode 100644
index 0000000..2a16079
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/transform-008-ref.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<style>
+  .fakecolumn {
+      width: 100px;
+      height: 100px;
+  }
+  .relpos {
+      position: relative;
+      top: 50px;
+      left: 50px;
+      width: 50px;
+  }
+  .transform {
+      transform: rotate(45deg);
+      height: 100%;
+  }
+  .abspos {
+      position: absolute;
+      width: 100%;
+      height: 100%;
+      background: green;
+  }
+</style>
+<p>Below there should be two green squares, and one green rectangle between
+  them. They should all be rotated.</p>
+<div style="display:flex;">
+  <div class="fakecolumn">
+    <div class="relpos" style="margin-top:50px; height:50px;">
+      <div class="transform">
+        <div class="abspos"></div>
+      </div>
+    </div>
+  </div>
+  <div class="fakecolumn">
+    <div class="relpos" style="height:100px;">
+      <div class="transform">
+        <div class="abspos"></div>
+      </div>
+    </div>
+  </div>
+  <div class="fakecolumn">
+    <div class="relpos" style="height:50px;">
+      <div class="transform">
+        <div class="abspos"></div>
+      </div>
+    </div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/transform-008.html b/third_party/blink/web_tests/external/wpt/css/css-break/transform-008.html
new file mode 100644
index 0000000..b3b80d7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/transform-008.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/css-break-3/#transforms">
+<link rel="match" href="transform-008-ref.html">
+<style>
+  .relpos {
+      position: relative;
+      top: 50px;
+      left: 50px;
+      width: 50px;
+  }
+  .transform {
+      transform: rotate(45deg);
+      height: 200px;
+  }
+  .abspos {
+      position: absolute;
+      width: 100%;
+      height: 100%;
+      background: green;
+  }
+</style>
+<p>Below there should be two green squares, and one green rectangle between
+  them. They should all be rotated.</p>
+<div style="columns:3; column-gap:0; column-fill:auto; width:300px; height:100px;">
+  <div class="relpos" style="margin-top:50px;">
+    <div class="transform">
+      <div class="abspos"></div>
+    </div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/transform-009-ref.html b/third_party/blink/web_tests/external/wpt/css/css-break/transform-009-ref.html
new file mode 100644
index 0000000..d7d3ebf
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/transform-009-ref.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/css-break-3/#transforms">
+<style>
+  .fakecolumn {
+      width: 100px;
+      height: 100px;
+  }
+  .relpos {
+      position: relative;
+      width: 30px;
+      top: 50px;
+      left: 50px;
+  }
+  .transform {
+      transform: rotate(45deg);
+      height: 100%;
+  }
+  .abspos {
+      position: absolute;
+      width: 100%;
+      height: 100%;
+      background: green;
+  }
+</style>
+<p>Below there should be six rotated green rectangles (not all with the same
+  size).</p>
+<div style="display:flex;">
+  <div class="fakecolumn">
+    <div class="relpos" style="margin-top:50px;">
+      <div class="transform" style="height:0;">
+        <div class="abspos" style="height:50px;"></div>
+      </div>
+    </div>
+  </div>
+  <div class="fakecolumn">
+    <div class="relpos">
+      <div class="transform" style="height:0;">
+        <div class="abspos" style="height:100px;"></div>
+      </div>
+    </div>
+  </div>
+  <div class="fakecolumn">
+    <div class="relpos" style="margin-top:50px;">
+      <div class="transform" style="height:50px;">
+        <div class="abspos" style="top:-50px; height:100px;"></div>
+      </div>
+    </div>
+  </div>
+  <div class="fakecolumn">
+    <div class="relpos">
+      <div class="transform" style="height:100px;">
+        <div class="abspos"></div>
+      </div>
+    </div>
+  </div>
+  <div class="fakecolumn">
+    <div class="relpos">
+      <div class="transform" style="height:0;">
+        <div class="abspos" style="height:100px;"></div>
+      </div>
+    </div>
+  </div>
+  <div class="fakecolumn">
+    <div class="relpos">
+      <div class="transform" style="height:0;">
+        <div class="abspos" style="height:50px;"></div>
+      </div>
+    </div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/transform-009.html b/third_party/blink/web_tests/external/wpt/css/css-break/transform-009.html
new file mode 100644
index 0000000..f0653f79
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/transform-009.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/css-break-3/#transforms">
+<link rel="match" href="transform-009-ref.html">
+<style>
+  .relpos {
+      position: relative;
+      width: 30px;
+      top: 50px;
+      left: 50px;
+  }
+  .transform {
+      transform: rotate(45deg);
+      height: 150px;
+  }
+  .abspos {
+      position: absolute;
+      width: 100%;
+      height: 500px;
+      top: -200px;
+      background: green;
+  }
+</style>
+<p>Below there should be six rotated green rectangles (not all with the same
+  size).</p>
+<div style="columns:5; column-gap:0; column-fill:auto; width:500px; height:100px;">
+  <div style="height:250px;"></div>
+  <div class="relpos">
+    <div class="transform">
+      <div class="abspos"></div>
+    </div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/spanner-in-opacity-ref.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/spanner-in-opacity-ref.html
new file mode 100644
index 0000000..e981eac
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/spanner-in-opacity-ref.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<p>Test passes if there is a purple square below.</p>
+<div style="width:100px; background:blue;">
+  <div style="opacity:0.5;">
+    <div style="height:100px; background:red;"></div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/spanner-in-opacity.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/spanner-in-opacity.html
new file mode 100644
index 0000000..78b1ac8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/spanner-in-opacity.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/css-break-3/">
+<link rel="match" href="spanner-in-opacity-ref.html">
+<p>Test passes if there is a purple square below.</p>
+<div style="columns:2; column-fill:auto; column-gap:0; width:100px; background:blue;">
+  <div style="opacity:0.5;">
+    <div style="column-span:all; height:100px; background:red;"></div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/OWNERS b/third_party/blink/web_tests/external/wpt/webaudio/OWNERS
index a837fc9b..5248064 100644
--- a/third_party/blink/web_tests/external/wpt/webaudio/OWNERS
+++ b/third_party/blink/web_tests/external/wpt/webaudio/OWNERS
@@ -1,2 +1 @@
 hongchan@chromium.org
-rtoy@chromium.org
diff --git a/third_party/blink/web_tests/webaudio/OWNERS b/third_party/blink/web_tests/webaudio/OWNERS
index a837fc9b..5248064 100644
--- a/third_party/blink/web_tests/webaudio/OWNERS
+++ b/third_party/blink/web_tests/webaudio/OWNERS
@@ -1,2 +1 @@
 hongchan@chromium.org
-rtoy@chromium.org
diff --git a/third_party/blink/web_tests/wpt_internal/webid/get-argument-validation.https.html b/third_party/blink/web_tests/wpt_internal/webid/get-argument-validation.https.html
index dc71265..a9f70d6f 100644
--- a/third_party/blink/web_tests/wpt_internal/webid/get-argument-validation.https.html
+++ b/third_party/blink/web_tests/wpt_internal/webid/get-argument-validation.https.html
@@ -7,20 +7,12 @@
 <script src="/resources/testharnessreport.js"></script>
 
 <script>
-  // request
-  promise_test(async t => {
-    assert_implements(navigator.id, 'missing navigator.id.');
-    const result = navigator.id.get({
-      provider: 'https://idp.test',
-    });
-    return promise_rejects_js(t, TypeError, result);
-  }, "Reject when request is missing");
-
   // provider
   promise_test(async t => {
     assert_implements(navigator.id, 'missing navigator.id.');
     const result = navigator.id.get({
-      request: ''
+      client_id: '1',
+      nonce: '2',
     });
     return promise_rejects_js(t, TypeError, result);
   }, "Reject when provider is missing" );
@@ -29,7 +21,8 @@
     assert_implements(navigator.id, 'missing navigator.id.');
     const result = navigator.id.get({
       provider: 'not_a_url',
-      request: '',
+      client_id: '1',
+      nonce: '2',
     });
     return promise_rejects_dom(t, 'SyntaxError', result);
   }, `Reject when provider is an invalid URL`);
@@ -39,7 +32,8 @@
     assert_implements(navigator.id, 'missing navigator.id.');
     const result = navigator.id.get({
       provider: 'https://idp.test',
-      request: '',
+      client_id: '1',
+      nonce: '2',
       mode: 'invalid_mode'
     });
     return promise_rejects_js(t, TypeError, result);
diff --git a/third_party/blink/web_tests/wpt_internal/webid/get-permission-basic.https.html b/third_party/blink/web_tests/wpt_internal/webid/get-permission-basic.https.html
index 2de3386..38b450b 100644
--- a/third_party/blink/web_tests/wpt_internal/webid/get-permission-basic.https.html
+++ b/third_party/blink/web_tests/wpt_internal/webid/get-permission-basic.https.html
@@ -10,7 +10,8 @@
   import {webid_test} from './resources/webid-helper.js';
   const test_options = {
     provider: 'https://idp.test',
-    request: ''
+    client_id: '1',
+    nonce: '2',
   };
 
   webid_test(async (t, mock) => {
diff --git a/tools/clang/rewrite_raw_ptr_fields/RewriteRawPtrFields.cpp b/tools/clang/rewrite_raw_ptr_fields/RewriteRawPtrFields.cpp
index 9107c20..e331dd6 100644
--- a/tools/clang/rewrite_raw_ptr_fields/RewriteRawPtrFields.cpp
+++ b/tools/clang/rewrite_raw_ptr_fields/RewriteRawPtrFields.cpp
@@ -241,6 +241,7 @@
         return true;
 
       case clang::Language::CXX:
+      case clang::Language::OpenCLCXX:
       case clang::Language::ObjCXX:
         return false;
     }
@@ -436,6 +437,12 @@
   return !Node.isExplicitSpecialization();
 }
 
+// Matches CXXRecordDecls that are classified as trivial:
+// https://en.cppreference.com/w/cpp/named_req/TrivialType
+AST_MATCHER(clang::CXXRecordDecl, isTrivial) {
+  return Node.isTrivial();
+}
+
 // Given:
 //   template <typename T, typename T2> void foo(T t, T2 t2) {};  // N1 and N4
 //   template <typename T2> void foo<int, T2>(int t, T2 t) {};    // N2
@@ -1290,13 +1297,15 @@
   match_finder.addMatcher(union_field_decl_matcher, &union_field_decl_writer);
 
   // Matches rewritable fields of struct `SomeStruct` if that struct happens to
-  // be a destination type of a `reinterpret_cast<SomeStruct*>` cast.
+  // be a destination type of a `reinterpret_cast<SomeStruct*>` cast and is a
+  // trivial type (otherwise `reinterpret_cast<SomeStruct*>` wouldn't be valid
+  // before the rewrite if it skipped non-trivial constructors).
   auto reinterpret_cast_struct_matcher =
-      cxxReinterpretCastExpr(hasDestinationType(
-          pointerType(pointee(hasUnqualifiedDesugaredType(recordType(
-              hasDeclaration(recordDecl(forEach(field_decl_matcher)))))))));
-  FilteredExprWriter reinterpret_cast_struct_writer(&output_helper,
-                                                    "reinterpret-cast-struct");
+      cxxReinterpretCastExpr(hasDestinationType(pointerType(pointee(
+          hasUnqualifiedDesugaredType(recordType(hasDeclaration(cxxRecordDecl(
+              allOf(forEach(field_decl_matcher), isTrivial())))))))));
+  FilteredExprWriter reinterpret_cast_struct_writer(
+      &output_helper, "reinterpret-cast-trivial-type");
   match_finder.addMatcher(reinterpret_cast_struct_matcher,
                           &reinterpret_cast_struct_writer);
 
diff --git a/tools/clang/rewrite_raw_ptr_fields/tests/gen-in-out-arg-expected.txt b/tools/clang/rewrite_raw_ptr_fields/tests/gen-in-out-arg-expected.txt
index c174fb7..36a442b 100644
--- a/tools/clang/rewrite_raw_ptr_fields/tests/gen-in-out-arg-expected.txt
+++ b/tools/clang/rewrite_raw_ptr_fields/tests/gen-in-out-arg-expected.txt
@@ -1,7 +1,7 @@
 ==== BEGIN EDITS ====
 include-user-header:::gen-in-out-arg-actual.cc:::-1:::-1:::base/memory/checked_ptr.h
 r:::gen-in-out-arg-actual.cc:::1090:::3:::CheckedPtr<T> 
-r:::gen-in-out-arg-actual.cc:::2875:::3:::CheckedPtr<T> 
+r:::gen-in-out-arg-actual.cc:::2873:::3:::CheckedPtr<T> 
 r:::gen-in-out-arg-actual.cc:::789:::11:::CheckedPtr<SomeClass> 
 r:::gen-in-out-arg-actual.cc:::813:::11:::CheckedPtr<SomeClass> 
 r:::gen-in-out-arg-actual.cc:::842:::11:::CheckedPtr<SomeClass> 
diff --git a/tools/clang/rewrite_raw_ptr_fields/tests/gen-reinterpret-cast-expected.txt b/tools/clang/rewrite_raw_ptr_fields/tests/gen-reinterpret-cast-expected.txt
index a9a48ba36..1894e20 100644
--- a/tools/clang/rewrite_raw_ptr_fields/tests/gen-reinterpret-cast-expected.txt
+++ b/tools/clang/rewrite_raw_ptr_fields/tests/gen-reinterpret-cast-expected.txt
@@ -1,12 +1,13 @@
 ==== BEGIN EDITS ====
 include-user-header:::gen-reinterpret-cast-actual.cc:::-1:::-1:::base/memory/checked_ptr.h
-r:::gen-reinterpret-cast-actual.cc:::1048:::5:::CheckedPtr<int> 
-r:::gen-reinterpret-cast-actual.cc:::1327:::5:::CheckedPtr<int> 
-r:::gen-reinterpret-cast-actual.cc:::1445:::5:::CheckedPtr<int> 
-r:::gen-reinterpret-cast-actual.cc:::976:::5:::CheckedPtr<int> 
+r:::gen-reinterpret-cast-actual.cc:::1000:::5:::CheckedPtr<int> 
+r:::gen-reinterpret-cast-actual.cc:::1072:::5:::CheckedPtr<int> 
+r:::gen-reinterpret-cast-actual.cc:::1459:::5:::CheckedPtr<int> 
+r:::gen-reinterpret-cast-actual.cc:::2317:::5:::CheckedPtr<int> 
+r:::gen-reinterpret-cast-actual.cc:::2570:::5:::CheckedPtr<int> 
 ==== END EDITS ====
 ==== BEGIN FIELD FILTERS ====
-ReinterpretedClass1::ptr2_  # reinterpret-cast-struct
-ReinterpretedClass1::ptr_  # reinterpret-cast-struct
-ReinterpretedClass2::ptr_  # reinterpret-cast-struct
+ReinterpretedClass1::ptr2_  # reinterpret-cast-trivial-type
+ReinterpretedClass1::ptr_  # reinterpret-cast-trivial-type
+ReinterpretedClass2::ptr_  # reinterpret-cast-trivial-type
 ==== END FIELD FILTERS ====
diff --git a/tools/clang/rewrite_raw_ptr_fields/tests/gen-reinterpret-cast-test.cc b/tools/clang/rewrite_raw_ptr_fields/tests/gen-reinterpret-cast-test.cc
index 2f9d92b..0e3c16a 100644
--- a/tools/clang/rewrite_raw_ptr_fields/tests/gen-reinterpret-cast-test.cc
+++ b/tools/clang/rewrite_raw_ptr_fields/tests/gen-reinterpret-cast-test.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <type_traits>
+
 // This file (and other gen-*-test.cc files) tests generation of output for
 // --field-filter-file and therefore the expectations file
 // (gen-char-expected.txt) needs to be compared against the raw output of the
@@ -22,6 +24,8 @@
   // All fields in ReinterpretedClass1 should be emitted.
   int* ptr2_;
 };
+static_assert(std::is_trivial<ReinterpretedClass1>::value,
+              "ReinterpretedClass1 is trivial");
 
 class ReinterpretedClass2 {
   // The field below should be emitted as candidates for the
@@ -30,14 +34,36 @@
   // https://crbug.com/1165613.
   int* ptr_;
 };
+static_assert(std::is_trivial<ReinterpretedClass2>::value,
+              "ReinterpretedClass2 is trivial");
+
+class ReinterpretedNonTrivialClass3 {
+  // User-defined constructor means that ReinterpretedNonTrivialClass3 is
+  // non-trivial.
+  ReinterpretedNonTrivialClass3() : ptr_(nullptr) {}
+
+  // This field should not be emitted as a candidate for --field-filter-file,
+  // because we only want to exclude cases where a `reinterpret_cast` is 1)
+  // valid before the rewrite and 2) invalid after the rewrite (e.g. because it
+  // skips CheckedPtr's constructors).  A reinterpret_cast of a pointer to
+  // non-trivial type would have been invalid before the rewrite if it skipped
+  // the (non-trivial) constructors.  See also the discussion in
+  // https://groups.google.com/a/google.com/g/chrome-memory-safety/c/MwnBj_EuILg/m/1cVmcBOMBAAJ
+  int* ptr_;
+};
+static_assert(!std::is_trivial<ReinterpretedNonTrivialClass3>::value,
+              "ReinterpretedNonTrivialClass3 is *not* trivial");
 
 class SomeOtherClass {
   // This field should not be emitted as a candidate for --field-filter-file.
   int* ptr_;
 };
+static_assert(std::is_trivial<SomeOtherClass>::value,
+              "SomeOtherClass is trivial");
 
 void foo() {
   void* void_ptr = nullptr;
   auto* p1 = reinterpret_cast<ReinterpretedClass1*>(void_ptr);
   auto* p2 = reinterpret_cast<const ReinterpretedClass2*>(void_ptr);
+  auto* p3 = reinterpret_cast<const ReinterpretedNonTrivialClass3*>(void_ptr);
 }
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 53b6205b..5ff46d9 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -341,6 +341,7 @@
       'linux-chromeos-js-code-coverage': 'chromeos_with_codecs_release_bot_javascript_coverage',
       'linux-chromium-tests-staging-builder': 'release_bot',
       'linux-code-coverage': 'clang_code_coverage',
+      'linux-exp-code-coverage': 'clang_code_coverage',
       'linux-example-builder': 'release_bot',
       'linux-fieldtrial-rel': 'release_bot_minimal_symbols',
       'linux-backuprefptr-x64-fyi-rel': 'release_trybot_backuprefptr_x64',
diff --git a/tools/mb/mb_config_expectations/chromium.fyi.json b/tools/mb/mb_config_expectations/chromium.fyi.json
index 887d811..b7d21d8 100644
--- a/tools/mb/mb_config_expectations/chromium.fyi.json
+++ b/tools/mb/mb_config_expectations/chromium.fyi.json
@@ -900,6 +900,16 @@
       "use_goma": true
     }
   },
+  "linux-exp-code-coverage": {
+    "gn_args": {
+      "is_clang": true,
+      "is_component_build": false,
+      "is_debug": false,
+      "symbol_level": 0,
+      "use_clang_coverage": true,
+      "use_goma": true
+    }
+  },
   "linux-fieldtrial-rel": {
     "gn_args": {
       "is_component_build": false,
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index c79ad39..4649c32 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -25868,7 +25868,7 @@
   <int value="862" label="DeviceScheduledReboot"/>
   <int value="863" label="ReportDeviceLoginLogout"/>
   <int value="864" label="RemoteDebuggingAllowed"/>
-  <int value="865" label="ManagedWebAppsAccessToDeviceAttributesAllowed"/>
+  <int value="865" label="DeviceAttributesAllowedForOrigins"/>
   <int value="866" label="BrowserSwitcherParsingMode"/>
   <int value="867" label="DefaultJavaScriptJitSetting"/>
   <int value="868" label="JavaScriptJitAllowedForSites"/>
@@ -46671,6 +46671,7 @@
   <int value="-1720653947" label="WebRtcHybridAgc:disabled"/>
   <int value="-1719833926" label="disable-answers-in-suggest"/>
   <int value="-1719699712" label="AudioPlayerJsModules:enabled"/>
+  <int value="-1718644168" label="SharingHubLinkToggle:disabled"/>
   <int value="-1718074215" label="HomepageSettingsUIConversion:enabled"/>
   <int value="-1716654100" label="tab-capture-downscale-quality"/>
   <int value="-1716140224" label="EnableEmbeddedAssistantUI:disabled"/>
@@ -50837,6 +50838,7 @@
   <int value="1717788959" label="SlowDCTimerInterruptsWin:disabled"/>
   <int value="1717987538" label="NTPTilesLowerResolutionFavicons:enabled"/>
   <int value="1718341860" label="NTPButton:enabled"/>
+  <int value="1718421370" label="SharingHubLinkToggle:enabled"/>
   <int value="1719189460" label="EnablePasswordSelection:disabled"/>
   <int value="1719958026" label="QueryTiles:enabled"/>
   <int value="1722748383" label="EnableAppReinstallZeroState:disabled"/>
diff --git a/tools/metrics/histograms/histograms_xml/memory/histograms.xml b/tools/metrics/histograms/histograms_xml/memory/histograms.xml
index 097f1c5c..aa9fdda 100644
--- a/tools/metrics/histograms/histograms_xml/memory/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/memory/histograms.xml
@@ -1921,7 +1921,7 @@
 </histogram>
 
 <histogram name="Memory.PaintPreviewCompositor.ResidentSet" units="MiB"
-    expires_after="2021-08-15">
+    expires_after="2021-10-17">
   <owner>ckitagawa@chromium.org</owner>
   <owner>fredmello@chromium.org</owner>
   <owner>mahmoudi@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/service/histograms.xml b/tools/metrics/histograms/histograms_xml/service/histograms.xml
index b7b7258..a3adf1e 100644
--- a/tools/metrics/histograms/histograms_xml/service/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/service/histograms.xml
@@ -1185,7 +1185,7 @@
 </histogram>
 
 <histogram name="ServiceWorkerCache.Cache.Browser.Match.RelatedFetchEvent"
-    units="ms" expires_after="2021-08-01">
+    units="ms" expires_after="2022-08-01">
   <owner>wanderview@chromium.org</owner>
   <owner>chrome-owp-storage@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/web_audio/histograms.xml b/tools/metrics/histograms/histograms_xml/web_audio/histograms.xml
index ca13433..8aaed2c 100644
--- a/tools/metrics/histograms/histograms_xml/web_audio/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/web_audio/histograms.xml
@@ -23,7 +23,6 @@
 
 <histogram name="WebAudio.AudioBuffer.Length" units="frames"
     expires_after="2021-08-22">
-  <owner>rtoy@chromium.org</owner>
   <owner>hongchan@chromium.org</owner>
   <summary>
     The length (in frames) requested by createBuffer(). Recorded for every call
@@ -33,7 +32,6 @@
 
 <histogram name="WebAudio.AudioBuffer.NumberOfChannels" units="units"
     expires_after="2021-11-14">
-  <owner>rtoy@chromium.org</owner>
   <owner>hongchan@chromium.org</owner>
   <summary>
     The number of channels requested by createBuffer(). Recorded for every call
@@ -43,7 +41,6 @@
 
 <histogram name="WebAudio.AudioBuffer.SampleRate384kHz" units="Hz"
     expires_after="2021-12-26">
-  <owner>rtoy@chromium.org</owner>
   <owner>hongchan@chromium.org</owner>
   <summary>
     The sample rate (in Hz) requested by createBuffer(). Recorded for every call
@@ -53,7 +50,6 @@
 
 <histogram name="WebAudio.AudioBuffer.SampleRateRatio384kHz" units="units"
     expires_after="2021-10-25">
-  <owner>rtoy@chromium.org</owner>
   <owner>hongchan@chromium.org</owner>
   <summary>
     The ratio of the buffer sample rate from createBuffer() to the context
@@ -64,7 +60,6 @@
 
 <histogram name="WebAudio.AudioContext.HardwareSampleRate" units="Hz"
     expires_after="2021-09-05">
-  <owner>rtoy@chromium.org</owner>
   <owner>hongchan@chromium.org</owner>
   <summary>
     The hardware sample rate (in Hz) used by an AudioContext. Recorded for every
@@ -74,7 +69,6 @@
 
 <histogram name="WebAudio.AudioContext.latencyHintCategory" units="units"
     expires_after="2022-01-02">
-  <owner>rtoy@chromium.org</owner>
   <owner>hongchan@chromium.org</owner>
   <summary>
     If provided, the latencyHint option category of &quot;interactive&quot;,
@@ -87,7 +81,6 @@
 
 <histogram name="WebAudio.AudioContext.latencyHintMilliSeconds" units="ms"
     expires_after="2022-01-02">
-  <owner>rtoy@chromium.org</owner>
   <owner>hongchan@chromium.org</owner>
   <summary>
     If the latencyHint is provided and is a floating-point number, the value in
@@ -98,7 +91,6 @@
 
 <histogram name="WebAudio.AudioContext.MaxChannelsAvailable" units="units"
     expires_after="2022-01-06">
-  <owner>rtoy@chromium.org</owner>
   <owner>hongchan@chromium.org</owner>
   <summary>
     The maximum number of (hardware) channels available in an AudioContext.
@@ -109,7 +101,6 @@
 
 <histogram name="WebAudio.AudioContextOptions.sampleRate" units="Hz"
     expires_after="2021-08-09">
-  <owner>rtoy@chromium.org</owner>
   <owner>hongchan@chromium.org</owner>
   <summary>
     The sample rate requested by developer to be used as the sample rate when
@@ -120,7 +111,6 @@
 
 <histogram name="WebAudio.AudioContextOptions.sampleRateRatio" units="units"
     expires_after="2021-08-09">
-  <owner>rtoy@chromium.org</owner>
   <owner>hongchan@chromium.org</owner>
   <summary>
     The ratio of the user-selected sample rate to the hardware sample rate of an
@@ -131,7 +121,6 @@
 
 <histogram name="WebAudio.AudioDestination.CallbackBufferSize" units="units"
     expires_after="2021-09-05">
-  <owner>rtoy@chromium.org</owner>
   <owner>hongchan@chromium.org</owner>
   <summary>
     The callback buffer size (in audio frames) for WebAudio rendering between
@@ -143,7 +132,6 @@
 
 <histogram name="WebAudio.AudioDestination.HardwareBufferSize" units="units"
     expires_after="2021-12-12">
-  <owner>rtoy@chromium.org</owner>
   <owner>hongchan@chromium.org</owner>
   <summary>
     The buffer size (in audio frames) for WebAudio rendering recommended by the
@@ -155,7 +143,6 @@
     expires_after="2021-08-09">
   <owner>hongchan@chromium.org</owner>
   <owner>media-dev@chromium.org</owner>
-  <owner>rtoy@chromium.org</owner>
   <summary>
     The autoplay status of an AudioContext when destroyed. This include all
     types of frames. In order to know the value only for main frames, the
@@ -167,7 +154,6 @@
     expires_after="2021-10-04">
   <owner>hongchan@chromium.org</owner>
   <owner>media-dev@chromium.org</owner>
-  <owner>rtoy@chromium.org</owner>
   <summary>
     The autoplay status of an AudioContext when destroyed in a cross-origin
     frame.
@@ -178,7 +164,6 @@
     enum="WebAudioAutoplayUnlockType" expires_after="2021-06-01">
   <owner>hongchan@chromium.org</owner>
   <owner>media-dev@chromium.org</owner>
-  <owner>rtoy@chromium.org</owner>
   <summary>
     Records how an AudioContext was unlocked (if it was). This is recorded when
     the AudioContext is destroyed.
@@ -187,7 +172,6 @@
 
 <histogram name="WebAudio.BiquadFilter.Type" enum="BiquadFilterType"
     expires_after="2022-01-06">
-  <owner>rtoy@chromium.org</owner>
   <owner>hongchan@chromium.org</owner>
   <summary>
     The type of the BiquadFilterNode. Recorded each time the type is set. This
@@ -199,7 +183,6 @@
 
 <histogram name="WebAudio.ConvolverNode.ImpulseResponseLength" units="ms"
     expires_after="2021-12-19">
-  <owner>rtoy@chromium.org</owner>
   <owner>hongchan@chromium.org</owner>
   <summary>
     The duration in millisec of impulse responses for a ConvolverNode. Recorded
@@ -209,7 +192,6 @@
 
 <histogram name="WebAudio.IIRFilterNode.Order" units="units"
     expires_after="2022-01-06">
-  <owner>rtoy@chromium.org</owner>
   <owner>hongchan@chromium.org</owner>
   <summary>
     The order of the WebAudio IIRFilterNode. The order is one less than the
@@ -223,7 +205,6 @@
   <obsolete>
     Removed 2021-01-12. See crbug.com/1165240.
   </obsolete>
-  <owner>rtoy@chromium.org</owner>
   <owner>hongchan@chromium.org</owner>
   <summary>
     The number of channels specified for the offline audio context. Recorded for
@@ -237,7 +218,6 @@
   <obsolete>
     Removed 2021-01-12. See crbug.com/1165240.
   </obsolete>
-  <owner>rtoy@chromium.org</owner>
   <owner>hongchan@chromium.org</owner>
   <summary>
     The length (in frames) specified for the offline audio context. Recorded for
@@ -251,7 +231,6 @@
   <obsolete>
     Removed 2021-01-12. See crbug.com/1165240.
   </obsolete>
-  <owner>rtoy@chromium.org</owner>
   <owner>hongchan@chromium.org</owner>
   <summary>
     The sample rate (in Hz) specified for the offline audio context. Recorded
@@ -262,7 +241,6 @@
 
 <histogram name="WebAudio.PannerNode.PanningModel" enum="PanningModelType"
     expires_after="2022-01-06">
-  <owner>rtoy@chromium.org</owner>
   <owner>hongchan@chromium.org</owner>
   <summary>
     The panning model for the PannerNode. Recorded once with the default value
@@ -275,7 +253,6 @@
 
 <histogram name="WebAudio.PushPullFIFO.UnderflowGlitches" enum="Boolean"
     expires_after="2022-01-06">
-  <owner>rtoy@chromium.org</owner>
   <owner>hongchan@chromium.org</owner>
   <summary>
     Captures if WebAudio caused glitches or not due to the FIFO underflow. It is
@@ -286,7 +263,6 @@
 
 <histogram name="WebAudio.PushPullFIFO.UnderflowPercentage" units="%"
     expires_after="2022-01-06">
-  <owner>rtoy@chromium.org</owner>
   <owner>hongchan@chromium.org</owner>
   <summary>
     Percentage of FIFO underflow happened due to the the missed deadline of
diff --git a/tools/perf/OWNERS b/tools/perf/OWNERS
index 6fe36de..05eacd34 100644
--- a/tools/perf/OWNERS
+++ b/tools/perf/OWNERS
@@ -18,6 +18,9 @@
 eyaich@chromium.org
 sullivan@chromium.org
 
+# For V8 and system_health stories.
+cbruni@chromium.org
+
 # For page_cycler and loading benchmarks related changes.
 kouhei@chromium.org
 
diff --git a/tools/perf/benchmark.csv b/tools/perf/benchmark.csv
index 74b3a56..592d70c 100644
--- a/tools/perf/benchmark.csv
+++ b/tools/perf/benchmark.csv
@@ -22,7 +22,7 @@
 blink_perf.sanitizer-api,lyf@chromium.org,Blink>Security>SanitizerAPI,https://bit.ly/blink-perf-benchmarks,all
 blink_perf.shadow_dom,masonf@chromium.org,Blink>DOM>ShadowDOM,https://bit.ly/blink-perf-benchmarks,all
 blink_perf.svg,"fs@opera.com, pdr@chromium.org",Blink>SVG,https://bit.ly/blink-perf-benchmarks,all
-blink_perf.webaudio,"hongchan@chromium.org, rtoy@chromium.org",Blink>WebAudio,https://bit.ly/blink-perf-benchmarks,all
+blink_perf.webaudio,hongchan@chromium.org,Blink>WebAudio,https://bit.ly/blink-perf-benchmarks,all
 blink_perf.webgl,"kbr@chromium.org, enga@chromium.org, webgl-team@google.com",Blink>WebGL,https://bit.ly/blink-perf-benchmarks,
 blink_perf.webgl_fast_call,"kbr@chromium.org, enga@chromium.org, mslekova@chromium.org, junov@chromium.org, webgl-team@google.com",Blink>WebGL,https://bit.ly/blink-perf-benchmarks,
 blink_perf.webgpu,"enga@chromium.org, cwallez@chromium.org, webgpu-developers@google.com",Blink>WebGPU,https://bit.ly/blink-perf-benchmarks,
diff --git a/tools/perf/benchmarks/blink_perf.py b/tools/perf/benchmarks/blink_perf.py
index 466ef6f..d50c14b 100644
--- a/tools/perf/benchmarks/blink_perf.py
+++ b/tools/perf/benchmarks/blink_perf.py
@@ -701,7 +701,8 @@
     options.AppendExtraBrowserArgs(
       ['--enable-blink-features=DisplayLocking,CSSContentSize'])
 
-@benchmark.Info(emails=['hongchan@chromium.org', 'rtoy@chromium.org'],
+
+@benchmark.Info(emails=['hongchan@chromium.org'],
                 component='Blink>WebAudio',
                 documentation_url='https://bit.ly/blink-perf-benchmarks')
 class BlinkPerfWebAudio(_BlinkPerfBenchmark):
diff --git a/ui/accessibility/accessibility_features.cc b/ui/accessibility/accessibility_features.cc
index b9049968..574f23f9c 100644
--- a/ui/accessibility/accessibility_features.cc
+++ b/ui/accessibility/accessibility_features.cc
@@ -91,6 +91,16 @@
 bool IsIChromeAccessibleEnabled() {
   return base::FeatureList::IsEnabled(::features::kIChromeAccessible);
 }
+
+const base::Feature kSelectiveUIAEnablement{"SelectiveUIAEnablement",
+                                            base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Returns true if accessibility will be selectively enabled depending on the
+// UIA APIs that are called, allowing non-screenreader usage to enable less of
+// the accessibility system.
+bool IsSelectiveUIAEnablementEnabled() {
+  return base::FeatureList::IsEnabled(::features::kSelectiveUIAEnablement);
+}
 #endif  // defined(OS_WIN)
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/ui/accessibility/accessibility_features.h b/ui/accessibility/accessibility_features.h
index e2e6f697..28174e76 100644
--- a/ui/accessibility/accessibility_features.h
+++ b/ui/accessibility/accessibility_features.h
@@ -75,6 +75,13 @@
 // Returns true if the IChromeAccessible COM API is enabled.
 AX_BASE_EXPORT bool IsIChromeAccessibleEnabled();
 
+AX_BASE_EXPORT extern const base::Feature kSelectiveUIAEnablement;
+
+// Returns true if accessibility will be selectively enabled depending on the
+// UIA APIs that are called, allowing non-screenreader usage to enable less of
+// the accessibility system.
+AX_BASE_EXPORT bool IsSelectiveUIAEnablementEnabled();
+
 #endif  // defined(OS_WIN)
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/ui/accessibility/ax_mode.h b/ui/accessibility/ax_mode.h
index 6bac8eb8..0bb0d50 100644
--- a/ui/accessibility/ax_mode.h
+++ b/ui/accessibility/ax_mode.h
@@ -121,6 +121,13 @@
                                         AXMode::kInlineTextBoxes |
                                         AXMode::kScreenReader | AXMode::kHTML);
 
+// Similar to kAXModeComplete, used when an AT that requires full accessibility
+// access, but does not need all HTML properties or attributes.
+static constexpr AXMode kAXModeCompleteNoHTML(AXMode::kNativeAPIs |
+                                              AXMode::kWebContents |
+                                              AXMode::kInlineTextBoxes |
+                                              AXMode::kScreenReader);
+
 // For debugging, test assertions, etc.
 AX_BASE_EXPORT std::ostream& operator<<(std::ostream& stream,
                                         const AXMode& mode);
diff --git a/ui/accessibility/platform/ax_fragment_root_win.cc b/ui/accessibility/platform/ax_fragment_root_win.cc
index 7a180e4..fa7624a 100644
--- a/ui/accessibility/platform/ax_fragment_root_win.cc
+++ b/ui/accessibility/platform/ax_fragment_root_win.cc
@@ -326,7 +326,7 @@
   // Automation. Signal observers when we're asked for a platform object on it.
   for (WinAccessibilityAPIUsageObserver& observer :
        GetWinAccessibilityAPIUsageObserverList()) {
-    observer.OnUIAutomationUsed();
+    observer.OnBasicUIAutomationUsed();
   }
   return platform_node_.Get();
 }
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index 6fb0a48..c727ff3 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -4185,6 +4185,7 @@
                                                      IUnknown** result) {
   WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_PATTERN_PROVIDER);
   WIN_ACCESSIBILITY_API_PERF_HISTOGRAM(UMA_API_GET_PATTERN_PROVIDER);
+  NotifyAPIObserverForPatternRequest(pattern_id);
   return GetPatternProviderImpl(pattern_id, result);
 }
 
@@ -4217,6 +4218,9 @@
     // Collapse all unknown property IDs into a single bucket.
     base::UmaHistogramSparse("Accessibility.WinAPIs.GetPropertyValue", 0);
   }
+
+  NotifyAPIObserverForPropertyRequest(property_id);
+
   return GetPropertyValueImpl(property_id, result);
 }
 
@@ -8230,6 +8234,92 @@
   SanitizeStringAttributeForIA2(input, output);
 }
 
+void AXPlatformNodeWin::NotifyAPIObserverForPatternRequest(
+    PATTERNID pattern_id) const {
+  bool probable_advanced_client_detected = false;
+  bool text_pattern_support_needed = false;
+  switch (pattern_id) {
+    case UIA_TextPatternId:
+    case UIA_TextChildPatternId:
+      // These properties require information gated behind the kInlineTextBoxes
+      // AXMode. See kInlineTextBoxes for details.
+      text_pattern_support_needed = true;
+      break;
+    // These properties require more advanced accessibility features to be
+    // enabled See kScreenReader for details.
+    case UIA_RangeValuePatternId:
+    case UIA_TableItemPatternId:
+      probable_advanced_client_detected = true;
+      break;
+  }
+
+  for (WinAccessibilityAPIUsageObserver& observer :
+       GetWinAccessibilityAPIUsageObserverList()) {
+    if (probable_advanced_client_detected)
+      observer.OnAdvancedUIAutomationUsed();
+    if (text_pattern_support_needed)
+      observer.OnTextPatternRequested();
+  }
+}
+void AXPlatformNodeWin::NotifyAPIObserverForPropertyRequest(
+    PROPERTYID property_id) const {
+  bool probable_advanced_client_detected = false;
+  bool probable_screen_reader_detected = false;
+  switch (property_id) {
+    // These properties are used by non-screenreader UIA clients. They should
+    // not cause additional enablement.
+    case UIA_ControlTypePropertyId:
+    case UIA_HasKeyboardFocusPropertyId:
+    case UIA_IsControlElementPropertyId:
+    case UIA_FrameworkIdPropertyId:
+    case UIA_IsEnabledPropertyId:
+      break;
+    //  These properties are not currently implemented and should not cause
+    //  enablement.
+    case UIA_AnnotationTypesPropertyId:
+    case UIA_CenterPointPropertyId:
+    case UIA_FillColorPropertyId:
+    case UIA_FillTypePropertyId:
+    case UIA_HeadingLevelPropertyId:
+    case UIA_ItemTypePropertyId:
+    case UIA_OutlineColorPropertyId:
+    case UIA_OutlineThicknessPropertyId:
+    case UIA_RotationPropertyId:
+    case UIA_SizePropertyId:
+    case UIA_VisualEffectsPropertyId:
+      break;
+    // These properties are provided by UIA Core; we should not implement, and
+    // they should not cause enablement.
+    case UIA_BoundingRectanglePropertyId:
+    case UIA_NativeWindowHandlePropertyId:
+    case UIA_ProcessIdPropertyId:
+    case UIA_ProviderDescriptionPropertyId:
+    case UIA_RuntimeIdPropertyId:
+      break;
+    // These properties are indicative of a screenreader, we should enable full
+    // accessibility support.
+    case UIA_AriaRolePropertyId:
+    case UIA_LabeledByPropertyId:
+    case UIA_LiveSettingPropertyId:
+    case UIA_LevelPropertyId:
+    case UIA_DescribedByPropertyId:
+      probable_screen_reader_detected = true;
+      probable_advanced_client_detected = true;
+      break;
+    default:
+      // All other properties should cause us to enable.
+      probable_advanced_client_detected = true;
+  }
+
+  for (WinAccessibilityAPIUsageObserver& observer :
+       GetWinAccessibilityAPIUsageObserverList()) {
+    if (probable_advanced_client_detected)
+      observer.OnAdvancedUIAutomationUsed();
+    if (probable_screen_reader_detected)
+      observer.OnProbableUIAutomationScreenReaderDetected();
+  }
+}
+
 // static
 void AXPlatformNodeWin::SanitizeStringAttributeForIA2(const std::string& input,
                                                       std::string* output) {
diff --git a/ui/accessibility/platform/ax_platform_node_win.h b/ui/accessibility/platform/ax_platform_node_win.h
index 84a21ed..91f114d 100644
--- a/ui/accessibility/platform/ax_platform_node_win.h
+++ b/ui/accessibility/platform/ax_platform_node_win.h
@@ -341,7 +341,10 @@
   virtual void OnIAccessible2Used() = 0;
   virtual void OnScreenReaderHoneyPotQueried() = 0;
   virtual void OnAccNameCalled() = 0;
-  virtual void OnUIAutomationUsed() = 0;
+  virtual void OnBasicUIAutomationUsed() = 0;
+  virtual void OnAdvancedUIAutomationUsed() = 0;
+  virtual void OnProbableUIAutomationScreenReaderDetected() = 0;
+  virtual void OnTextPatternRequested() = 0;
   virtual void StartFiringUIAEvents() = 0;
   virtual void EndFiringUIAEvents() = 0;
 };
@@ -1470,6 +1473,9 @@
       const std::wstring& active_composition_text,
       bool is_composition_committed);
 
+  void NotifyAPIObserverForPatternRequest(PATTERNID pattern_id) const;
+  void NotifyAPIObserverForPropertyRequest(PROPERTYID property_id) const;
+
   // Return true if the given element is valid enough to be returned as a value
   // for a UIA relation property (e.g. ControllerFor).
   static bool IsValidUiaRelationTarget(AXPlatformNode* ax_platform_node);
diff --git a/ui/accessibility/platform/inspect/ax_tree_formatter_base.cc b/ui/accessibility/platform/inspect/ax_tree_formatter_base.cc
index 33fb9f61..5209fcfd 100644
--- a/ui/accessibility/platform/inspect/ax_tree_formatter_base.cc
+++ b/ui/accessibility/platform/inspect/ax_tree_formatter_base.cc
@@ -76,8 +76,9 @@
     return contents;
 
   for (const base::Value& script : scripts->GetList()) {
-    WriteAttribute(true, script.GetString(), &contents);
-    contents += "\n";
+    std::string line;
+    WriteAttribute(true, script.GetString(), &line);
+    contents += line + "\n";
   }
 
   return contents;
diff --git a/ui/android/java/res/values/color_palette.xml b/ui/android/java/res/values/color_palette.xml
index 54a25a3..801e5e3 100644
--- a/ui/android/java/res/values/color_palette.xml
+++ b/ui/android/java/res/values/color_palette.xml
@@ -6,19 +6,30 @@
 -->
 <resources xmlns:tools="http://schemas.android.com/tools">
     <!-- 2021 color palette -->
+    <color name="baseline_error_200">#F2B8B5</color>
+    <color name="baseline_error_600">#B3261E</color>
+    <color name="baseline_primary_0">@android:color/white</color>
     <color name="baseline_primary_100">#D3E3FD</color>
     <color name="baseline_primary_200">#A8C7FA</color>
     <color name="baseline_primary_600">#0B57D0</color>
     <color name="baseline_primary_800">#062E6F</color>
     <color name="baseline_primary_900">#041E49</color>
+    <color name="baseline_neutral_0">@android:color/white</color>
+    <color name="baseline_neutral_50">#F2F2F2</color>
     <color name="baseline_neutral_100">#E3E3E3</color>
     <color name="baseline_neutral_100_alpha_12">#1EE3E3E3</color>
+    <color name="baseline_neutral_200">#C7C7C7</color>
+    <color name="baseline_neutral_600">#5E5E5E</color>
+    <color name="baseline_neutral_800">#303030</color>
+    <color name="baseline_neutral_900">#1F1F1F</color>
     <color name="baseline_neutral_900_alpha_12">#1E1F1F1F</color>
     <color name="baseline_neutral_900_with_neutral_100_alpha_38">#696969</color>
     <color name="baseline_neutral_variant_100">#E1E3E1</color>
     <color name="baseline_neutral_variant_200">#C4C7C5</color>
     <color name="baseline_neutral_variant_200_alpha_15">#26C4C7C5</color>
     <color name="baseline_neutral_variant_400">#8E918F</color>
+    <color name="baseline_neutral_variant_500">#747775</color>
+    <color name="baseline_neutral_variant_700">#444746</color>
 
     <color name="baseline_neutral_900_with_neutral_200_alpha_12_with_primary_200_alpha_2">#353637</color>
 
diff --git a/ui/base/x/x11_gl_egl_utility.cc b/ui/base/x/x11_gl_egl_utility.cc
index 8464e44..624c6f9 100644
--- a/ui/base/x/x11_gl_egl_utility.cc
+++ b/ui/base/x/x11_gl_egl_utility.cc
@@ -39,20 +39,8 @@
 
 void GetPlatformExtraDisplayAttribs(EGLenum platform_type,
                                     std::vector<EGLAttrib>* attributes) {
-  // ANGLE_NULL and SwiftShader backends don't use the visual,
-  // and may run without X11 where we can't get it anyway.
-  if ((platform_type != EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE) &&
-      (std::find(attributes->begin(), attributes->end(),
-                 EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE) ==
-       attributes->end())) {
-    x11::VisualId visual_id;
-    XVisualManager::GetInstance()->ChooseVisualForWindow(
-        true, &visual_id, nullptr, nullptr, nullptr);
-    attributes->push_back(EGL_X11_VISUAL_ID_ANGLE);
-    attributes->push_back(static_cast<EGLAttrib>(visual_id));
-    attributes->push_back(EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE);
-    attributes->push_back(EGL_PLATFORM_X11_EXT);
-  }
+  attributes->push_back(EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE);
+  attributes->push_back(EGL_PLATFORM_X11_EXT);
 }
 
 void ChoosePlatformCustomAlphaAndBufferSize(EGLint* alpha_size,
diff --git a/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc b/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc
index 541702c..eaed1f56 100644
--- a/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc
@@ -811,12 +811,12 @@
 
   // Override test server's data device drag delegate such that
   // wl_data_device.start_drag no-ops.
-  struct NoopDragDeviceDelegate : public wl::TestDataDevice::Delegate {
+  struct NoopDragDeviceDelegate : public wl::TestDataDevice::DragDelegate {
     void StartDrag(wl::TestDataSource* source,
                    wl::MockSurface* origin,
                    uint32_t serial) override {}
   } noop_drag_delegate;
-  data_device_manager_->data_device()->set_delegate(&noop_drag_delegate);
+  data_device_manager_->data_device()->set_drag_delegate(&noop_drag_delegate);
 
   FocusAndPressLeftPointerButton(window_.get(), &delegate_);
 
diff --git a/ui/ozone/platform/wayland/test/test_data_device.cc b/ui/ozone/platform/wayland/test/test_data_device.cc
index 6fc8a3e..dface6c7 100644
--- a/ui/ozone/platform/wayland/test/test_data_device.cc
+++ b/ui/ozone/platform/wayland/test/test_data_device.cc
@@ -64,8 +64,8 @@
                                uint32_t serial) {
   DCHECK(source);
   DCHECK(origin);
-  if (delegate_)
-    delegate_->StartDrag(source, origin, serial);
+  if (drag_delegate_)
+    drag_delegate_->StartDrag(source, origin, serial);
   wl_client_flush(client_);
 }
 
diff --git a/ui/ozone/platform/wayland/test/test_data_device.h b/ui/ozone/platform/wayland/test/test_data_device.h
index 85ad4af..1b8805c 100644
--- a/ui/ozone/platform/wayland/test/test_data_device.h
+++ b/ui/ozone/platform/wayland/test/test_data_device.h
@@ -25,7 +25,7 @@
 
 class TestDataDevice : public ServerObject {
  public:
-  struct Delegate {
+  struct DragDelegate {
     virtual void StartDrag(TestDataSource* source,
                            MockSurface* origin,
                            uint32_t serial) = 0;
@@ -34,7 +34,7 @@
   TestDataDevice(wl_resource* resource, wl_client* client);
   ~TestDataDevice() override;
 
-  void set_delegate(Delegate* delegate) { delegate_ = delegate; }
+  void set_drag_delegate(DragDelegate* delegate) { drag_delegate_ = delegate; }
 
   void SetSelection(TestDataSource* data_source, uint32_t serial);
   void StartDrag(TestDataSource* data_source,
@@ -55,7 +55,7 @@
  private:
   TestDataOffer* data_offer_;
   wl_client* client_ = nullptr;
-  Delegate* delegate_ = nullptr;
+  DragDelegate* drag_delegate_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(TestDataDevice);
 };
diff --git a/ui/ozone/platform/wayland/test/wayland_drag_drop_test.cc b/ui/ozone/platform/wayland/test/wayland_drag_drop_test.cc
index cf0b379f..739e424 100644
--- a/ui/ozone/platform/wayland/test/wayland_drag_drop_test.cc
+++ b/ui/ozone/platform/wayland/test/wayland_drag_drop_test.cc
@@ -98,15 +98,15 @@
   ASSERT_TRUE(data_device_manager_);
 
   data_source_ = nullptr;
-  data_device_manager_->data_device()->set_delegate(this);
+  data_device_manager_->data_device()->set_drag_delegate(this);
 }
 
 void WaylandDragDropTest::TearDown() {
-  data_device_manager_->data_device()->set_delegate(nullptr);
+  data_device_manager_->data_device()->set_drag_delegate(nullptr);
   data_device_manager_ = nullptr;
 }
 
-// wl::TestDataDevice::Delegate:
+// wl::TestDataDevice::DragDelegate:
 void WaylandDragDropTest::StartDrag(wl::TestDataSource* source,
                                     wl::MockSurface* origin,
                                     uint32_t serial) {
diff --git a/ui/ozone/platform/wayland/test/wayland_drag_drop_test.h b/ui/ozone/platform/wayland/test/wayland_drag_drop_test.h
index 0bf5e67..cd7a238 100644
--- a/ui/ozone/platform/wayland/test/wayland_drag_drop_test.h
+++ b/ui/ozone/platform/wayland/test/wayland_drag_drop_test.h
@@ -27,7 +27,7 @@
 // emulate dnd-related events from the test compositor and can be used in both
 // data and window dragging test cases.
 class WaylandDragDropTest : public WaylandTest,
-                            public wl::TestDataDevice::Delegate {
+                            public wl::TestDataDevice::DragDelegate {
  public:
   WaylandDragDropTest();
   WaylandDragDropTest(const WaylandDragDropTest&) = delete;
@@ -56,7 +56,7 @@
   void SetUp() override;
   void TearDown() override;
 
-  // wl::TestDataDevice::Delegate:
+  // wl::TestDataDevice::DragDelegate:
   void StartDrag(wl::TestDataSource* source,
                  wl::MockSurface* origin,
                  uint32_t serial) override;
diff --git a/ui/views/controls/webview/web_dialog_view.cc b/ui/views/controls/webview/web_dialog_view.cc
index 606f82c..aba1ecf 100644
--- a/ui/views/controls/webview/web_dialog_view.cc
+++ b/ui/views/controls/webview/web_dialog_view.cc
@@ -54,18 +54,6 @@
     delegate_->OnWebContentsFinishedLoad();
 }
 
-void ObservableWebView::ResourceLoadComplete(
-    content::RenderFrameHost* render_frame_host,
-    const content::GlobalRequestID& request_id,
-    const blink::mojom::ResourceLoadInfo& resource_load_info) {
-  // Only listen to the main frame.
-  if (render_frame_host->GetParent())
-    return;
-
-  if (delegate_)
-    delegate_->OnMainFrameResourceLoadComplete(resource_load_info);
-}
-
 void ObservableWebView::ResetDelegate() {
   delegate_ = nullptr;
 }
diff --git a/ui/views/controls/webview/web_dialog_view.h b/ui/views/controls/webview/web_dialog_view.h
index 978155ad..d4d63380 100644
--- a/ui/views/controls/webview/web_dialog_view.h
+++ b/ui/views/controls/webview/web_dialog_view.h
@@ -26,7 +26,6 @@
 namespace content {
 class BrowserContext;
 class RenderFrameHost;
-struct GlobalRequestID;
 }  // namespace content
 
 namespace views {
@@ -45,10 +44,6 @@
   // content::WebContentsObserver
   void DidFinishLoad(content::RenderFrameHost* render_frame_host,
                      const GURL& validated_url) override;
-  void ResourceLoadComplete(
-      content::RenderFrameHost* render_frame_host,
-      const content::GlobalRequestID& request_id,
-      const blink::mojom::ResourceLoadInfo& resource_load_info) override;
 
   // Resets the delegate. The delegate will no longer receive calls after this
   // point.
diff --git a/ui/views/controls/webview/web_dialog_view_unittest.cc b/ui/views/controls/webview/web_dialog_view_unittest.cc
index 352ffe7..18a6a3d 100644
--- a/ui/views/controls/webview/web_dialog_view_unittest.cc
+++ b/ui/views/controls/webview/web_dialog_view_unittest.cc
@@ -177,12 +177,6 @@
   EXPECT_FALSE(web_view_delegate());
 
   ResetWebDialogDelegate();
-  // Calling back to web view's ResourceLoadComplete() should not cause crash.
-  content::RenderFrameHost* rfh = web_view()->web_contents()->GetMainFrame();
-  ASSERT_TRUE(rfh);
-  content::GlobalRequestID request_id;
-  blink::mojom::ResourceLoadInfo resource_load_info;
-  web_view()->ResourceLoadComplete(rfh, request_id, resource_load_info);
 }
 
 TEST_F(WebDialogViewUnitTest, MetadataTest) {
diff --git a/ui/web_dialogs/web_dialog_delegate.h b/ui/web_dialogs/web_dialog_delegate.h
index dc7fe5f..417db49 100644
--- a/ui/web_dialogs/web_dialog_delegate.h
+++ b/ui/web_dialogs/web_dialog_delegate.h
@@ -9,7 +9,6 @@
 #include <vector>
 
 #include "content/public/browser/web_contents_delegate.h"
-#include "third_party/blink/public/mojom/loader/resource_load_info.mojom.h"
 #include "ui/base/ui_base_types.h"
 #include "ui/base/window_open_disposition.h"
 #include "ui/web_dialogs/web_dialogs_export.h"
@@ -176,8 +175,6 @@
   virtual bool AcceleratorPressed(const Accelerator& accelerator);
 
   virtual void OnWebContentsFinishedLoad() {}
-  virtual void OnMainFrameResourceLoadComplete(
-      const blink::mojom::ResourceLoadInfo& resource_load_info) {}
 
   virtual void RequestMediaAccessPermission(
       content::WebContents* web_contents,
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/BrowserViewController.java b/weblayer/browser/java/org/chromium/weblayer_private/BrowserViewController.java
index ba98983..d0e86a3 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/BrowserViewController.java
+++ b/weblayer/browser/java/org/chromium/weblayer_private/BrowserViewController.java
@@ -210,6 +210,8 @@
                     mModalDialogManager.resumeType(
                             ModalDialogManager.ModalDialogType.TAB, mTabModalToken);
                 }
+                mAppModalToken = TokenHolder.INVALID_TOKEN;
+                mTabModalToken = TokenHolder.INVALID_TOKEN;
             }
         };
         mBottomSheetController.addObserver(mBottomSheetObserver);